关于PrepareInterceptor
对上面的程序中的
Method method = getPrefixedMethod(prefixes, methodName, action);方法进行分析:
对应的源码分析:com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor
<pre name="code" class="java">public String doIntercept(ActionInvocation invocation) throws Exception {
// 获取实例
Object action = invocation.getAction();
// 判断Action是否实现了Preparable接口
if (action instanceof Preparable) {
try {
String[] prefixes;
// 根据当前拦截器firstCallPrepareDo(默认为false)
// 属性确定prefixes
if (firstCallPrepareDo) {
prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
} else {
prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
}
// 若为false,则prefixes为:prepare、prepareDo
// 调用前缀方法
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;
}
}
// 根据当前拦截器的alwaysInvokePrepare(默认为true)决定是否调用Action的prepare方法
if (alwaysInvokePrepare) {
((Preparable) action).prepare();
}
}
return invocation.invoke();
}
}
对上面程序中的PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);进行分析:
<pre name="code" class="java">public String doIntercept(ActionInvocation invocation) throws Exception {
// 获取实例
Object action = invocation.getAction();
// 判断Action是否实现了Preparable接口
if (action instanceof Preparable) {
try {
String[] prefixes;
// 根据当前拦截器firstCallPrepareDo(默认为false)
// 属性确定prefixes
if (firstCallPrepareDo) {
prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
} else {
prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
}
// 若为false,则prefixes为:prepare、prepareDo
// 调用前缀方法
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;
}
}
// 根据当前拦截器的alwaysInvokePrepare(默认为true)决定是否调用Action的prepare方法
if (alwaysInvokePrepare) {
((Preparable) action).prepare();
}
}
return invocation.invoke();
}
}
public String doIntercept(ActionInvocation invocation) throws Exception {
// 获取实例
Object action = invocation.getAction();
// 判断Action是否实现了Preparable接口
if (action instanceof Preparable) {
try {
String[] prefixes;
// 根据当前拦截器firstCallPrepareDo(默认为false)
// 属性确定prefixes
if (firstCallPrepareDo) {
prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
} else {
prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
}
// 若为false,则prefixes为:prepare、prepareDo
// 调用前缀方法
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;
}
}
// 根据当前拦截器的alwaysInvokePrepare(默认为true)决定是否调用Action的prepare方法
if (alwaysInvokePrepare) {
((Preparable) action).prepare();
}
}
return invocation.invoke();
}
}
进行分析后得到的结论:
(1)
若Action实现了Prepare接口,则Struts将尝试执行prepare[ActionMethodName]方法,
若
prepare[ActionMethodName]不存在,则尝试执行prepareDo[ActionMethodName]方法,若都存在,就都不执行。
(2)若PrepareInterceptor的alwaysInvokePrepare属性为false,则Struts2将不会调用实现了Preparable的Action。
(3)解决前一篇文章的方案是:可以为每一个ActionMethod准备Prepare[ActionMethodName]方法,而抛弃原来的prepare方法;避免PrepareInterceptor的alwaysInvokePrepare属性为false,以避免Struts2框架在用prepare方法。
代码具体实现:
struts配置文件的配置:
</pre><pre name="code" class="html"><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- 配置struts可以受理的请求的扩展名 -->
<constant name="struts.action.extension" value="action,do,"></constant>
<package name="default" namespace="/" extends="struts-default">
<!-- 修改PrepareInterceptorParamsStack拦截器的 alwaysInvokePrepare属性值为false-->
<interceptors>
<interceptor-stack name="atguiguStak">
<interceptor-ref name="paramsPrepareParamsStack">
<param name="prepare.alwaysInvokePrepare">false</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 配置使用paramsPrepareParamsStack作为默认的拦截器栈 -->
<default-interceptor-ref name="atguiguStak"></default-interceptor-ref>
<action name="emp-*" class="com.yu.struts2.app.EmployeeAction" method="{1}">
<result name="{1}">/{1}.jsp</result>
<result name="success" type="redirectAction">emp-list</result>
</action>
</package>
</struts>
EmployeeAction类改写如下:
package com.yu.struts2.app;
import java.util.Map;
import org.apache.struts2.interceptor.RequestAware;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
public class EmployeeAction implements RequestAware ,ModelDriven<Employee>, Preparable{
private Dao dao = new Dao();
public String list(){
requestMap.put("emps", dao.getEmployees());
return "list";
}
public String delete(){
dao.delete(employeeId);
return "success";
}
private Employee employee;
public String save(){
// 1.获取请求参数:通过定义对应属性的方式
// 2.调用Dao的save方法
dao.save(employee);
return "success";
}
public void prepareSave(){
employee = new Employee();
}
public String edit(){
// 1.获取传入的employeeId:employee.getEmployeeId()
// 2.根据employeeId获取Employee对象
//Employee emp = dao.get(employee.getEmployeeId());
// 3.把栈顶对象的属性转配好,此时栈顶对象时employee
// 目前的employee对象只有employeeId属性,其他属性为null
/*
* Struts2表单回显时:从值栈栈顶开始查找匹配的属性,若找到就添加到value属性中
*/
// employee.setEmail(emp.getEmail());
// employee.setFirstName(emp.getFirstName());
// employee.setLastName(emp.getLastName());
// 不能够进行表单的回显,因为经过重写赋值的employee对象不再是栈顶对象
//employee = dao.get(employee.getEmployeeId());
// 手动的把从数据库中获取的Employee对象放到值栈的栈顶。
// 但此时值栈栈顶及第二个对象均为Employee对象,不够完美
//ActionContext.getContext().getValueStack().push(dao.get(employee.getEmployeeId()));
return "edit";
}
public void prepareEdit(){
employee = dao.get(employeeId);
}
public String update(){
dao.update(employee);
return "success";
}
public void prepareUpdate(){
employee = new Employee();
}
private Map<String, Object> requestMap;
@Override
public void setRequest(Map<String, Object> arg0) {
// TODO Auto-generated method stub
this.requestMap = arg0;
}
private Integer employeeId;
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
@Override
public Employee getModel() {
// 判断是Create还是Edit。
// 若为Create,则employee = new Employee();
// 若为Edit,则employee = dao.get(employeeId);
// 判定标准为是否有employeeId这个参数。若有该参数,则视为Edit;若没有该参数,则视为Create
// 若通过employeeId来判断,则需要在modelDriven拦截器之前执行一个params拦截器!
// 而这可以通过使用paramsPrepareParams拦截器栈实现
// 需要在struts.xml文件中配置使用paramsPrepareParams作为默认的拦截器栈
// if(employeeId == null){
// employee = new Employee();
// }
// else
// employee = dao.get(employeeId);
//
return employee;
}
/*
* prepare方法的主要作用:为getModel()方法准备model的
*/
@Override
public void prepare() throws Exception {
System.out.println("prepare...");
}
}