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

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

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

微博:伊直都在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. jquery autocomplete插件结合ajax使用

    <%@ page isELIgnored="false"%> <%@ page contentType="text/html; charset=UTF- ...

  2. .Net搭建的WebService测试页使用TextArea大文本框方便调试

    用.Net搭建的WebService,系统默认提供了测试页,供大家输入参数进行测试.但因为参数输入框使用的是单行input控件,导致无法输入换行文本,使得有些参数(如换行的xml)无法输入,及其不便. ...

  3. Java高级之虚拟机加载机制

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 1.0版本:2016-05-21 SubClass!! 执行结果说明一个问题:子类调用父类变量的时候 ...

  4. python 之 utf-8编码的秘密

    python3的默认编码方案是utf-8编码,看了些资料,来做总结. 要说utf-8,就要说说unicode,要说unicode,就要说ASCII,我们还是慢慢来. 1.ASCII ASCII编码最初 ...

  5. android常用命令

    首先配置好环境变量会比较方便... 大部分sdk提供的工具都在sdk\platform-tools和sdk\tools下,建议配置这两个路径到path 另外aapt工具在sdk\build-tools ...

  6. windows bat常用命令积累

    1.判断文件夹是否为空  dir/a/b "D:\test"|findstr . >nul&&(echo 有文件)||(echo 空)   2.多层文件夹遍历 ...

  7. 10 Ways to Inspire Your Team

    Inspire. Just the word itself causes us to pause and think. We may remember our own personal heroes ...

  8. JS-007-富文本域操作

    在日常 web 编写过程中,富文本域几乎成为了一个网站不可页面元素,同时,其也有着各种各样的实现方式,网络上也存在着各种各样的集成插件可供引用.此文以 js 获取.修改 163 邮箱写邮件时的邮件内容 ...

  9. ASP.NET中身份验证

    ASP.NET中身份验证有三种方式:Windows.Forms和Passport. 1.Windows验证,基于窗体验证,需要每个页面写上验证身份代码,相对灵活,但操作过于复杂: 2.Passport ...

  10. django 笔记

    最近开始接触django,一些基本的操作记录于此. 参考链接: http://www.ziqiangxuetang.com/django/django-tutorial.html django安装 s ...