我的struts2使用的是2.3.16.3版本的,web配置struts2的监听如下
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>config</param-name>
<param-value>struts-default.xml,struts-plugin.xml,config/struts-config/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>actionPackages</param-name>
<param-value>com.founder.rk</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
Struts2中package配置如下
<package name="global" extends="struts-default,json-default">
<interceptors>
<interceptor-stack name="SMInterceptorStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="SMInterceptorStack"></default-interceptor-ref>
<global-results>
<result name="login" type="redirect">/sm/frame/system/login/login.jsp</result>
<result name="error">/sm/frame/system/errorReport/error500.jsp</result>
<result name="error_nologin">/sm/frame/system/errorReport/errorNologin.jsp</result>
<result name="error_nopage">/sm/frame/system/errorReport/error404.jsp</result>
</global-results>
</package>
action类继承和实现了如下接口
public class SjbflAction extends ActionSupport implements Preparable,ModelDriven{
ModelDriven接口是使用模型封装请求参数,Preparable接口是为了在模型封装之前构造model对象,代码如下
@Override
public SjbflVO getModel() {
// TODO Auto-generated method stub
return sjbfl;
}
@Override
public void prepare() throws Exception {
// TODO Auto-generated method stub
System.out.println(request.getParameter("id"));
//判断是否传递参数id,如果有id,则根据id去数据库获取实例,没有则创建一个新的
if (isNullOrEmptyString(id)) {
sjbfl = new SjbflVO();
} else {
sjbfl = sjbflService.getById(id);
}
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
就这样,请求action的方法时我传递了id参数,但是发现action中prepare的方法中获取属性id为空,我断点调试了一下发现在执行action的prepare方法前没有调用setId方法,没有给id设置值,我检查了好多地方都没有发现问题所在,最后把实现Preparable接口给去掉后,set方法就自动调用了。
后来我又查了一下Struts2的拦截器相关资料,结果代码测试,发现其实是拦截器的问题,Struts2默认的拦截器栈
“defaultStack”如果action实现了preparable接口,action的执行顺序是先执行prepare方法,再执行set方法,所以再prepare方法中属性id是没有被赋值的为null,此时把默认的拦截器栈换成paramsPrepareParamsStack就解决了我遇到的上面的问题,代码如下
<package name="global" extends="struts-default,json-default">
<interceptors>
<interceptor-stack name="SMInterceptorStack">
<!-- 该拦截器栈,先调用action的set方法,再调用prepare方法,最后再调用一次set方法 -->
<interceptor-ref name="paramsPrepareParamsStack" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="SMInterceptorStack"></default-interceptor-ref>
<global-results>
<result name="login" type="redirect">/sm/frame/system/login/login.jsp</result>
<result name="error">/sm/frame/system/errorReport/error500.jsp</result>
<result name="error_nologin">/sm/frame/system/errorReport/errorNologin.jsp</result>
<result name="error_nopage">/sm/frame/system/errorReport/error404.jsp</result>
</global-results>
</package>
paramsPrepareParamsStack包含的拦截器如下:
<interceptor-stack name="paramsPrepareParamsStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="params"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
paramsPrepareParamsStack拦截器栈中的使用顺序:
params->prepare->model-driven->params
Struts2的设计上要求modelDriven在params之前调用,而业务中prepare要负责准备model,准备model又需要参数,这就需要在prepare之前调用params拦截器设置相关参数,这个也就是创建paramsPrepareParamsStack的原因。
流程:
1.params拦截器首先给action的相关参数赋值
2.prepare拦截器执行prepare方法,prepare方法会根据参数,如id,去调用业务逻辑,设置model对象
3.model-diven拦截器将model对象压入值栈,这里的model对象就是在prepare中创建
4.params拦截器将参数值赋给model对象
5.action的逻辑执行