您的位置:首页 > 编程语言 > Java开发

24(续)Struts2_CRUD总结下(paramsPrepareParamsStack 拦截器)

2017-11-20 15:35 218 查看


paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack
拦截器栈

使用   paramsPrepareParamsStack 拦截器的运行流程

   1)paramsPrepareParamsStack  和 defaultSstack 一样都是拦截器栈,而struts-defalt包默认使用的是defaultStack

   2)可以通过在struts.xml 中配置默认的拦截器栈 

              <!--
配置使用paramsPrepareParamsStack 作为默认的拦截器栈 -->
<default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>


 

  3)paramsPrepareParamsStack   拦截器在的运行过程: params -> modelDriven -> params

    可以先把请求参数赋给 Action 对应的属性,再根据赋给Action 的属性值 决定压入值栈栈顶的对象,最后再为栈顶对象的属性赋值

  


  4)使用 paramsPrepareParamsStack 拦截器栈:

    Struts 2.0的设计上要求 modelDriven 在 params 之前调用,而业务中prepare要负责准备model,准备model又需要参数,

    这就需要在 prepare之前运行params拦截器设置相关参数,这个也就是创建paramsPrepareParamsStack的原因。

  


  

 

 

1.修改默认的拦截器在struts.xml 中

  

 1 <?xml version="1.0" encoding="UTF-8" ?>
2 <!DOCTYPE struts PUBLIC
3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
4 "http://struts.apache.org/dtds/struts-2.3.dtd">
5
6 <struts>
7
8 <constant name="struts.action.extension" value="action,do,"></constant>
9 <package name="default" namespace="/" extends="struts-default">
10
11 <!-- 配置使用paramsPrepareParamsStack 作为默认的拦截器栈 -->
12 <default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>
13 <action name="emp-*" class="com.jason.strut2.curd.EmployeeAction" method="{1}">
14 <result name="{1}">/emp-{1}.jsp</result>
15 <result name="success" type="redirectAction">emp-list</result>
16 </action>
17
18
19 </package>
20 </struts>


 

 

2.重构 acntion代码

 

  对于edit 操作而言

    1)先为 EmployeeAction 的 employeeId 赋值

    2)再根据employeeId 从数据库中加载对应的对象,并且压入到值栈的栈顶

    3)再为栈顶对象的employeeId 赋值

    4)把栈顶对象的属性回显在表单中

 

  关于回显:

    struts2 表单标签会从值栈中获取对应的属性值进行回显

 

3.存在问题:

      

      public EmployeeBean getModel() {
          if(employeeId == null){
             employeeBean = new EmployeeBean();
          } else { 
             employeeBean = dao.get(employeeId);
          }
          return employeeBean;
      }

 

    1)在执行删除的时候,employeeId 不为null,但getModel 方法却从数据库中加载了一个对象,多余

    2)在查询全部的时候,new Empployee() 对象,多余

4.解决问题方案:

    使用 PrepareIntercepter 和 Preparable 接口

  

1 package com.jason.strut2.curd;
2
3 import java.util.Map;
4
5 import org.apache.struts2.interceptor.RequestAware;
6
7 import com.opensymphony.xwork2.ActionContext;
8 import com.opensymphony.xwork2.ActionInvocation;
9 import com.opensymphony.xwork2.ModelDriven;
10 import com.opensymphony.xwork2.util.ValueStack;
11
12 public class EmployeeAction implements RequestAware ,ModelDriven<EmployeeBean>{
13
14     private Dao dao = new Dao();
15     private Map<String, Object> requestMap;
16     private EmployeeBean employeeBean;
17
18     // 需要在当前的 EmployeeAction 中定义employeeId 属性,以接收页面请求参数:删除操作
19
20
21     public String list() {
22
23         requestMap.put("emps", dao.getEmployees());
24         return "list";
25     }
26
27     //删除
28     public String delete() {
29
30         dao.delete(employeeId);
31         // 返回结果的类型应为 :redirectAction,也可以是chain:实际chain 是没有必要
32         // 还有,若使用chain 则到达目标页面后,地址栏显示的依然是 删除 的那个连接,刷新时 会有重复提交
33         return "success";
34     }
35
36
37     public String save(){
38
39
40
41             //1.获取请求参数:通过定义属性的方式
42             //2.调用DAO的 svae 方法
43
44             dao.save(employeeBean);
45             //3.通过redirectAction 的方式响应结果给 emp-list
46             return "success";
47     }
48
49
50     public String update(){
51         dao.update(employeeBean);
52         return "success";
53     }
54
55     public String edit(){
56
57          //1.获取传入的employeeId:employee.getEmployeeId()
58          //2.根据employeesId  获取employee对象
59          //EmployeeBean empl = dao.get(employeeBean.getEmployeeId());
60
61          //3.把栈顶的对象的属性装配好:此时的栈顶对象是employee
62          //目前的employee 对象只有 employeeId 属性,其他属性为 null
63
64          /*
65           *Struts2表单回显:从值栈栈顶开始查找匹配的属性,若找到就添加到value 属性中。
66           */
67         /*employeeBean.setEmail(empl.getEmail());
68         employeeBean.setFirstNmame(empl.getFirstName());
69         employeeBean.setLastName(empl.getLastName());*/
70
71         //不能进行表单的回显,因为经过重写赋值的employee 对象已经不再是栈顶对象
72         // employeeBean  = dao.get(employeeBean.getEmployeeId());
73
74         //手动的把从该数据库中获取的Employee 对象放到值栈的栈顶
75         //但是此时值栈栈顶及第二个对象均为employee 对象
76         //ActionContext.getContext().getValueStack().push(dao.get(employeeBean.getEmployeeId()));
77
78
79         return "edit";
80     }
81
82     @Override
83     public void setRequest(Map<String, Object> requestMap) {
84         this.requestMap = requestMap;
85     }
86
87     private Integer employeeId;
88     public void setEmployeeId(Integer employeeId) {
89         this.employeeId = employeeId;
90     }
91
92     @Override
93     public EmployeeBean getModel() {
94         //判断Create  还是 edit
95         //若为Create,则:employeeBean  = new EmployeeBean();
96         //若为edit ,则从数据库中获取 employeeBean  = dao.get(employeeBean.getEmployeeId());
97         //判断标准为:是否有employeeId。若有则视为 edit,若没有则视为 Create
98         //若通过employeeId 来判断,则需要在modelDriven 拦截器之前先执行一个params拦截器
99         //可以通过使用paramsPrepareParams 拦截器实现
100         //需要在 struts.xml 文件中配置 paramsPrepareParams 为默认的拦截器栈
101
102         if(employeeId == null){
103             employeeBean  = new EmployeeBean();
104         } else {
105             employeeBean = dao.get(employeeId);
106         }
107         return employeeBean;
108     }
109
110 }


5.其他 代码 

EmployeeBean  Employee Dao struts.xml  web.xml  emp-list.jsp  emp-edit.jsp inde.jsp 参考

代码参考22.Struts2_CRUD操作(2)添加和修改

 

6. Preparable 拦截器

  1)Struts 2.0 中的 modelDriven 拦截器负责把 Action 类以外的一个对象压入到值栈栈顶

  2)而 prepare 拦截器负责准备为 getModel() 方法准备 model

7.关于PrepareIntercepter 源码结论
      ① 若Action 实现了Preparable 接口,则 Struts 将尝试执行prepare[ActionMethodName]方法;
        若prepare[ActionMethodName] 不存在,则将尝试执行prepareDo[ActionMethodName] 方法;
             若都不存在,就都不执行; 
    ② 若PrepareIntercepter  的  alwaysInvokePrepare
属性为false,则struts2 将不会调用实现了Preparable 接口的 Action 的prepare 方法

8.PrepareInterceptor拦截器使用方法
    ①若 Action
实现 Preparable 接口,则 Action 方法需实现 prepare() 方法
               ② PrepareInterceptor 拦截器将调用 prepare() 方法  prepareActionMethodName()方法 或 prepareDoActionMethodName ()方法   
               ③PrepareInterceptor 拦截器根据 firstCallPrepareDo 属性决定获取 prepareActionMethodName 、prepareDoActionMethodName的顺序。默认情况下先获取
prepareActionMethodName (), 如果没有该方法,就寻找prepareDoActionMethodName()。如果找到对应的方法就调用该方法
               ④PrepareInterceptor 拦截器会根据 alwaysInvokePrepare 属性决定是否执行prepare()方法

 

   源代码解析

1 @Override
2     public String doIntercept(ActionInvocation invocation) throws Exception {
3         Object action = invocation.getAction();
4
5         if (action instanceof Preparable) {
6             try {
7                 String[] prefixes

8                 //根据当前拦截器的 firstCallPrepareDo 确定 前缀数组;firstCallPrepareDo 默认为false
9                 if (firstCallPrepareDo) {
10                     prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
11                 } else {
12                     prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
13                 }
14                 //若为false: 则prefixex 为 prepare ,prepareDo
15                 //调用前缀方法
16                 PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
17             }
18             catch (InvocationTargetException e) {
19
20                 Throwable cause = e.getCause();
21                 if (cause instanceof Exception) {
22                     throw (Exception) cause;
23                 } else if(cause instanceof Error) {
24                     throw (Error) cause;
25                 } else {
26
27                     throw e;
28                 }
29             }
30
31             //根据当前拦截器的 alwaysInvokePrepare(默认是true) 决定是否调用 Action 的 prepare 方法
32             if (alwaysInvokePrepare) {
33                 ((Preparable) action).prepare();
34             }
35         }
36
37         return invocation.invoke();
38     }
39
40
41
42     public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
43         //获取Action 实例
44         Object action = actionInvocation.getAction();
45         //获取要调用的Action 方法的名字(update)
46         String methodName = actionInvocation.getProxy().getMethod();
47
48         if (methodName == null) {
49             // if null returns (possible according to the docs), use the default execute
50             methodName = DEFAULT_INVOCATION_METHODNAME;
51         }
52         //获取前缀方法
53         Method method = getPrefixedMethod(prefixes, methodName, action);
54         if (method != null) {
55             //若方法不为 null,通过反射调用前缀方法
56             method.invoke(action, new Object[0]);
57         }
58     }
59
60     public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {
61         assert(prefixes != null);
62         //把方法的名字变为大写
63         String capitalizedMethodName = capitalizeMethodName(methodName);
64         //遍历前缀数组
65         for (String prefixe : prefixes) {
66             //通过拼接的方式,得到前缀方法名:第一次 prepare + capitalizedMethodName ;第二次 prepareDo +c apitalizedMethodName
67             String prefixedMethodName = prefixe + capitalizedMethodName;
68             try {
69                 //利用反射从aciton 中获取对应的方法,若有,直接返回并结束循环
70                 return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY);
71             }
72             catch (NoSuchMethodException e) {
73                 // hmm -- OK, try next prefix
74                 if (LOG.isDebugEnabled()) {
75                     LOG.debug("cannot find method [#0] in action [#1]", prefixedMethodName, action.toString());
76                 }
77             }
78         }
79         return null;
80     }


 

 

9.解决(3所存在的问题)的方法:

    方案:为每一个ActionMethod 准备一个prepare[ActionMethodName] 方法,而抛弃原来的prepare()方法;将PrepareIntercepter  的  alwaysInvokePrepare 属性设为false,避免Struts2 框架在嗲用prepare()方法

 

1 package com.jason.strut2.curd;
2
3 import java.util.Map;
4
5 import org.apache.struts2.interceptor.RequestAware;
6
7 import com.opensymphony.xwork2.ActionContext;
8 import com.opensymphony.xwork2.ActionInvocation;
9 import com.opensymphony.xwork2.ModelDriven;
10 import com.opensymphony.xwork2.Preparable;
11 import com.opensymphony.xwork2.util.ValueStack;
12
13 public class EmployeeAction implements RequestAware, ModelDriven<EmployeeBean>,
14         Preparable {
15
16     private Dao dao = new Dao();
17     private Map<String, Object> requestMap;
18     private EmployeeBean employeeBean;
19
20     // 需要在当前的 EmployeeAction 中定义employeeId 属性,以接收页面请求参数:删除操作
21
22     public String list() {
23
24         requestMap.put("emps", dao.getEmployees());
25         return "list";
26     }
27
28     // 删除
29     public String delete() {
30
31         dao.delete(employeeId);
32         // 返回结果的类型应为 :redirectAction,也可以是chain:实际chain 是没有必要
33         // 还有,若使用chain 则到达目标页面后,地址栏显示的依然是 删除 的那个连接,刷新时 会有重复提交
34         return "success";
35     }
36
37     public String save() {
38         // 1.获取请求参数:通过定义属性的方式
39         // 2.调用DAO的 svae 方法
40
41         dao.save(employeeBean);
42         // 3.通过redirectAction 的方式响应结果给 emp-list
43         return "success";
44     }
45
46     public void prepareSave() {
47         employeeBean = new EmployeeBean();
48     }
49
50     public void prepareUpdate() {
51         employeeBean = new EmployeeBean();
52     }
53
54     public String update() {
55         dao.update(employeeBean);
56         return "success";
57     }
58
59     public void prepareEidt() {
60         employeeBean = dao.get(employeeId);
61     }
62
63     public String edit() {
64         return "edit";
65     }
66
67     @Override
68     public void setRequest(Map<String, Object> requestMap) {
69         this.requestMap = requestMap;
70     }
71
72     private Integer employeeId;
73
74     public void setEmployeeId(Integer employeeId) {
75         this.employeeId = employeeId;
76     }
77
78     @Override
79     public EmployeeBean getModel() {
80
81         return employeeBean;
82     }
83
84     /*
85      * prepare 方法的主要作用:为getModel() 方法准备 model 的
86      */
87     @Override
88     public void prepare() throws Exception {
89         System.out.println("prepare ... ");
90     }
91
92 }


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: