- 浏览: 143668 次
文章分类
最新评论
-
whwh13764799336:
[color=red][/color]
出现Connection reset by peer: socket write error问题的原因 -
aihua_girl:
good
第三章 PL/SQL数据类型 -
haitunwan:
<result name="success ...
出现Connection reset by peer: socket write error问题的原因 -
ynial:
对接口使用注释 好吗?
spring 中的事务小结 -
poshboytl:
问题应该出在session中
由于迭代前session中存放的 ...
在学习<应用Rails进行敏捷Web开发>遇到问题
转载自:http://www.iteye.com/topic/93984
目前流行的新型的MVC框架 几乎都在"增强单元测试能力"上做了很多文章.
目的就是让 Controller 可以脱离web容器单独进行单元测试.
大多数采用的方法都是使 Controller 中的方法的参数 和 返回值 与 j2ee特有的类(如HttpXXXX)无关.
例如 传入的 是若干个 HashMap ,返回的是纯的字符串.
这样在单元测试的时候,只要new一个Controller,准备一些装有测试数据的Map,
然后执行相关的Controller方法,再然后看看返回值,就可以了.
显然,流行的Struts 1.X (>=1.2) 是不具备这样的特性的.
如果您现在有一个遗留的使用Struts 1.X(>=1.2) 的系统,或者因为人力资源的原因,不能立即引入ww或Struts2.x,
那么如何让您的Action类似的可测性了呢(其实除了可测试性,这样的改进往往也会大大的减少代码的开发量).
下面我就把我的一些心得写出来,和大家一起分享,欢迎大家拍砖.
注意:以下讨论均以改造 DispatchAction 为例(不使用DispatchAction的情况应该比较少吧 呵呵).
先说明一下改造的目的:
简化开发,减少代码量
增强单元测试能力
全面兼容现有DispatchAction(这点很重要)
一个传统的 DispatchAction 代码结构
- public class MyClassicAction extends DispatchAction {
- // 一个添加user的操作
- public ActionForward addUser(ActionMapping mapping, ActionForm form,
- HttpServletRequest request, HttpServletResponse response)
- throws Exception {
- // 1 取得参数 ...
- // 2 执行相关的BO DAO方法
- // 3 取得执行后的返回值
- if (添加成功) {
- return mapping.findForward("Succee");
- }
- return mapping.findForward("Fail");
- // 还有一种情况是 返回 new ActionForward(....).
- }
- }
对于上面的代码大家再熟悉不过了,我们现在要做的事情就是通过改造,让上面的action方法变成下面的样子.
- // 一个添加user的操作
- public String addUser( 传入与web容器无关的参数 )
- throws Exception {
- // 1 取得参数 ...
- // 2 执行相关的BO DAO方法
- // 3 取得执行后的返回值
- if (添加成功) {
- return "Succee";
- }
- return "Fail";
- // 对于action中返回 new ActionForward(....).的情况,我们可以设定另外一种特殊的前缀.
- // 例如 return "NEW:/addUserFail.jsp";
- }
上面的代码是一个最终的目标,我们先一步一步来.
首先这种改造我们一定要从 Struts 提供的 DispatchAction 做起.
总体思路很明显:
自己写个类 继承 DispatchAction ,并且添加或修改一些方法, 然后项目中的其他的DispatchAction都继承这个自己写的DispatchAction类.
简单说一下Struts 的 DispatchAction的工作流程.
首先 它也是一个action,所以请求来了 他会自动去执行execute方法
execute方法内部做一些操作后,会调用 dispatchMethod 方法
dispatchMethod方法会,调用getMethod方法 来取得欲执行的方法,并且执行之
改造的核心就是围绕最关键的dispatchMethod方法.
而由于我们要"全面兼容现有DispatchAction",所以对于getMethod我们不做修改,而是选择增加一个类似的方法 getMethodTD
首先写一个新的 .DispatchAction基类,他继承org.apache.struts.actions.DispatchAction.
- public class TDDispatchAction extends DispatchAction {
- protected Class[] typesTD = {TDServletWrapper.class };
- protected final static String TD_METHODCACHE_PREFIX="TD_METHODCACHE_PREFIX";
- protected final static String TD_DEFAULT_METHOD="defaultMethod";
- protected final static String TD_NEW_FORWARD_PREFIX="NEW:";
- protected Method getMethodTD(String name)
- throws NoSuchMethodException {
- String cacheKey=TD_METHODCACHE_PREFIX+name;
- synchronized (methods) {
- Method method = (Method) methods.get(cacheKey);
- if (method == null) {
- method = clazz.getMethod(name, typesTD);
- methods.put(cacheKey, method);
- }
- return (method);
- }
- }
- // 对unspecified这个方法的扩展实际上与本次讨论无关,只是为我们框架加的一个小功能
- // 提供一个默认的方法.也就是说,如果您的action中,有名为 defaultMethod 的方法,那么无需在请求的参数中加入相关信息,就会自动执行.
- protected ActionForward unspecified(ActionMapping mapping, ActionForm form,
- HttpServletRequest request, HttpServletResponse response)
- throws Exception {
- return dispatchMethod(mapping, form, request, response, TD_DEFAULT_METHOD);
- }
- protected ActionForward dispatchMethod(ActionMapping mapping,
- ActionForm form, HttpServletRequest request,
- HttpServletResponse response, String name)
- throws Exception {
- // 后面再说
- }
- }
首先来看一下这个 getMethodTD 方法.
原getMethod(String name)方法的作用是:
取得一个名字为name,参数类型为 ActionMapping , ActionForm , HttpServletRequest ,HttpServletResponse 的一个方法.
而这个新写的 getMethodTD 方法的作用是:
取得一个名字为name,参数类型为 TDServletWrapper 的一个方法.
这个大家和 原getMethod一对比就能看出来作用和差异了,注意那个cacheKey=TD_METHODCACHE_PREFIX+name,这个是必须的,不能直接用name做key.
其中这个 TDServletWrapper 就是封装的一个"可以"与web容器脱离的对象,注意,这里用的是可以.而不是直接就脱离了.
对此后面再做解释.
要添加的 getMethodTD 方法添加完了.
下面来看一下重点 改造 dispatchMethod方法:
原dispatchMethod方法的流程其实很简单:
1 调用 getMethod(name)方法,取得真正要执行的方法 并执行(传入的参数类型为 ActionMapping , ActionForm , HttpServletRequest ,HttpServletResponse ).
2 返回 方法执行的 结果 (返回结果类型为 ActionForward ).
改造后的目的是:
1 调用 getMethodTD(name)方法,取得真正要执行的方法并执行(传入的参数类型为TDServletWrapper ).
2 取得 方法执行的 结果 (返回结果类型为 String ).
3 根据这个返回的String, 创建ActionForward对象,并返回
但是我们还有一个目的是"兼容",所以最后确定的流程是
1 调用 getMethod(name)方法,取得真正要执行的方法,如果取得,则按原方式继续.
2 如果没有取得 调用 getMethodTD(name)方法,取得真正要执行的方法,若取得则执行.
3 根据返回结果的类型不同 做不同的操作.
- // 改造的 dispatchMethod方法,重点看 //TD...字样所在的代码段
- protected ActionForward dispatchMethod(ActionMapping mapping,
- ActionForm form, HttpServletRequest request,
- HttpServletResponse response, String name)
- throws Exception {
- if (name == null) {
- return this.unspecified(mapping, form, request, response);
- }
- Method method = null;
- //TD: Modified by Wei Zijun
- boolean useTDMethod=false;
- try {
- // 按传统方式取 action方法
- method = getMethod(name);
- } catch (NoSuchMethodException ex) {
- try {
- // 没取到的话 再按新方式取 action方法
- method = getMethodTD(name);
- // 标识一下到底是使用的原始方法 还是新方法
- useTDMethod=true;
- } catch (NoSuchMethodException e) {
- String message =
- messages.getMessage("dispatch.method", mapping.getPath(), name);
- log.error(message, e);
- String userMsg =
- messages.getMessage("dispatch.method.user", mapping.getPath());
- throw new NoSuchMethodException(userMsg);
- }
- }
- ActionForward forward = null;
- try {
- //TD: Modified by Wei Zijun
- Object forwardR=null;
- if (!useTDMethod){
- // 如果是原始 action 方法
- Object[] args = { mapping, form, request, response };
- forwardR= method.invoke(this, args);
- }else{
- // 如果是新 action 方法
- // TDServletWrapperFactory.getInstance创建一个封装的对象
- Object[] args = { TDServletWrapperFactory.getInstance(mapping, form,request, response) };
- forwardR= method.invoke(this, args);
- }
- if (forwardR!=null){
- if (forwardR instanceof ActionForward){
- forward=(ActionForward)forwardR;
- }else{
- // 如果返回值是字符串:
- // 以 TD_NEW_FORWARD_PREFIX("NEW:")开头,则new ActionForward;
- // 否则 调用 mapping.findForward.
- if ( (String.valueOf(forwardR) ).toUpperCase().startsWith(TD_NEW_FORWARD_PREFIX)){
- forward = new ActionForward(String.valueOf(forwardR).substring(TD_NEW_FORWARD_PREFIX.length()) );
- }else{
- forward = mapping.findForward(String.valueOf(forwardR));
- }
- }
- }
- } catch (ClassCastException e) {
- String message =
- messages.getMessage("dispatch.return", mapping.getPath(), name);
- log.error(message, e);
- throw e;
- } catch (IllegalAccessException e) {
- String message =
- messages.getMessage("dispatch.error", mapping.getPath(), name);
- log.error(message, e);
- throw e;
- } catch (InvocationTargetException e) {
- Throwable t = e.getTargetException();
- if (t instanceof Exception) {
- throw ((Exception) t);
- } else {
- String message =
- messages.getMessage("dispatch.error", mapping.getPath(),
- name);
- log.error(message, e);
- throw new ServletException(t);
- }
- }
- return (forward);
- }
这样做完后,我们的action就可以支持下面的任何一种类型的方法了:
- // 传统方式
- public ActionForward testSubmit(ActionMapping mapping,ActionForm form, HttpServletRequest request,HttpServletResponse response) throws Exception;
- // 新方式
- public String testSubmit1(TDServletWrapper servletWrapper) throws Exception;
- // 以下两者是则中方式.
- public String testSubmit2(ActionMapping mapping,ActionForm form, HttpServletRequest request,HttpServletResponse response) throws Exception;
- public ActionForward testSubmit3(TDServletWrapper servletWrapper) throws Exception;
下面简单说一下 TDServletWrapper .
这个类实际上就是封装了 ActionMapping mapping,ActionForm form, HttpServletRequest request,HttpServletResponse response,
同时提供了一些用来简化开发的方法,例如
public String getParameter(String key,String ifNull);
public Integer getIntegerParameter(String key);
public void bind(Object bean);
等等.
不再具体叙述,看一下代码就应该都明白了.
TDServletWrapper 是一接口,他有两个实现:
TDServletWrapperTestImpl 为测试专用的,是一个与web容器无关的实现.
他主要就是利用"模拟"request response的方式来处理
目前他的实现还不是很完全(例如没有模拟session等),大家可以根据自己的需求来补充.
大家也可以根据这个原理 不用TDServletWrapper ,而完全的使用Map等,
总之,通过dispatchMethod的改造,几乎可以实现你全部的合理的想法(别超出Struts1的能力极限就行),我在这里提供的只是一个思路而已.
经过上面的改造,一个可测试的action就诞生了:
- public class MyClassicAction extends TDDispatchAction {
- // 一个添加user的操作
- public ActionForward addUser(TDServletWrapper servletWrapper) throws Exception {
- UserInfoVO vo=new UserInfoVO();
- servletWrapper.bind(vo);
- // 校验,并执行相关DAO操作
- if ( 添加成功 ) {
- return "Succee";
- }
- return "Fail";
- }
- }
测试的可以这样写:
- public static void testAddUser() throws Exception {
- // 创建一个action对象
- TestAction test=new TestAction();
- //准备一些测试数据 放入map里,模仿request的Parameters
- Map requestParameters=new HashMap();
- requestParameters.put("userName", "asdqe");
- requestParameters.put("password", "mghjghj");
- requestParameters.put("userRole", "1");
- requestParameters.put("email", "ut_email");
- requestParameters.put("gender", "1");
- requestParameters.put("age", "22");
- // TDServletWrapperFactory.getTestInstance 方法用来取得一个脱离web容器的 TDServletWrapper对象 )
- Assert.isTrue("Sucess".equals(test.testSubmit1(TDServletWrapperFactory.getTestInstance(requestParameters))) );
- }
至此全部改造完毕.
这样的改造对于大家来说也许没什么意义,不过多少也是一种尝试.
由于Struts1.X(>=1.2)的 局限性,以及我个人能力的局限性,很多改造还不够彻底 不够合理,
对于前者我无能为力,对于后者,还恳请大家多多指正我的不足 谢谢了先.
上次发了一篇对 spring jdbctemplate的改造,这次又发了一篇对 struts 1 的改造,
(其实我那个ecside 也是对老版extremecomponents的改造)
也许很多人会觉得我太落伍了,这些老掉牙的东西还改造个什么劲儿啊 呵呵
其实,很多时候,对于我来说,改造就是一个智力游戏,在一些现有的东西实现一些自己的新的想法,这样的感觉总是快乐的.
而且,我们的项目就是用的老技术 老东西,在不能换新东西的情况下,努力的挖掘现有东西的剩余价值,也许更具有实际意义.
- action.rar (4.7 KB)
- 描述: 源码,不包括示例代码
- 下载次数: 9
相关推荐
修炼成Javascript中级程序员必知必会_资源分享
内容概要:本文详细介绍了如何使用MATLAB的深度学习工具箱,在果树病虫害识别任务中从数据准备、模型设计、训练优化到最后的模型评估与应用全流程的具体实施步骤和技术要点。涵盖了MATLAB深度学习工具箱的基本概念及其提供的多种功能组件,如卷积神经网络(CNN)的应用实例。此外,文中还具体讲述了数据集的收集与预处理方法、不同类型的深度学习模型搭建、训练过程中的超参数设定及其优化手段,并提供了病虫害识别的实际案例。最后展望了深度学习技术在未来农业领域的潜在影响力和发展前景。 适合人群:对深度学习及农业应用感兴趣的科研人员、高校师生和相关从业者。 使用场景及目标:①希望掌握MATLAB环境下构建深度学习模型的方法和技术细节;②从事果树病虫害管理研究或实践,寻找高效的自动化解决方案。 阅读建议:在阅读本文之前,建议读者熟悉基本的MATLAB编程环境及初步了解机器学习的相关概念。针对文中涉及的理论和技术难点,可以通过官方文档或其他教程进行补充学习。同时,建议动手实践每一个关键点的内容,在实践中加深理解和掌握技能。
nodejs010-nodejs-block-stream-0.0.7-1.el6.centos.alt.noarch.rpm
机械模型与技术交底书的融合:创新点详解与解析,机械模型加技术交底书,有创新点 ,机械模型; 技术交底书; 创新点,创新机械模型与技术交底书详解
免费JAVA毕业设计 2024成品源码+论文+数据库+启动教程 启动教程:https://www.bilibili.com/video/BV1SzbFe7EGZ 项目讲解视频:https://www.bilibili.com/video/BV1Tb421n72S 二次开发教程:https://www.bilibili.com/video/BV18i421i7Dx
免费JAVA毕业设计 2024成品源码+论文+数据库+启动教程 启动教程:https://www.bilibili.com/video/BV1SzbFe7EGZ 项目讲解视频:https://www.bilibili.com/video/BV1Tb421n72S 二次开发教程:https://www.bilibili.com/video/BV18i421i7Dx
nodejs010-nodejs-cmd-shim-1.1.0-4.1.el6.centos.alt.noarch.rpm
西门子四轴卧加后处理系统:828D至840D兼容,四轴联动高效加工解决方案,支持图档处理及试看程序。,西门子四轴卧加后处理,支持828D~840D系统,支持四轴联动,可制制,看清楚联系,可提供图档处理试看程序 ,核心关键词:西门子四轴卧加后处理; 828D~840D系统支持; 四轴联动; 制程; 联系; 图档处理试看程序。,西门子四轴卧加后处理程序,支持多种系统与四轴联动
基于黏菌优化算法(SMA)的改进与复现——融合EO算法更新策略的ESMA项目报告,黏菌优化算法(SMA)复现(融合EO算法改进更新策略)——ESMA。 复现内容包括:改进算法实现、23个基准测试函数、多次实验运行并计算均值标准差等统计量、与SMA对比等。 程序基本上每一步都有注释,非常易懂,代码质量极高,便于新手学习和理解。 ,SMA复现;EO算法改进;算法实现;基准测试函数;实验运行;统计量;SMA对比;程序注释;代码质量;学习理解。,标题:ESMA算法复现:黏菌优化与EO算法融合改进的实证研究
基于MATLAB的Stewart平台并联机器人仿真技术研究与实现:Simscape环境下的虚拟模拟分析与应用,MATLAB并联机器人Stewart平台仿真simscape ,MATLAB; 并联机器人; Stewart平台; 仿真; Simscape; 关键技术。,MATLAB中Stewart平台并联机器人Simscape仿真
Grad-CAM可视化医学3D影像
探索comsol泰勒锥:电流体动力学的微观世界之旅,comsol泰勒锥、电流体动力学 ,comsol泰勒锥; 电流体动力学; 锥形结构; 电场影响,COMSOL泰勒锥与电流体动力学研究
免费JAVA毕业设计 2024成品源码+论文+数据库+启动教程 启动教程:https://www.bilibili.com/video/BV1SzbFe7EGZ 项目讲解视频:https://www.bilibili.com/video/BV1Tb421n72S 二次开发教程:https://www.bilibili.com/video/BV18i421i7Dx
PFC6.03D模型动态压缩模拟与SHPB霍普金森压杆系统理论及实验数据处理技术解析,PFC6.03D模型,动态压缩模拟,还包括: SHPB霍普金森压杆系统理论知识介绍,二波法和三波法处理实验数据,提出三波波形,计算动态压缩强度等 ,PFC模型; 动态压缩模拟; SHPB霍普金森压杆系统; 理论介绍; 二波法处理; 三波法处理; 三波波形; 动态压缩强度。,"PFC模型下的动态压缩模拟及SHPB理论实践研究"
ProASCI 开发板原理图,适用于A3P3000
免费JAVA毕业设计 2024成品源码+论文+录屏+启动教程 启动教程:https://www.bilibili.com/video/BV1SzbFe7EGZ 项目讲解视频:https://www.bilibili.com/video/BV1Tb421n72S 二次开发教程:https://www.bilibili.com/video/BV18i421i7Dx
1、文件内容:pykde4-devel-4.10.5-6.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/pykde4-devel-4.10.5-6.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、安装指导:私信博主,全程指导安装
基于Comsol模拟的三层顶板随机裂隙浆液扩散模型:考虑重力影响的瞬态扩散规律分析,Comsol模拟,考虑三层顶板包含随机裂隙的浆液扩散模型,考虑浆液重力的影响,模型采用的DFN插件建立随机裂隙,采用达西定律模块中的储水模型为控制方程,分析不同注浆压力条件下的浆液扩散规律,建立瞬态模型 ,Comsol模拟; 随机裂隙浆液扩散模型; 浆液重力影响; DFN插件; 达西定律模块储水模型; 注浆压力条件; 浆液扩散规律; 瞬态模型,Comsol浆液扩散模型:随机裂隙下考虑重力的瞬态扩散分析
A simple fast, easy use distributed file system written by golang(similar fastdfs).go-fastdfs