[原创]java WEB学习笔记6:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) 使用 paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack 拦截器栈

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用

内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系。

本人互联网技术爱好者,互联网技术发烧友

微博:伊直都在0221

QQ:951226918

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

使用   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 表单标签会从值栈中获取对应的属性值进行回显

  存在问题:

      

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

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

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

 解决问题方案:

    使用 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 }

3.其他 代码 
EmployeeBean Dao

 web.xml  emp-list.jsp  emp-edit.jsp inde.jsp 参考

[原创]java WEB学习笔记65:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) ModelDriven拦截器 paramter 拦截器

4. Preparable 拦截器

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

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

    3)关于PrepareIntercepter 源码结论

    ① 若Action 实现了Preparable 接口,则 Struts 将尝试执行prepare[ActionMethodName]方法;

        若prepare[ActionMethodName] 不存在,则将尝试执行prepareDo[ActionMethodName] 方法;

            若都不存在,就都不执行; 

    ② 若PrepareIntercepter  的  alwaysInvokePrepare 属性为false,则struts2 将不会调用实现了Preparable 接口的 Action 的prepare 方法

    4)PrepareInterceptor 拦截器用方法

    ①若 Action 实现 Preparable 接口,则 Action 方法需实现 prepare() 方法

② PrepareInterceptor 拦截器将调用 prepare() 方法  prepareActionMethodName()方法 或 prepareDoActionMethodName ()方法   

③PrepareInterceptor 拦截器根据 firstCallPrepareDo 属性决定获取 prepareActionMethodName 、prepareDoActionMethodName的顺序。默认情况下先获取 prepareActionMethodName (), 如果没有该方法,就寻找prepareDoActionMethodName()。如果找到对应的方法就调用          该方法

④PrepareInterceptor 拦截器会根据 alwaysInvokePrepare 属性决定是否执行prepare()方法

   5)源码分析

 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     }

   6)解决上述上述问题的方法:

    方案:为每一个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 }
时间: 2024-12-05 08:52:15

[原创]java WEB学习笔记6:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) 使用 paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack 拦截器栈的相关文章

[原创]java WEB学习笔记64:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) ModelDriven拦截器 paramter 拦截器

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

[原创]java WEB学习笔记75:Struts2 学习之路-- 总结 和 目录

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

[原创]java WEB学习笔记95:Hibernate 目录

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

【web开发学习笔记】Struts-Tags学习笔记1 - 通用标签和控制标签

通用标签和控制标签 第一部分:代码 //前端 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030" /> <title>Insert title here</title> </head> <body> 访问属性 <a href="<%=contextP

【web开发学习笔记】ibatis学习总结

ibatis学习总结 ibatis数据库配置文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <

【web开发学习笔记】Hibernate学习总结

hibernate学习笔记 学习笔记部分: 本部分的学习比较容易,代码比较全,也容易理解,可以说是一些记忆性质的东西. 本人在学习过程中没有自己在做笔记,只是参考了网上找的学习笔记,按照那个笔记学习和复习挺快的. 源码中有一些jar包缺失,我在自学的时候也整理了相关的jar包和软件,已经上传,祝大家学习快乐. 相关资源链接: 相关的数据库连接的资源: http://download.csdn.net/detail/licong_carp/7656601 相关的jar包文件: http://dow

[学习笔记] Sencha Cmd 学习笔记 Sencha Cmd是什么

本文地址: http://blog.csdn.net/sushengmiyan/article/details/38295575 本文作者:sushengmiyan -------------------------------------------------------------资源链接----------------------------------------------------------------------- 翻译来源  Sencha Cmd官方网站: http://w

Accelerated C++学习笔记1—&lt;开始学习C++&gt;

第0章 开始学习C++ 1.每次学习一个新的语言,大家都是从Hello, world!开始 // lesson0_1.cpp : 定义控制台应用程序的入口点. //功能:编译并运行Hello,world //时间:2014.5.7 #include "stdafx.h" #include "iostream" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { std::cout<< &

easyui学习笔记2—在行内进行表格的增删改操作【转载】

第一篇笔记中记录了如何实现表格的增删改,那个是点击之后跳出来一个对话框然后进行的,这里是在表格本身上进行的操作,也很简单,但是这里发现一个版本问题,也可以说是兼容性问题. 1.首先我们看引用的js和css代码 <link rel="stylesheet" href="jquery-easyui-1.3.5/themes/default/easyui.css" /> <link rel="stylesheet" href=&quo