知识大全 Struts教程-Struts的几个精细之处

Posted

篇首语:未知的事物总是被人以为奇妙无比。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Struts教程-Struts的几个精细之处相关的知识,希望对你有一定的参考价值。

Struts教程-Struts的几个精细之处  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  最近在网上看到一篇N Alex Rupp写的 Beyond MVC: A New Look at the Servlet Infrastructure 文章 意思大致是说MVC被Struts等框架错误地应用到了Servlet架构中 我想只有对Struts有足够的了解再加上在MVC方面有足够深的功力 才敢发此言论 不是经常听人说 最熟悉自己的人是你的敌人 本人功力尚浅 没有引领风潮的能力 而且生活还得继续 只能先来熟悉熟悉Struts

  申明 强烈建议在阅读本文之前先阅读一下N Alex Rupp老兄的文章 如果你赞同他的看法 可能你会觉得研究Struts就没什么意义了

  说明 本文所讲的Struts知识基于Struts 版本 除非特别说明 本文中的Struts都特指Struts 这个版本

  精细之处一 利用Token解决重复提交 背后的前提

  我们知道 可以利用同步令牌(Token)机制来解决Web应用中重复提交的问题 Struts也给出了一个参考实现 服务器端在处理到达的请求之前 会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较 看是否匹配 在处理完该请求后 且在答复发送给客户端之前 将会产生一个新的令牌 该令牌除传给客户端以外 也会将用户会话中保存的旧的令牌进行替换 这样如果用户回退到刚才的提交页面并再次提交的话 客户端传过来的令牌就和服务器端的令牌不一致 从而有效地防止了重复提交的发生 对应于这段描述 你可能会在你的Action子类中有这么一段代码

  

   if (isTokenValid(request true)) // your code here return mapping findForward( success ); else saveToken(request); return mapping findForward( submitagain );

  其中isTokenValid()和saveToken()都是 apache struts action Action类中的方法 而具体的Token处理逻辑都在 apache struts util TokenProcessor类中 Struts中是根据用户会话ID和当前系统时间来生成一个唯一(对于每个会话)令牌的 具体实现可以参考TokenProcessor类中的generateToken()方法

  不知道大家有没有注意到这样一个问题 因为Struts是将Token保存在Session的一个属性中 也就是说对于每个会话服务器端只保存而且只能保存一个最新Token值 对于这一点 我的同事就提出了疑问 那如果我在同一个会话中打开两个页面 那么后提交的那个页面肯定不能提交成功了 他还给出了一个实际的例子 比如现在需要把两个客户A和B的地址都改为某个值 那用户就可能同时打开两个页面 修改A 修改B 提交A 提交B 按照Struts中的处理逻辑 B的修改提交就肯定不能成功 但是这个提交操作对于用户来说并不存在操作不正确的地方

  在这里 可能有人要问 怎么可能在同一个会话中打开两个页面呢?重新打开一个IE浏览器不是重新开始了一个会话吗?不错 这种情况下是两个会话 不存在任何问题 但是 你还可以通过菜单 文件 - 新建 - 窗口 (或者快捷键Ctrl+N)来复制当前窗口 这个时候你会发现该页面与原有页面同处在一个会话当中 其实 能够发现这个问题得归功于我的那位同事对IE习惯性的操作方法

  这下我的那位同事不满意啦 他于是开始动手修改Struts中的实现方式 让每个页面(至少某类页面)在服务器端都保存有一个唯一的Token值 这样 前面所讲的客户A B同时修改的限制就不存在了 但是不久 我的那位同事就开始意识到他正在走向一条危险的道路 首先 如果每个页面都在服务器端保存一个Token值 则服务器端保存的数据量将越来越大 而且 如果考虑这种同一个会话中打开多个页面的情况的话 就好像打开了潘多拉魔盒 将会给自己带来无穷无尽的麻烦 比如 首先打开页面P 然后利用Ctrl+N得到页面P P 提交 P 提交 目前为止一切正常 但是如果此时 在P P 中点击 后退 按钮 然后再提交P P 呢 情况会是怎样?如果在P 中提交完后执行其它操作 而在P 中回退后提交 情况又是怎么样呢?如果有P P P 那情况又是如何呢?太复杂啦!我想你也会和我们有同感 你需要考虑许多种可能的组合 而且有的时候结果并不是你想象中的那样简单

  此路不通 还得回来看看Struts 其实经过以上一番折腾 我们可以发现在Struts中的Token机制背后隐藏着这样一个前提 不允许你(客户端)在同一会话中打开多个页面 注意是同一会话 如果打开两个IE浏览器 那已经是两个会话啦 不受该限制 其实 这个看似不合理的规定却自有其道理 一是它极大地简化了Token的实现 二个这种限定也符合大部分人的使用习惯

  精细之处二 页面流转控制中的职责分配

  我们知道 Struts的执行过程大致如下 首先 控制器接收到客户端请求 将这些请求映射至相应的Action 并调用Action的execute方法 这中间可能还涉及到ActionForm的创建和填充 Action的execute方法执行完以后 返回一个ActionForward对象 控制器根据该ActionForward对象将请求转发至下一个Action或JSP 最后 产生视图响应客户 在大的层面上 Struts是采用了MVC这种架构 没什么特别之处 但从一些小的地方 我们还是可以看出Craig R McClanahan老兄的一些考虑 我们看到Action与控制器之间传递的是ActionForward对象 由于Action的execute方法要求返回一个ActionForward对象 所以你会经常在Action子类中看到如下语句

  

   return (new ActionForward(mapping getInput()));

  或

  

   return (mapping findForward( success ));

  其实返回的就是一个ActionForward对象 在Action中我们根据程序执行的不同情况 决定接下来的页面走向(比如返回到输入页面或者转到下一个页面) 并将这些信息保存在ActionForward对象中 而接下来控制器就可以直接利用该ActionForward对象来进行页面的流转 下面是 apache struts action RequestProcessor类的processForwardConfig()方法的摘录 该方法调用发生在Action实例调用后

  

   protected void processForwardConfig(HttpServletRequest request HttpServletResponse response ForwardConfig forward) throws IOException ServletException … String forwardPath = forward getPath(); String uri = null; // paths not starting with / should be passed through without any processing // (ie they re absolute) if (forwardPath startsWith( / )) uri = RequestUtils forwardURL(request forward); // get module relative uri else uri = forwardPath; if (forward getRedirect()) // only prepend context path for relative uri if (uri startsWith( / )) uri = request getContextPath() + uri; response sendRedirect(response encodeRedirectURL(uri)); else doForward(uri request response);

  注意 ForwardConfig是ActionForward的父类

  该方法首先调用ForwardConfig的getPath()方法获得下一步流转的路径 在某些条件下还需要进行一些拼装得到正确的URI 最后根据该URI进行页面跳转 可见在processForwardConfig()方法中只是对ActionForward进行了一些 技术上 的处理 没有任何和业务相关的内容 这样就将控制器(ActionServlet)和Action完全分开来 两者互不影响 达到了功能模块之间松散耦合的目的

  模块间(系统间)松散耦合一直是OO设计所追求的 但是具体如何去实现这样一种松散耦合却不是那么容易做到的 Struts中的设计给了我们一些启示 模块间相互关联影响因素的传递可以用对象的形式来包装起来 其实 个人觉得Struts中的做法还可以稍微有一点点改进 就是在ActionForward中提供一个getURI()方法来给出最终的URI岂不是更好?

  参考

   Beyond MVC: A New Look at the Servlet Infrastructure

   Allen Holub的Build user interfaces for object oriented systems系列文章 可以从这篇文章中学到很多面向对象设计方面的知识 虽然作者并不认为MVC是一种面向对象的方法 但是我们这些MVC的实践者仍然可以从中学到面向对象的知识

   Struts 的介绍性文章 深入Struts

   Apache Struts Website

   关于重复提交问题的讨论及其解决方案 可以参考《Core J EE Patterns》一书(中文版《J EE核心模式》)

cha138/Article/program/Java/ky/201311/27929

相关参考

知识大全 JSP、Struts避免Form重复提交的几种方案

JSP、Struts避免Form重复提交的几种方案  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 Java Struts几个面试题

JavaStruts几个面试题  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!cha138

知识大全 struts2 中的日期格式化输出

  struts中的默认的日期输出并不符合我们的中文日常习惯以下是我知道的在struts中进行日期格式化输出的几种方式  利用<s:date>进行格式化如  <s:dateforma

知识大全 一个高效简洁的Struts分页方法

一个高效简洁的Struts分页方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在网上看了几个

知识大全 struts2中的通配符

  Action通配符(wildcard)的配置  使用通配符将配置量降到最低不过一定要遵守约定优于配置的原则   通配符  星号(*) 表示所有  数字 表示第几个通配符  例如

知识大全 学习比较Struts2和Struts1:Struts2完胜

学习比较Struts2和Struts1:Struts2完胜  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一

知识大全 Struts处方:Hibernate与Struts

Struts处方:Hibernate与Struts  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 Struts的后代:Shale不是Struts

Struts的后代:Shale不是Struts  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  S

知识大全 Struts2与Struts1的对比

Struts2与Struts1的对比  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Action

知识大全 Struts从零开始六、Struts的模块使用实例

Struts从零开始六、Struts的模块使用实例  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!