<span style="white-space:pre"> </span><!-- 定义新的拦截器栈, 配置 prepare 拦截器栈的 alwaysInvokePrepare 参数值为 false -->
<interceptors>
<interceptor-stack name="sshStack">
<interceptor-ref name="paramsPrepareParamsStack">
<param name="prepare.alwaysInvokePrepare">false</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 使用新的拦截器栈 -->
<default-interceptor-ref name="sshStack"></default-interceptor-ref>
常常我们在Struts2中,都需要配置一个这个东西,是什么东西呢?
先说下正常业务中的情况:
Action接受用户提交的表单数据,并封装到bean里面,例如action中有个user对象,如果想要用params拦截器将数据
直接封装到user对象中,那么就要在jsp中这么写 <input type="text" name="user.name" />
而如果我们想在jsp页面直接写<input type="text" name="name" />并将这个name封装到user对象的name属性上,
就需要依赖我们 的ModelDriven<T>拦截器i:实际上他就是把我们的model对象压到栈顶,这样使用OGNL时就先从栈顶找name一样的set方法。
ModelDrivenInterceptor.java:
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action instanceof ModelDriven) {
ModelDriven modelDriven = (ModelDriven) action;
ValueStack stack = invocation.getStack();
Object model = modelDriven.getModel();
if (model != null) {
stack.push(model);
}
if (refreshModelBeforeResult) {
invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
}
那么Preparable接口又是干什么的,我们知道form提交的action会请求到一个java类的方法上,有时候我们需要在方法调用前准备点什么,
那么实现Preparable接口就可以了,因为PrepareInterceptor为我们代理了一下action的调用:
PrepareInterceptor.java
@Override
public String doIntercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action instanceof Preparable) {
try {
String[] prefixes;
if (firstCallPrepareDo) {
prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
} else {
prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
}
PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
}
catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof Exception) {
throw (Exception) cause;
} else if(cause instanceof Error) {
throw (Error) cause;
} else {
throw e;
}
}
if (alwaysInvokePrepare) {
((Preparable) action).prepare();
}
}
return invocation.invoke();
}
}
我们看到:默认是在action方法调用前执行prepare方法,但是,实际中我们的一个action可能要处理增删改查等多个逻辑。
如果我们都放到一个prepare方法中,会显得混乱,并且方法的复用性也很低。
那我们就可以看到一个alwaysInvokePrepare参数可以控制不使用prepare方法了,而是
PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes),就是比如我的action方法是input(),那么它会自动找inputprepare()方法
如果找到,就会在input()之前执行,是不是很方便呢!
另外:在prepare方法中,我们有时候需要一些表单传递过来的参数,例如id等,而我们知道params拦截器是处理请求参数,默认的DefalultInterceptorStack里面
虽然也有prepare拦截器,但是prepare却无法接收到用户请求的数据,因为只有params拦截器才能传递,这就要
paramsPrepareParamsStack:
<span style="white-space:pre"> </span><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>
而defaultStack:
<span style="white-space:pre"> </span><interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<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-ref name="debugging"/>
<interceptor-ref name="deprecation"/>
</interceptor-stack>
显然在prepare前面少了params拦截器。
下面给出action中使用这2个技术的demo:
Xxxaction.java
package ray.actions;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import ray.po.Employee;
import ray.services.DepartmentService;
import ray.services.EmployeeService;
public class EmployeeAction extends BaseAction<Employee> implements ModelDriven<Employee>, Preparable{
/**
*
*/
private static final long serialVersionUID = 1L;
private DepartmentService departmentService;
public void setDepartmentService(DepartmentService departmentService) {
this.departmentService = departmentService;
}
public String list() {
requestMap.put("employees", employeeService.getAll());
return "list";
}
private Integer id;
public void setId(Integer id) {
this.id = id;
}
private Employee model;
public String input(){
requestMap.put("departments", departmentService.getAll());
return INPUT;
}
public void prepareInput(){
if(id != null){
model = employeeService.get(id);
}
}
public String save(){
if(id == null){
(model).setCreateDate(new Date());
}
employeeService.saveOrUpdate(model);
return SUCCESS;
}
public void prepareSave(){
if(id == null){
model = new Employee();
}else{
model = employeeService.get(id);
}
}
@Override
public void prepare() throws Exception {
}
@Override
public Employee getModel() {
// TODO Auto-generated method stub
return model;
}
}