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

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

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

微博:伊直都在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 中

  

 <?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> <constant name="struts.action.extension" value="action,do,"></constant>
<package name="default" namespace="/" extends="struts-default"> <!-- 配置使用paramsPrepareParamsStack 作为默认的拦截器栈 -->
<default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>
<action name="emp-*" class="com.jason.strut2.curd.EmployeeAction" method="{1}">
<result name="{1}">/emp-{1}.jsp</result>
<result name="success" type="redirectAction">emp-list</result>
</action> </package>
</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 接口

  

 package com.jason.strut2.curd;

 import java.util.Map;

 import org.apache.struts2.interceptor.RequestAware;

 import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.util.ValueStack; public class EmployeeAction implements RequestAware ,ModelDriven<EmployeeBean>{ private Dao dao = new Dao();
private Map<String, Object> requestMap;
private EmployeeBean employeeBean; // 需要在当前的 EmployeeAction 中定义employeeId 属性,以接收页面请求参数:删除操作 public String list() { requestMap.put("emps", dao.getEmployees());
return "list";
} //删除
public String delete() { dao.delete(employeeId);
// 返回结果的类型应为 :redirectAction,也可以是chain:实际chain 是没有必要
// 还有,若使用chain 则到达目标页面后,地址栏显示的依然是 删除 的那个连接,刷新时 会有重复提交
return "success";
} public String save(){ //1.获取请求参数:通过定义属性的方式
//2.调用DAO的 svae 方法 dao.save(employeeBean);
//3.通过redirectAction 的方式响应结果给 emp-list
return "success";
} public String update(){
dao.update(employeeBean);
return "success";
} public String edit(){ //1.获取传入的employeeId:employee.getEmployeeId()
//2.根据employeesId 获取employee对象
//EmployeeBean empl = dao.get(employeeBean.getEmployeeId()); //3.把栈顶的对象的属性装配好:此时的栈顶对象是employee
//目前的employee 对象只有 employeeId 属性,其他属性为 null /*
*Struts2表单回显:从值栈栈顶开始查找匹配的属性,若找到就添加到value 属性中。
*/
/*employeeBean.setEmail(empl.getEmail());
employeeBean.setFirstNmame(empl.getFirstName());
employeeBean.setLastName(empl.getLastName());*/ //不能进行表单的回显,因为经过重写赋值的employee 对象已经不再是栈顶对象
// employeeBean = dao.get(employeeBean.getEmployeeId()); //手动的把从该数据库中获取的Employee 对象放到值栈的栈顶
//但是此时值栈栈顶及第二个对象均为employee 对象
//ActionContext.getContext().getValueStack().push(dao.get(employeeBean.getEmployeeId())); return "edit";
} @Override
public void setRequest(Map<String, Object> requestMap) {
this.requestMap = requestMap;
} private Integer employeeId;
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
} @Override
public EmployeeBean getModel() {
//判断Create 还是 edit
//若为Create,则:employeeBean = new EmployeeBean();
//若为edit ,则从数据库中获取 employeeBean = dao.get(employeeBean.getEmployeeId());
//判断标准为:是否有employeeId。若有则视为 edit,若没有则视为 Create
//若通过employeeId 来判断,则需要在modelDriven 拦截器之前先执行一个params拦截器
//可以通过使用paramsPrepareParams 拦截器实现
//需要在 struts.xml 文件中配置 paramsPrepareParams 为默认的拦截器栈 if(employeeId == null){
employeeBean = new EmployeeBean();
} else {
employeeBean = dao.get(employeeId);
}
return employeeBean;
} }

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)源码分析

 @Override
public String doIntercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction(); if (action instanceof Preparable) {
try {
String[] prefixes;
//根据当前拦截器的 firstCallPrepareDo 确定 前缀数组;firstCallPrepareDo 默认为false
if (firstCallPrepareDo) {
prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
} else {
prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
}
//若为false: 则prefixex 为 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 static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
//过去Action 实例
Object action = actionInvocation.getAction();
//获取要调用的Action 方法的名字(update)
String methodName = actionInvocation.getProxy().getMethod(); if (methodName == null) {
// if null returns (possible according to the docs), use the default execute
methodName = DEFAULT_INVOCATION_METHODNAME;
}
//获取前缀方法
Method method = getPrefixedMethod(prefixes, methodName, action);
if (method != null) {
//若方法不为 null,通过反射调用前缀方法
method.invoke(action, new Object[0]);
}
} public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {
assert(prefixes != null);
//把方法的名字变为大写
String capitalizedMethodName = capitalizeMethodName(methodName);
//遍历前缀数组
for (String prefixe : prefixes) {
//通过拼接的方式,得到前缀方法名:第一次 prepare + capitalizedMethodName ;第二次 prepareDo +c apitalizedMethodName
String prefixedMethodName = prefixe + capitalizedMethodName;
try {
//利用反射从aciton 中获取对应的方法,若有,直接返回并结束循环
return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY);
}
catch (NoSuchMethodException e) {
// hmm -- OK, try next prefix
if (LOG.isDebugEnabled()) {
LOG.debug("cannot find method [#0] in action [#1]", prefixedMethodName, action.toString());
}
}
}
return null;
}

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

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

 package com.jason.strut2.curd;

 import java.util.Map;

 import org.apache.struts2.interceptor.RequestAware;

 import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.util.ValueStack; public class EmployeeAction implements RequestAware, ModelDriven<EmployeeBean>,
Preparable { private Dao dao = new Dao();
private Map<String, Object> requestMap;
private EmployeeBean employeeBean; // 需要在当前的 EmployeeAction 中定义employeeId 属性,以接收页面请求参数:删除操作 public String list() { requestMap.put("emps", dao.getEmployees());
return "list";
} // 删除
public String delete() { dao.delete(employeeId);
// 返回结果的类型应为 :redirectAction,也可以是chain:实际chain 是没有必要
// 还有,若使用chain 则到达目标页面后,地址栏显示的依然是 删除 的那个连接,刷新时 会有重复提交
return "success";
} public String save() {
// 1.获取请求参数:通过定义属性的方式
// 2.调用DAO的 svae 方法 dao.save(employeeBean);
// 3.通过redirectAction 的方式响应结果给 emp-list
return "success";
} public void prepareSave() {
employeeBean = new EmployeeBean();
} public void prepareUpdate() {
employeeBean = new EmployeeBean();
} public String update() {
dao.update(employeeBean);
return "success";
} public void prepareEidt() {
employeeBean = dao.get(employeeId);
} public String edit() {
return "edit";
} @Override
public void setRequest(Map<String, Object> requestMap) {
this.requestMap = requestMap;
} private Integer employeeId; public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
} @Override
public EmployeeBean getModel() { return employeeBean;
} /*
* prepare 方法的主要作用:为getModel() 方法准备 model 的
*/
@Override
public void prepare() throws Exception {
System.out.println("prepare ... ");
} }

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

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

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

  2. MyBatis-Plus学习笔记(1):环境搭建以及基本的CRUD操作

    MyBatis-Plus是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,使用MyBatis-Plus时,不会影响原来Mybatis方式的使用. SpringBoot+M ...

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

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

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

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

  5. Java后台处理框架之struts2学习总结

    Java后台处理框架之struts2学习总结 最近我在网上了解到,在实际的开发项目中struts2的使用率在不断降低,取而代之的是springMVC.可能有很多的朋友看到这里就会说,那还不如不学str ...

  6. 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用

    目录 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用 24.1 expect实现无交互登录 24.1.1 安装和使用expect 24.2 正则表达式的使用 24 ...

  7. 学习笔记:CentOS7学习之二十:shell脚本的基础

    目录 学习笔记:CentOS7学习之二十:shell脚本的基础 20.1 shell 基本语法 20.1.1 什么是shell? 20.1.2 编程语言分类 20.1.3 什么是shell脚本 20. ...

  8. 学习笔记:CentOS7学习之十七: Linux计划任务与日志的管理

    目录 学习笔记:CentOS7学习之十七: Linux计划任务与日志的管理 17.1 计划任务-at-cron-计划任务使用方法 17.1.1 at计划任务的使用 17.1.2 查看和删除at将要执行 ...

  9. 学习笔记:CentOS7学习之十九:Linux网络管理技术

    目录 学习笔记:CentOS7学习之十九:Linux网络管理技术 本文用于记录学习体会.心得,兼做笔记使用,方便以后复习总结.内容基本完全参考学神教育教材,图片大多取材自学神教育资料,在此非常感谢MK ...

随机推荐

  1. 关于Java的File.separator

    在Windows下的路径分隔符和Linux下的路径分隔符是不一样的,当直接使用绝对路径时,跨平台会暴出“No such file or diretory”的异常. 比如说要在temp目录下建立一个te ...

  2. (转)android 在电脑上显示真机屏幕

    http://my.oschina.net/u/202293/blog/199954 方法一: 可以用360手机助手等实现. 方法二: 想把手机屏幕显示在电脑屏幕上时就需要使用Android Scre ...

  3. 500Internal Server Error

    在今晚测试wamp的项目时,当我导入一个项目到www目录下时出现如下错误:Internal Server ErrorThe server encountered an internal error o ...

  4. 关于YARN的HA

    一:准备 1.规划 namenode               namenode ZKFC ZKFC journalnode        journalnode               jou ...

  5. This system is not registered with RHN

    在红帽EL5上运行yum,提示“This system is not registered with RHN”,意思是没有在官网上注册,不能下载RH的软件包,替代方案是采用centos源. 1.卸载r ...

  6. 常用yum命令

    yum list 查询所有可用软件包 yum search 关键字 查询和关键字相关的包 yum -y install 包名 加上-y自动回答yes yum -y update 包名 升级  yum ...

  7. ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法

    原文:ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法 群里好几个朋友都提到过这样的问题,说他们在Silverlight中调用了WebServi ...

  8. Subway---poj2502(最短路)

    题目链接:http://poj.org/problem?id=2502 人走路的速度是10km/h,地铁的速度是40km/h题目给出一个起点,一个终点,以及几条地铁线路运行的站点.题目给的点的做坐标单 ...

  9. Android调用WCF

    http://www.cnblogs.com/davidgu/archive/2012/05/16/2504182.html

  10. OO之美4(好代码与坏代码)

    前言:写代码不仅仅要做到能与机器交流,更要做到能和人交流 编码规范:编码规范就是最佳实践,是前辈在编码这件事上的积累和总结,是智慧的延续和工业的实践,如下: ⑴命名规范 ⑵避免行数过多的方法 ⑶代码缩 ...