zoukankan      html  css  js  c++  java
  • Struts2 Action与Servlet API耦合

    单元测试在开发中是非常重要的一个环节
    程序员在写完代码时,相应的单元测试也应写完整,否则你的代码就是不能让人信服的
    Struts2将Action与Servlet的API进行解耦之后,就使得单元测试变得非常容易了
    比如HttpServletRequest对象,它是由Tomcat容器给我们提供的,我们自己产生不出来
    若Action中充斥者ServletAPI,哪怕仅一个,那么一般意义上的JUnit单元测试便无法进行
    若Action中耦合了ServletAPI,可以采用apache的Cactus对它进行测试,这要稍微麻烦些
    另外也可以采用Mock,它本身是模拟的Servlet的API的一些相关的对象
    然后用模拟出来的对象代替容器中产生的对象,来实现对应用程序的访问
    而Struts2的Action已经脱离了ServletAPI,所以无需这两种方式,便可直接用JUnit测试


    Struts2和Struts1.X中关于Action的测试
    Struts1.X的Action依赖于ServletAPI,比如HttpServletRequest、HttpServletResponse对象
    这些类都是和容器结合的,所以必须启动Tomcat服务器之后才能获得容器里面的对象
    所以测试时比较麻烦。而Apache提供了可以捆绑到Eclipse上专门用于独立测试的项目
    它为我们模拟了一系列的HttpServlet对象,使用它之后就可以脱离Tomcat独立测试
    Struts2的Action不依赖容器,它和容器无关,所以能够脱离容器进行单独测试
    换句话说,我们可以直接在Action里面写一个main()方法进行测试,这是没问题的
    这在Struts1.X中是不可想象的,它必须要么启动Tomcat然后去测试,要么装插件再进行测试


    Struts2没有与任何的Servlet API耦合
    这样可以不依赖于Web容器【如Tomcat】轻松测试Action
    Struts2为我们提供了三种方式,使得我们可以轻松获得Servlet的API
    ActionContext
    ServletActionContext
    实现特定接口
    由于com.opensymphony.xwork2.ActionContext已经与Servlet的API完全解耦
    所以建议首选ActionContext次之采用ServletActionContext最不推荐使用接口


    第一种com.opensymphony.xwork2.ActionContext类
    首先通过ActionContext类的静态getContext()方法获得当前线程相关的一个ActionContext实例
    然后就可以通过该实例调用它的众多方法得到Servlet的一些API
    public Object get(Object key)方法,就相当于HttpServletRequest.getAttribute()
    public void put(Object key, Object value)对应HttpServletRequest.setAttribute()
    public Map<String, Object> getParameters()对应HttpServletRequest.getParameterMap()
    public Map<String, Object> getSession()方法对应javax.servlet.http.HttpSession
    session.put(Object key, Object value)对应Servlet编程中的HttpSession.setAttribute(…)
    也就是说,ActionContext能够获得三个Map类型的Request, Session, Application对象
    ActionContext有一个好处,就是它已经将底层的Servlet进行了转化,比如它将session转化成Map
    这样在测试时,Struts2便可脱离Servlet容器进行单纯的JUnit测试


    第二种org.apache.struts2.ServletActionContext类
    ServletActionContext.getRequest()对应javax.servlet.http.HttpServletRequest
    ServletActionContext.getResponse()对应javax.servlet.http.HttpServletResponse
    ServletActionContext.getServletContext()对应javax.servlet.ServletContext
    它的方法全都是static的。另外它所获得的ServletContext对象,就相当于Application
    因为它的生命周期与Application生命周期是一样的,只要服务器不关闭,就都是有效的
    ServletActionContext可以获得和容器绑定Request, Response, ServletContext对象
    这里获得的都不是Map对象,所以在测试的时候,就必须要启动Tomcat服务器


    第三种org.apache.struts2.util.ServletContextAware接口
    它仅有个void setServletContext(javax.servlet.ServletContext context)方法
    通过该方法获得的ServletContext就相当于Application,二者生命周期都是相同的
    以及org.apache.struts2.interceptor.ServletRequestAware接口
    同样有个void setServletRequest(javax.servlet.http.HttpServletRequest request)方法
    以及org.apache.struts2.interceptor.ServletResponseAware接口
    同样有个void setServletResponse(javax.servlet.http.HttpServletResponse response)方法
    使用方式及示例代码,如下所示
    此时需设置一个跟Servlet容器耦合HttpServletRequest类型request成员变量
    当执行完setServletRequest()方法,成员变量就被它的HttpServletRequest参数赋值了
    该方法是由Struts2自动调用的,显然这是一种非常非常典型的依赖注入DI
    由Struts2自动将容器产生的HttpServletRequest对象set到我们应用中的变量上
    这样成员变量request就变成了容器所产生的HttpServletRequest对象了
    接下来就可以正常的使用request了,使用方法与在Servlet中的使用方式是一样的

    1. public class DecoupleAction implements ServletRequestAware {  
    2.     private HttpServletRequest request;  
    3.     public void setServletRequest(HttpServletRequest arg0) {  
    4.         this.request = arg0;  
    5.     }  
    6. }  
    1. public class DecoupleAction implements ServletRequestAware {  
    2.     private HttpServletRequest request;  
    3.     public void setServletRequest(HttpServletRequest arg0) {  
    4.         this.request = arg0;  
    5.     }  
    6. }  

    补充org.apache.struts2.interceptor.RequestAware接口
    示例代码如下

    1. public class DecoupleAction implements RequestAware, SessionAware, ApplicationAware {  
    2.     Map request;  
    3.     Map session;  
    4.     Map application;  
    5.     public void setRequest(Map arg0) {  
    6.         this.request = arg0;  
    7.     }  
    8.     public void setSession(Map arg0) {  
    9.         this.session = arg0;  
    10.     }  
    11.     public void setApplication(Map arg0) {  
    12.         this.application = arg0;  
    13.     }  
    14. }  
    1. public class DecoupleAction implements RequestAware, SessionAware, ApplicationAware {  
    2.     Map request;  
    3.     Map session;  
    4.     Map application;  
    5.     public void setRequest(Map arg0) {  
    6.         this.request = arg0;  
    7.     }  
    8.     public void setSession(Map arg0) {  
    9.         this.session = arg0;  
    10.     }  
    11.     public void setApplication(Map arg0) {  
    12.         this.application = arg0;  
    13.     }  
    14. }  

    这里用到了IoC模式,即将三个Map变量初始化的权利交给了调用者,即容器
    容器会自动的利用这三个setXxx()方法将三个Map变量的值从外面注入进来
    而我们在Action中不需要new出来Map对象,也不需要做任何的初始化操作
    然后就可以直接使用request, session, application三个对象了


    小结
    与Servlet容器解耦非IoC方法:com.opensymphony.xwork2.ActionContext类  (ActionContext )
    与Servlet容器解耦的   IoC方法:RequestAware、SessionAware、ApplicationAware接口
    与Servlet容器耦合非IoC方法:org.apache.struts2.ServletActionContext类 (ServletActionContext)
    与Servlet容器耦合的   IoC方法:ServletRequestAware、ServletResponseAware接口 

  • 相关阅读:
    灵活使用ssh、dsh和pssh高效管理大量计算机
    GDPR全文翻译(二)
    GDPR全文翻译(一)
    加盐密码哈希:如何正确使用
    p2p通信原理及实现
    拜耳阵列
    数码相机成像原理
    图像基础
    antd Tree组件中,自定义右键菜单
    如何保障前端项目的代码质量
  • 原文地址:https://www.cnblogs.com/nucdy/p/5088284.html
Copyright © 2011-2022 走看看