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

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

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

微博:伊直都在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. StringBuffer与StringBuilder的简单理解

    联系:两者都适用于字符串的操作,都可以随便对字符串的内容进行变更操作,都继承至AbstractStringBuilder. 区别:StringBuffer是线程安全的,方法都加了synchronize ...

  2. Python + PIL 处理支付宝AR红包

    思路比较简单:1.对图片进行锐化处理:2.设(r_h, g_h, b_h)为支付宝遮罩黑条的RGB值,以此为中心,查找半径为Diff_radius的范围内所有的色值: 3.对每一行符合步骤2的像素点个 ...

  3. 解决Firefox浏览器每次打开都弹出导入向导的问题

    每次打开Firefox浏览器都会弹出导入向导这个页面,只有这个页面关闭后,Firefox界面才会打开. 解决办法: C:\Users\{用户名}\AppData\Roaming\Mozilla\Fir ...

  4. 2326: [HNOI2011]数学作业 - BZOJ

    首先是DP,分段DP(按位数讨论) 然后每一段构造出它对应的矩阵,用矩阵快速幂加速 type matrix=..,..]of int64; var n,m:int64; a,b,c,d:matrix; ...

  5. Buffer Cache(缓冲区缓存)篇:缓存区块大小

    缓冲区缓存(Buffer Cache) Buffer Cache是SGA的一部分,保存最近从磁盘读取的或修改的(dml修改或添加)数据块.Buffer Cache的目的就是减少磁盘I/O,提高速度. ...

  6. mysql数据库连接池使用(二)实现自己的数据库连接池

    上一个章节,我们讲了xml文件的解析框架XMLConfiguration的使用,不懂的可以参考 Apache Commons Configuration读取xml配置具体使用. 这个章节主要实现自己的 ...

  7. hadoop小知识札记

    hadoop实现全局变量: 只读的可以,可修改的不行,只读的可以通过configuration 或者分布式缓存实现.   hadoop做图像处理时,每个map读入一个图片,每个map读入一张图片,然后 ...

  8. 编译phoneix源码,整合Hbase

    Hbase版本:1.2.0-cdh5.14.0 1):下载phoneix源码 链接:https://pan.baidu.com/s/1uryK_jLEekdXV04DRc3axg 密码:bkqg 2) ...

  9. Linux内核如何装载和启动一个可执行程序(转)

    原文:http://www.cnblogs.com/petede/p/5351696.html 实验七:Linux内核如何装载和启动一个可执行程序 姓名:李冬辉 学号:20133201 注: 原创作品 ...

  10. SOAP和WebService的那些事

    当初对这段历史有过一点研究,不过当初写得关于这部分历史的论文不知道被我丢哪儿去了,下面我用通俗一点的语言来话说一下这段历史吧,因为当初详细到具体人物具体时间的已经记不清了,所以这里写得不够专业,大家就 ...