zoukankan      html  css  js  c++  java
  • 【深入Struts2】获取ServletAPI的三种方式

    一:获取servletAPI的三种方法

           在传统的Web开发中,经常会用到Servlet API中的HttpServletRequest、HttpSession和ServletContext。Struts 2框架让我们可以直接访问和设置action及模型对象的数据,这降低了对HttpServletRequest对象的使用需求,同时降低了对servletAPI的依赖性,从而降低了与servletAPI的耦合度。但在某些应用中,我们可 能会需要在action中去访问HttpServletRequest等对象,所以有时候我们不得不拉近struts2和servletAPI的关系,但struts2也有尽量减少耦合度的方法,下面我们就一起具体看一下在struts2中获得ServletAPI的三种方法:

    1.ServletAPI解藕方式(一)获取Map对象:

        为了避免与Servlet API耦合在一起,方便Action类做单元测试,Struts 2对HttpServletRequest、HttpSession和ServletContext进行了封装,构造了三个Map对象来替代这三种对象,在Action中,直接使用HttpServletRequest、HttpSession和ServletContext对应的Map对象来保存和读取 数据。可以通过com.opensymphony.xwork2.ActionContext类来得到这三个对象。ActionContext是Action执行的上下文,保存了很多对象如parameters、request、session、application和locale等。通过ActionContext类获取Map对象的方法为:

    ActionContext  context=ActionContext.getContext();  //得到Action执行的上下文  
      
    Map  request=(Map)context.get("request"); //得到HttpServletRequest的Map对象  
      
    Map  session=context.getSession();//得到HttpSession的Map对象  
      
    Map  application=context.getApplication();//得到ServletContext的Map对象

    ActionContext中保存的数据能够从请求对象中得到,其中的奥妙就在于Struts 2中的org.apache.struts2.dispatcher.StrutsRequestWrapper类,这个类是 HttpServletRequest的包装类,它重写了getAttribute()方法(在页面中获取request对象的属性就要调用这个方法), 在这个方法中,它首先在请求对象中查找属性,如果没有找到(如果你在ActionContext中保存数据,当然就找不到了),则到 ActionContext中去查找。这就是为什么在ActionContext中保存的数据能够从请求对象中得到的原因。

    2.IOC(控制反转)获取servletAPI

     

         Action类还有另一种获得ServletAPI的解耦方式,这就是我们可以让他实现某些特定的接口,让Struts2框架在运行时向Action实例注入request、session和application对象。这种方式也就是IOC(控制反转)方式,与之对应的三个接口和它们的方法如下所示:

    public class SampleAction implementsAction,  
    RequestAware, SessionAware, ApplicationAware  
    {  
    private Map request;  
    private Map session;  
    private Map application;  
      
    @Override  
    public void setRequest(Map request)  
    {this.request = request;}  
      
    @Override  
    public void setSession(Map session)  
    {this.session = session;}  
      
    @Override  
    public void setApplication(Map application)  
    {this.application = application;}  
      
    }  

    ServletRequestAware接口和ServletContextAware接口不属于同一个包,前者在org.apache.struts2.interceptor包中,后者在org.apache.struts2.util包中,这很让人迷惑。

     

    3.与Servlet API耦合的访问方式

        直接访问Servlet API将使你的Action与Servlet环境耦合在一起,我们知道对于HttpServletRequest、 HttpServletResponse和ServletContext这些对象,它们都是由Servlet容器来构造的,与这些对象绑定在一起,测试时就需要有Servlet容器,不便于Action的单元测试。但有时候,我们又确实需要直接访问这些对象,那么当然是以完成任务需求为主。要直接获取HttpServletRequest和ServletContext对象,可以使用org.apache.struts2. ServletActionContext类,该类是ActionContext的子类,在这个类中定义下面两个静态方法:

    1.得到HttpServletRequest对象:

    public static HttpServletRequestgetRequest()

    2.得到ServletContext对象:

    public static ServletContextgetServletContext()

    此外,ServletActionContext类还给出了获取HttpServletResponse对象的方法,如下:

    public static HttpServletResponsegetResponse()

    ServletActionContext类并没有给出直接得到HttpSession对象的方法,HttpSession对象可以通过HttpServletRequest对象来得到。

    除了上述的方法调用得到HttpServletRequest和ServletContext对象外,还可以调用ActionContext对象的 get()方法,传递ServletActionContext.HTTP_REQUEST和 ServletActionContext.SERVLET_CONTEXT键值来得到HttpServletRequest和 ServletContext对象同样的,也可以向ActionContext的get()方法传递ServletActionContext.HTTP_ RESPONSE键值来得到HttpServletResponse对象

     

           总结:通过上面三种方式的讲解我们可以看出,三种获得servletAPI的方式基本都差不多,通常我们建议大家采用第一种方式来获取HttpServletRequest和ServletContext对象,这样简单而又清晰,并且降低了和servletAPI的耦合度,这样也方便进行单元测试

    二:struts2封装请求参数三种方式

         在struts2开发应用中,我们可能经常要求获得视图层传过来的很多数据,一般都是一个实体类的n多属性,很多时候实体类的属性特别多,这时候如果还是按以前的方式在action里面一个个的定义出这些属性的私有变量,然后在提供set、get方法的话,这样就会使整个action太臃肿,严重妨碍了代码的可阅读性,并且也违背了代码的可复用性,这时我们就需要对这些请求参数进行封装,提高代码的可复用性,下面我们就一起来具体看一下三种封装请求参数的方法:

    1.利用实体类封装参数

            这种方式是封装参数最简单的方法,一般也比较常用,因为在我们的struts应用程序中,我们一般会根据数据库的信息写出对应的实体类,所以这正好使我们可以利用的,下面我们看一下具体操作:

    1.创建实体类user(包括用户名和密码属性),这里比较简单,我们就不贴出代码了。

    2.创建action,这里我们主要是来看一下action接收数据的属性这个地方,我们就不是在一一定义这些属性的私有变量了,我们直接定义一个对应实体类的私有对象就可以了,代码如下:

    publicclass LoginAction extends ActionSupport {  
      
        private User user;  
      
        public User getUser() {  
      
            returnuser;  
      
        }  
      
        publicvoid setUser(User user) {  
      
            this.user = user;  
      
        }  
      
        public String execute(){  
      
        if(user.getUsername().equals("admin")&&user.getPassword().equals("123456"))  
      
                return"success";  
      
            return"fail";  
      
        }  
      
    }  

    3.定义表单,这里我们需要注意一下,这里表单里面的控件的name属性定义有一定的要求,定义name时我们应该定义为:对象.属性的形式,

    示例代码:

    <s:form action="LoginAction">  
      
      <s:actionerror/>  
      
     <s:textfield name="user.username"></s:textfield>  
      
    <s:password name="user.password"></s:password>  
      
      <s:submit value="提交" ></s:submit>  
      
       </s:form>  

    4.配置struts.xml,这里配置和平常一样,这里就不再重复了

    至此,我们简单的实体类封装请求参数就完成了,我相信大家一定也会感觉很简单吧

     

    2.模型驱动封装请求参数
          模型驱动是指使用JavaBean来封装来回请求的参数.这种方式的好处就是减少了action的压力。既用于封装来回请求的参数,也保护了控制逻辑,使它的结构清晰.这就是模型驱动的优势.

    下面我们具体来看一下模型驱动的具体实现:

    模型驱动的实现主要是体现在action上

    1.首先建立一个实体,比较简单,这里就不再写了。

    2.建立action类,继承自ActionSupport,实现ModelDriven接口,这个接口定义了一个getModel()方法,用于返回定义的Model,然后调用set方法,进行赋值。

    代码示例:

    <span xmlns="http://www.w3.org/1999/xhtml">publicclass LoginAction3 extends ActionSupport implementsModelDriven<User> {  
     private User user=new User();//这里记住要实例化  
     private LoginService loginService=new LoginServiceImpl();//这里是调用登录的业务处理逻辑  
    @Override  
     public User getModel() {  
     //TODOAuto-generated method stub  
     return user;  
    }  
     public String execute()  
    {  
    System.out.println(user.getUsername());  
    System.out.println(user.getPassword());  
      
     if(loginService.isLogin(user.getUsername(),user.getPassword()))  
    {  
     return SUCCESS;  
    }  
     return INPUT;  
    }  
    }</span>  

    在com.opensymphony.xwork2.ModelDriven接口源代码中有一段很重要的说明,现抄录如下
    ModelDriven Actions provide a model object to bepushed onto the ValueStack in additionto the Action itself,allowing a FormBeantype approach like Struts
    翻译:模型驱动的Action。将模型对象以及Action对象都放到ValueStack里面,允许像Struts一样的FormBean方式
    也即:一个Action要想成为模型驱动的话,就必须实现ModelDriven接
    口,而我们之前所一直继承的ActionSupport类并没有实现ModelDriven接口


    ModelDrivenAction类的执行流程是:首先调用getModel()方法得到User对象,接着根据JavaBean的原则将客户端传过来的属性,一个一个的set到User对象的属性中,将属性全部set完之后,再执行execute()方法。对于模型驱动,只要了解这些就足够了

    扩展:模型驱动的底层实现机制
    这里用到了defaultStack拦截器栈中的modelDriven拦截器
    它对应com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor类,

    其API描述如下
    public class ModelDrivenInterceptor extends AbstractInterceptor
    Watches for ModelDriven actions and adds the action`s model on to the valuestack.
    翻译:观察模型驱动的Action,并将这个Action的模型【这里指User对象】放到值栈中
    Note:The ModelDrivenInterceptor must come before the bothStaticParametersInterceptor and ParametersInterceptor if you want theparameters to be applied to the model.
    翻译:若希望将表单提交过来的参数应用到模型里面,那么ModelDrivenInterceptor拦截器就必须位于StaticParametersInterceptor和ParametersInterceptor拦截器前面。

    实际上struts-default.xml已完成这个工作了。可以在defaultStack拦截器栈中查看三者位置,所以对于采用模型驱动的方式的话,在struts.xml中只需要指定模型驱动的类就可以了,其它的都不需要我们手工修改

    3,属性驱动接收参数

    这种方式应该不算是参数封装的方式,但我们很多情况下都用属性驱动的方式接收参数,因为这种方式方便,简洁,易控制。属性驱动在Action中提供与表单字段一一对应的属性,然后一一set赋值,采用属性驱动的方式时,是由每个属性来承载表单的字段值,运转在MVC流程里面。由于这种方式比较简单,这里就不在赘述了。


    到底是用属性驱动和是模型驱动呢?

    1)统一整个系统中的Action使用的驱动模型,即要么都是用属性驱动,要么都是用模型驱动。

    2)如果你的DB中的持久层的对象与表单中的属性都是一一对应的话,那么就使用模型驱动吧,毕竟看起来代码要整洁得多。

    3)如果表单的属性不是一一对应的话,那么就应该使用属性驱动,否则,你的系统就必须提供两个Bean,一个对应表单提交的数据,另一个用与持久层。

    本文来自:曹胜欢博客专栏。转载请注明出处:http://blog.csdn.net/csh624366188 

  • 相关阅读:
    两条斜线
    Cantor表
    城市网络
    一起来数二叉树吧
    牛客网音乐研究(枚举)
    删括号
    合并回文子串
    寻找道路
    EXTJS 4.0.2 XML数据
    extjs4.0.2a gridpanel看不到横向滚动条的一种原因
  • 原文地址:https://www.cnblogs.com/dooor/p/5315045.html
Copyright © 2011-2022 走看看