论坛首页 Java企业应用论坛

struts1.x & struts2对比学习及源码分析

浏览 5806 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (12) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-05-10   最后修改:2010-05-13

Struts1.x综述

一、业务逻辑

应包含在POJO类或EJB中,完全独立于Action。这样做的优点就是不依赖与框架本身,更好复用。
原则:类和类的方法应该有自己独立的职责,能够完成所建领域的特定任务(如ActionForm)


二、处理Exception
原则:1)在异常离开业务层之前捕获,处理,记录业务层抛出的所有异常;
      2)在业务层捕获一个异常时,作为一个通用的异常类型重新抛出。
编制定制ExceptionHandler(如加入邮件通知,log记录等功能)
  1、扩展org.apache.struts.action.ExceptionHandler,并重写execute方法
  2、配置exception时,加入handle选项


三、ActionForm与Action
  1、将ActionForm与业务逻辑分离,将ActionForm收集的数据copy到VO对象中,可以借助BeanUtils类完成该项功能。
  2、将ActionForm中的公共属性设置为String类型(用户处理数字类型或Date类型,ActionForm默认会做类型转化,如果不能转化会抛出异常,可以用JS在前台处理数据或后台转化,后台转化不成抛出自定义异常信息)
  3、将Action作为业务逻辑的调用点,而不是插入点。
  4、在ActionForm的reset方法中注意清空checkbox,应为在没有选中checkbox时,HTTP协议发送的数据为空,而页面中原来被选中的不会改变。


四、验证
  ActionForm的validate方法
  Struts验证框架
  JS前台验证


五、扩展Struts
1、扩展RequestProcessor,实现自己的控制器 实际上struts的控制器是RequestProcessor,而不是ActionServlet
  a)继承org.apache.struts.action.RequestProcessor
  b)重写process,processActionPerform,processPreProcess方法
  一般不重写processPreProcess方法,主要是其抛出了ServletException和IOException
c)在配置文件中配置<controller processorClass="**.*Controller"/>

========strut1.x源码分析==========


一、Struts1.x
1、ActionServlet
  init方法中初始化ActionMapping,ActionForward
  doGet,doPost方法调用ActionServlet.process方法,其间接调用RequestProcessor.process方法
                                
2、RequestProcessor
process
processPreProcess 设计上是一个钩子 可以在Action调用之前做一些动作。

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
private static Log log = LogFactory.getLog(ActionMapping.class);
processActionCreate Action 是单实例的,因为其存在一个HashMap中
        Action instance = (Action) actions.get(className);
            if (instance != null) {
                if (log.isTraceEnabled()) {
                    log.trace("  Returning existing Action instance");
                }
                return (instance);
        }
       
ServletContext.getRequestDispatcher(String url) url为绝对地址
ServletRequest.getRequestDispatcher(String url) url为相对地址

HashMap中keySet方法返回key值集合,values方法返回value集合

http://localhost:8088/news/main/list.jsp news是应用程序的名字
则执行下面向行代码后打印出如下结果:
1、System.out.println(request.getContextPath());  打印结果:/news
2、System.out.println(request.getServletPath());  打印结果:/main/list.jsp
3、System.out.println(request.getRequestURI());   打印结果:/news/main/list.jsp
4、System.out.println(request.getRealPath("/"));  打印结果: F:\Tomcat 6.0\webapps\news\test

struts1.x配置细节:Action中配置ActionForm,实例化ActionForm根据attribute配置

processPopulate中定义了处理ActionForm的定义

ModuleConfigImpl implements ModuleConfig
   public ModuleConfigImpl(String prefix) {
        super();
        this.prefix = prefix;
        this.actionConfigs = new HashMap();
        this.actionConfigList = new ArrayList();
        this.actionFormBeanClass = "org.apache.struts.action.ActionFormBean";
        this.actionMappingClass = "org.apache.struts.action.ActionMapping";
        this.actionForwardClass = "org.apache.struts.action.ActionForward";
        this.configured = false;
        this.controllerConfig = null;
        this.dataSources = new HashMap();
        this.exceptions = new HashMap();
        this.formBeans = new HashMap();
        this.forwards = new HashMap();
        this.messageResources = new HashMap();
        this.plugIns = new ArrayList();
   }
  
二、struts2
1、Action 普通POJO类
Struts2为Action的执行,准备了完整的数据环境和执行环境。而这个执行环境,就保证了Action在Web容器中的顺利运行。
2、Interceptor
Interceptor
  init();
  destory();
  String intercept(ActionInvocation invocation) throws Exception{//核心方法
  //doSomething....
  String result=invocation.invoke();
  //invocation.invoke()这个方法其实是整个拦截器框架的实现核心
  //ActionInvocation作为Action的调度者
  //doSomething....
  return result;
  }
 
3、result类型
Interface Result {
public void execute (ActionInvocation invocation) throws Exception{
}
}
dispatcher
redirect


 
4、测试
单元测试
  Interceptor借助ActionProxy
  Dispatcher
  ObjectFactory可配置,即struts.objectFactory=spring
  action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);  

5、Struts2源码分析
ActionMapper
  其实是HttpServletRequest和Action调用请求的一个映射,屏蔽了Action对于容器的依赖
ActionProxy&ActionInvocation
  Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,默认实现DefaultActionProxy是由ActionInvocation持有Action实例。
  ActionProxy作用是如何取得Action,无论是本地还是远程。
  而ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。

ConfigurationProvider&Configuration
  ConfigurationProvider就是Struts2中配置文件的解析器
  Struts2中的配置文件主要是尤其实现类XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析。
 
6. Struts2请求流程
1、客户端发送请求
2、请求先通过ActionContextCleanUp-->FilterDispatcher
3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action
4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate--Dispatcher来执行
5、ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类
6、ActionProxy创建一个ActionInvocation的实例
7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用
8、Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现。


java.util.concurrent包

preResultListeners 在处理Request之前可以做一些事情
RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);
if(dispatcher==null){
response.sendError(404,"result not found!!");
}

struts2标签

<s:iterator value="books" id="book" status="stat">
<tr>
<td><s:property value="#stat.count"/></td>
<td><s:property value="#book.name"/></td>
<td><s:property value="#book.author"/></td>
<td><s:property value="#book.publisher"/></td>
<td><s:property value="#book.price"/></td>
<td><s:date name="#book.publishDate" format="yyyy年MM月dd"></s:date></td>
<td><a onclick="return confirm('确认删除《${book.name }》')" href="book!delete.action?id=${book.id }">删除</a></td>
<td><a href=<s:url action="book" method="delete"></s:url>>更新</a></td>
</tr>
</s:iterator>

   <!-- 如何使用ognl表达式对集合过滤
     返回books集合中符合price>100的所有元素对象
     ?:表示返回所有满足条件的对象
     ^:表示返回第一个满足条件的对象
     $:表示返回最后一个满足条件的对象
   -->
  <s:iterator value="books.{?#this.price>100}" id="book">
  <tr>
  <td>${book.name }</td>
  <td>${book.author }</td>
  <td>${book.publisher }</td>
  <td>${book.price }</td>
  </tr>
  </s:iterator>
  </table>
  <hr>
  <!-- 定义一个age变量,可使用scope属性指定变量所属范围,
  scope属性值可为page、request、session、application、action。
  如果不加scope属性,则默认范围是context中 -->
  <s:set name="age" value="28"></s:set>
  <!-- test属性指定一个ognl表达式 -->
  <s:if test="age > 20">
  成年人
  </s:if>
  <s:else>
  未成年
  </s:else>
 
  OGNL表达式
  </h1><hr>
  <h1>
    action:<s:property value="name"/><br>
     request:<s:property value="#request.name"/>
     :<s:property value="#request.name1"/>
     <br>
     session:<s:property value="#session.name"/><br>
    application:<s:property value="#application.name"/><br>
    <hr>
    <s:property value="person.name"/>
    <s:property value="person.address"/><br>
    <s:property value="user.name"/>
    <s:property value="user.address"/>
    <hr>EL表达式在Struts2中的使用<br>
    ${name }
</h1>

 

   发表时间:2010-05-10  
前台验证太臃肿,不要使用。

还有一个是线程安全方面的实践。
0 请登录后投票
   发表时间:2010-05-11  
mercyblitz 写道
前台验证太臃肿,不要使用。

还有一个是线程安全方面的实践。


但是我发现很多网站都用JS做前台验证的啊,比如163邮箱等

线程安全方面的实践,谢谢提醒。
0 请登录后投票
   发表时间:2010-05-11  
mercyblitz 写道
前台验证太臃肿,不要使用。

还有一个是线程安全方面的实践。


但是我发现很多网站都用JS做前台验证的啊,比如163邮箱等

你误会我意思啦,Struts会把所有的验证方法全部压倒客户端,不是说不要JS验证。
0 请登录后投票
   发表时间:2010-05-12  
这种古董还有人研究呀
0 请登录后投票
   发表时间:2010-05-12  
这个不只是structs1.x吧。任何三层框架都应该是这样的啦。
0 请登录后投票
   发表时间:2010-05-12  
恩 我们不能局限于框架本身~
0 请登录后投票
   发表时间:2010-06-21  
发表下个人看法

1. 任何MVC框架关于前台UI的那部分我感觉都比较鸡肋,前台可以自己去实现,比如jQuery, ext, flex, 用他们提供的很不灵活,不可控。前台验证可以用jquery提供的验证,如果是ext或flex项目,框架自身提供验证。
2. Struts2的Action可以是线程安全的,与Spring集成时,定义bean的时候要定义成非单利模式,即可线程安全,每次实例化。
3. S1与S2虽说是一个公司的产品,但是两个时代的产物,可以当做只是名一样而已
0 请登录后投票
   发表时间:2010-07-02  
struts1.x我只用他的formbean 和 action 控制,感觉是最简单好用的框架了。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics