[原创]java WEB学习笔记66: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 中
- <?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 拦截器栈的更多相关文章
- [原创]java WEB学习笔记65:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) ModelDriven拦截器 paramter 拦截器
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- MyBatis-Plus学习笔记(1):环境搭建以及基本的CRUD操作
MyBatis-Plus是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,使用MyBatis-Plus时,不会影响原来Mybatis方式的使用. SpringBoot+M ...
- [原创]java WEB学习笔记75:Struts2 学习之路-- 总结 和 目录
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- [原创]java WEB学习笔记95:Hibernate 目录
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Java后台处理框架之struts2学习总结
Java后台处理框架之struts2学习总结 最近我在网上了解到,在实际的开发项目中struts2的使用率在不断降低,取而代之的是springMVC.可能有很多的朋友看到这里就会说,那还不如不学str ...
- 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用
目录 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用 24.1 expect实现无交互登录 24.1.1 安装和使用expect 24.2 正则表达式的使用 24 ...
- 学习笔记:CentOS7学习之二十:shell脚本的基础
目录 学习笔记:CentOS7学习之二十:shell脚本的基础 20.1 shell 基本语法 20.1.1 什么是shell? 20.1.2 编程语言分类 20.1.3 什么是shell脚本 20. ...
- 学习笔记:CentOS7学习之十七: Linux计划任务与日志的管理
目录 学习笔记:CentOS7学习之十七: Linux计划任务与日志的管理 17.1 计划任务-at-cron-计划任务使用方法 17.1.1 at计划任务的使用 17.1.2 查看和删除at将要执行 ...
- 学习笔记:CentOS7学习之十九:Linux网络管理技术
目录 学习笔记:CentOS7学习之十九:Linux网络管理技术 本文用于记录学习体会.心得,兼做笔记使用,方便以后复习总结.内容基本完全参考学神教育教材,图片大多取材自学神教育资料,在此非常感谢MK ...
随机推荐
- 浮动以后父DIV包不住子DIV解决方案
转载自http://blog.sina.com.cn/s/blog_6c363acf0100v4cz.html 当DIV1里面嵌套有一个DIV2,当DIV2设置了浮动,那么DIV1是无法被撑开的,也就 ...
- memache session
Memcache和PHP memcach扩展安装请见http://koda.iteye.com/blog/665761 设置session用memcache来存储 方法I: 在 php.ini 中全局 ...
- git-svn
sudo apt-get install git-svn svn作为一个优秀源码版本的管理工具,可以适合绝大多数项目.但是因为它的采用中心化管理,不可避免的存在本地代码的备份和版本管理问题.也就是说对 ...
- jquery mobile 方法收集.
1.在列表项和按钮上禁用文本截断 如果你的列表项或者按钮上是一个很长的文本,它将会被jQuery Mobile自动截断,要禁用这个截断设置,需要在CSS选择器上添加属性"white- ...
- zepto源码--fragment--学习笔记
文档片段fragment函数默认传递三个参数: html文档片段字符串 name标签 properties额外添加的属性 函数内部实现过程: var dom, nodes, container; 中间 ...
- php--tp3.2引入sphinx搜索
1.首先我们把coreseek下载好,命名为coreseek,我们找到coreseek/etc中的csft_mysql.conf修改这个配置文件 #源定义 source lemai { type ...
- Photoshop:通过图片理解通道原理
电脑上的图像通过色光三原色RGB表现,不同颜色存储在不同的通道,所以RGB模式下有3条通道,CMYK模式有4条通道等等 打开一张照片,查看通道 可以看出,显示越白的地方,对应的原色越深. 默认phot ...
- Spring整合CXF之发布WebService服务
今天我们来讲下如何用Spring来整合CXF,来发布WebService服务: 给下官方文档地址:http://cxf.apache.org/docs/writing-a-service-with-s ...
- Android笔记:Socket通讯常见问题
经验证的socket通讯问题 1.如果是模拟器和本机PC直接通讯,需要使用本机IP地址 而不是 10.0.2.2 如本机的静态地址为192.168.1.2 则直接使用该地址 2.接收和连接代码不能在 ...
- 生成uid的算法
private function _getUid() { //2013-01-01 00:00:00 (timestamp-microtime) $startTime= 1356969600000; ...