Struts2学习(五)【访问servletAPI方式】

来源:互联网 发布:rxjs 多个网络请求 编辑:程序博客网 时间:2024/06/04 17:49

一、原理

这里写图片描述

每次请求时,都会创建一个与请求对应的 ActionContext对象。请求完成会销毁ActionContext.

ActionContext创建好以后,与当前线程绑定,我们需要的时候从 ThreadLocal中去就行了。

ActionContext中存储着多个域的对象,已经请求和响应的对象。

public class ActionContext implements Serializable {    static ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();    .........    private Map<String, Object> context;    ....    public ActionContext(Map<String, Object> context) {        this.context = context;    }    public void setActionInvocation(ActionInvocation actionInvocation) {        put(ACTION_INVOCATION, actionInvocation);    }    public ActionInvocation getActionInvocation() {        return (ActionInvocation) get(ACTION_INVOCATION);    }    public void setApplication(Map<String, Object> application) {        put(APPLICATION, application);    }    public Map<String, Object> getApplication() {        return (Map<String, Object>) get(APPLICATION);    }    public static void setContext(ActionContext context) {        actionContext.set(context);    }    public static ActionContext getContext() {        return actionContext.get();    }    public void setContextMap(Map<String, Object> contextMap) {        getContext().context = contextMap;    }    public Map<String, Object> getContextMap() {        return context;    }    public void setConversionErrors(Map<String, Object> conversionErrors) {        put(CONVERSION_ERRORS, conversionErrors);    }    public Map<String, Object> getConversionErrors() {        Map<String, Object> errors = (Map) get(CONVERSION_ERRORS);        if (errors == null) {            errors = new HashMap<>();            setConversionErrors(errors);        }        return errors;    }    .............    public void setParameters(HttpParameters parameters) {        put(PARAMETERS, parameters);    }    public HttpParameters getParameters() {        return (HttpParameters) get(PARAMETERS);    }    public void setSession(Map<String, Object> session) {        put(SESSION, session);    }    public Map<String, Object> getSession() {        return (Map<String, Object>) get(SESSION);    }    public void setValueStack(ValueStack stack) {        put(VALUE_STACK, stack);    }    public ValueStack getValueStack() {        return (ValueStack) get(VALUE_STACK);    }    public void setContainer(Container cont) {        put(CONTAINER, cont);    }    .......    public Object get(String key) {        return context.get(key);    }    public void put(String key, Object value) {        context.put(key, value);    }}

二、通过ActionContext访问

2.1 分析

由上面的分析我们可以知道,我们可以通过当前线程的 ActionContext获取到我们域对象。

例如我们获取 Session域,我们可以通过

Map<String, Object> sessionScope = ActionContext.getContext().getSession();

其他方式的域获取也是一样的。

我们也可以看看主要的的方法

public class ActionContext implements Serializable {    static ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();    .........    private Map<String, Object> context;    ....    public Map<String, Object> getApplication() {        return (Map<String, Object>) get(APPLICATION);    }    public static ActionContext getContext() {        return actionContext.get();    }    public Map<String, Object> getContextMap() {        return context;    }    public Map<String, Object> getSession() {        return (Map<String, Object>) get(SESSION);    }    public Object get(String key) {        return context.get(key);    }}

这里面我们获取 session域和application域客户通过上面的方法。但是我们的 request 域就有点特殊了。

根据上面的方法中,我们看不到直接获取 request域的的方法呀?怎么来实现呢,我们知道上面这里个域的获取其实都是通过 键来获取的,那么我们的思路也就来了,我们可以通过 request域的键来获取request域。如下

//request域=> map (struts2并不推荐使用原生request域)Map<String,Object> requestScope = (Map<String,Object>)ActionContext.getContext().get("request");

但是Struts2并不推荐这么做,我们的ActionContext对象和request的生命周期是一样的,实际上我们的值可以存在 ActionContext 对象中。这一点我们可以去到我们和核心过滤器中证明。查找到我们的核心过滤器 StrutsPrepareAndExecuteFilter,查找到我们的 doFilter方法

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {    HttpServletRequest request = (HttpServletRequest) req;    HttpServletResponse response = (HttpServletResponse) res;    ............    //对request见此进行了包装,修改了取值方式    //先从原生request中查找,然后还会从ActionContext中查找    request = prepare.wrapRequest(request);    ......     }

2.2 获取域对象

根据上面的分析,我们知道了如果我们我们想要获取 session域和application域可以通过ActionContext,如果我们想要获取request域的话,那么我们可以把ActionContext当做request域来使用。
例如

//session域  mapMap<String, Object> sessionScope = ActionContext.getContext().getSession();// application域  mapMap<String, Object> applicationScope = ActionContext.getContext().getApplication();//request域存值ActionContext.getContext().put("name","request_wiming");

2.3 DemoApi1Action

package com.qwm.struts2_2.b_api;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;import java.util.Map;/** * @author: wiming * @date: 2017-09-18 16:50:34  星期一 * @decription: * 第一种方式获取 */public class DemoApi1Action extends ActionSupport{    @Override    public String execute() throws Exception {        /*          static ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();          (Map<String, Object>) get(SESSION);         */        //session域  map        Map<String, Object> sessionScope = ActionContext.getContext().getSession();        // application域  map        Map<String, Object> applicationScope = ActionContext.getContext().getApplication();        //request域=> map (struts2并不推荐使用原生request域)        //Map<String,Object> requestScope = (Map<String,Object>)ActionContext.getContext().get("request");        //推荐        // ActionContext和 request域的生命周期是一样的        // 全局过滤器包装了原生的request,主要就是改变了取值的时候,先从原生request中查找,然后还会从ActionContext中查找        ActionContext.getContext().put("name","request_wiming_test1");        sessionScope.put("name","session_wiming_test1");        applicationScope.put("name","application_wiming_test1");        return SUCCESS;    }}

2.4 api.jsp

<%--  Created by IntelliJ IDEA.  User: qiwenming  Date: 2017/9/18  Time: 17:11  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>原生ServletApi取值</title></head><body>    request: ${requestScope.name}<br><br>    session: ${sessionScope.name}<br><br>    application: ${applicationScope.name}<br></body></html>

2.5 配置文件

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"        "http://struts.apache.org/dtds/struts-2.5.dtd"><struts>    <package name="apidemo" namespace="/apidemo" extends="struts-default">        <action name="Api1Action" class="com.qwm.struts2_2.b_api.DemoApi1Action" method="execute">            <result name="success">/api.jsp</result>        </action>    </package></struts>

2.6 图示

gif)


三、通过ServletActionContext访问

3.1 分析与访问对象

通过ServletActionContext访问,我们直接调用它提供的方法就可以访问到里面的我们需要的域对象了。

如下

//原生requestHttpServletRequest request = ServletActionContext.getRequest();//原生responseHttpServletResponse response = ServletActionContext.getResponse();//原生sessionHttpSession session = ServletActionContext.getRequest().getSession();//原生servlerContextServletContext servletContext = ServletActionContext.getServletContext();

具体我们可以看看,他里面的方法是怎么时候实现的。

ServletActionContext

public class ServletActionContext extends ActionContext implements StrutsStatics {    ..............    public static PageContext getPageContext() {        return (PageContext) ActionContext.getContext().get(PAGE_CONTEXT);    }    public static HttpServletRequest getRequest() {        return (HttpServletRequest) ActionContext.getContext().get(HTTP_REQUEST);    }    public static HttpServletResponse getResponse() {        return (HttpServletResponse) ActionContext.getContext().get(HTTP_RESPONSE);    }    public static ServletContext getServletContext() {        return (ServletContext) ActionContext.getContext().get(SERVLET_CONTEXT);    }   ..............}

我们发现其实它里面是去调用 我们的 ActionContext的get方法,最终的实现和我们的前面一种方式是一样的

3.2 demo

package com.qwm.struts2_2.b_api;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;import org.apache.struts2.ServletActionContext;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.util.Map;/** * @author: wiming * @date: 2017-09-18 16:50:34  星期一 * @decription: * 第二种方式获取 不推荐 */public class DemoApi2Action extends ActionSupport{    @Override    public String execute() throws Exception {        //原生request//        内部调用   ActionContext.getContext().get(HTTP_REQUEST)        HttpServletRequest request = ServletActionContext.getRequest();        //原生response        HttpServletResponse response = ServletActionContext.getResponse();        //原生session        HttpSession session = ServletActionContext.getRequest().getSession();        //原生servlerContext        ServletContext servletContext = ServletActionContext.getServletContext();        request.setAttribute("name","request_wiming_test2");        session.setAttribute("name","session_wiming_test2");        servletContext.setAttribute("name","application_wiming_test2");        return SUCCESS;    }}

3.4 配置文件

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"        "http://struts.apache.org/dtds/struts-2.5.dtd"><struts>    <package name="apidemo" namespace="/apidemo" extends="struts-default">        <action name="Api2Action" class="com.qwm.struts2_2.b_api.DemoApi2Action" method="execute">            <result name="success">/api.jsp</result>        </action>    </package></struts>

3.4 图示

这里写图片描述


四、通过实现接口方式访问

4.1 分析

通过接口的方式访问,主要是通过实现 Aware结尾的接口来实现的。 实现我们setXXX方法,保存我们我们需要的对象,然后就可以访问了。

例如

public class DemoApi3Action extends ActionSupport implements ServletRequestAware{    private HttpServletRequest request;    public String execute() throws Exception{        //这里就可以使用那我们的request了        //原生session        HttpSession session = request.getSession();        return SUCCESS;    }    @Override    public void setServletRequest(HttpServletRequest request) {        this.request = request;    }}

那么这个功能是怎么完成的呢?这其实是拦截器做的。打开默认配置文件 struts2-core-2.5.13.jar!\struts-default.xml

struts-default.xml

.....<struts>    .....    <package name="struts-default" abstract="true" strict-method-invocation="true">        .....        <interceptors>            ........            <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>            <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>            <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>            ....            <interceptor-stack name="defaultStack">                <interceptor-ref name="exception"/>                <interceptor-ref name="alias"/>                <interceptor-ref name="servletConfig"/>                <interceptor-ref name="i18n"/>                ............            </interceptor-stack>            .........       </interceptors>        <default-interceptor-ref name="defaultStack"/>        <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />        <global-allowed-methods>execute,input,back,cancel,browse,save,delete,list,index</global-allowed-methods>    </package></struts>

产生这个作用的拦截器的是在配置中的 servletConfig,它对应的类是

org.apache.struts2.interceptor.ServletConfigInterceptor

我们来看看它的 intercept方法

public class ServletConfigInterceptor extends AbstractInterceptor implements StrutsStatics {    ....    public String intercept(ActionInvocation invocation) throws Exception {        final Object action = invocation.getAction();        final ActionContext context = invocation.getInvocationContext();        if (action instanceof ServletRequestAware) {            HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);            ((ServletRequestAware) action).setServletRequest(request);        }        ....省略的部分根据实现不同的接口来给不同的参数赋值...        return invocation.invoke();    }}

通过
((ServletRequestAware)action).setServletRequest(request);
就把request对象传递到了我们的 DemoApi3Action中了,然后我们就可以尽情的玩耍了。

4.2 DemoApi3Action

package com.qwm.struts2_2.b_api;import com.opensymphony.xwork2.ActionSupport;import org.apache.struts2.interceptor.ServletRequestAware;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;/** * @author: wiming * @date: 2017-09-18 17:37:20  星期一 * @decription: * 第三种方式获取 * 想要获取多个,就是实现多个域 */public class DemoApi3Action extends ActionSupport implements ServletRequestAware{    private HttpServletRequest request;    public String execute() throws Exception{        //原生session        HttpSession session = request.getSession();        //原生servlerContext        ServletContext servletContext = request.getServletContext();        request.setAttribute("name","request_wiming_test3");        session.setAttribute("name","session_wiming_test3");        servletContext.setAttribute("name","application_wiming_test3");        return SUCCESS;    }    @Override    public void setServletRequest(HttpServletRequest request) {        this.request = request;    }}

4.3 配置文件

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"        "http://struts.apache.org/dtds/struts-2.5.dtd"><struts>    <package name="apidemo" namespace="/apidemo" extends="struts-default">        <action name="Api3Action" class="com.qwm.struts2_2.b_api.DemoApi3Action" method="execute">            <result name="success">/api.jsp</result>        </action>    </package></struts>

4.4 图示

这里写图片描述