http请求的参数和属性

 练习搭建和使用SSH框架的时候,遇到一个http方面很简单的问题。一个form的表单登录请求,表单为最基本的html表单内容,代码如下

在struts的action中需要获取输入的用户名和密码,最开始我采用的代码如下

但是在运行的时候,一直在user.setUserName(request.getAttribute("user_name").toString());这里报空指针异常,后来改成
user.setUserName(request.getParameter("user_name"));之后就可以正常运行了。
还是上面的SSH项目,为了了解这其中的区别,我将parameters和attributes都打印出来,结果如下
the actual type for request org.apache.struts2.dispatcher.StrutsRequestWrapper
attribute:< __cleanup_recursion_counter,1>
attribute:< struts.actionMapping,org.apache.struts2.dispatcher.mapper.ActionMapping@19a4e8e>
attribute:< struts.valueStack,com.opensymphony.xwork2.ognl.OgnlValueStack@19b7b9d>
parameter:<passwd,sdfg>
parameter:<user_name,lynn>
由此可见,表单传递请求的方式主要是通过parameters来完成。而attributes的使用就主要是框架内部使用。

虽然修改之后系统成功运行,但对于java的Http以及表单请求却产生了许多问题,借此机会做个了解。


以上是来自tomcat源代码中整理出来的Servlet系统的一部分接口、类的继承和实现关系。但由于这里使用的是HttpServletRequest,所以研究的重点要放在HttpServletRequest类上,下面是根据tomat源代码整理出来的HttpServletRequest系统的结构图。

从上图可以看出,本项目中的request.getAttribute和request.getParameter方法是继承自父接口ServletRequest的。这上面解释了tomcat所提供的http系统的大致框架结构。要理解这两个方法之间具体的差别,需要知道这两个对象的实际类型和对象实例化的点。使用
System.  out .println( "the actual type for request " +request.getClass().getName());将request对象的类型打印出来,显示的结果为“ the actual type for request org.apache.struts2.dispatcher.StrutsRequestWrapper”
为什么是request的类型是org.apache.struts2.dispatcher.StrutsRequestWrapper呢?
StrutsRequestWrapper类是来自Struts框架,由于在项目中采用了SSH框架,Struts框架对tomcat的http系统进行了扩充。StrutsRequestWrapper是继承自HttpServletRequestWrapper类, 这个类又继承自ServletRequestWrapper,并且实现了HttpServletRequest接口
public  class  HttpServletRequestWrapper  extends  ServletRequestWrapper  implements  HttpServletRequest{/*....*/},它提供一个带HttpServletRequest类型参数的构造函数。代码如下
public  HttpServletRequestWrapper(HttpServletRequest request) {
         super (request);
    }
其父类ServletRequestWrappet实现了ServletRequest接口,并且提供了一个带ServletRequest类型参数的构造函数,相关代码如下。
  private  ServletRequest  request ;

     /**
     * Creates a ServletRequest adaptor wrapping the given request object.
     *
     *  @throws  java.lang.IllegalArgumentException
     *             if the request is null
     */
     public  ServletRequestWrapper(ServletRequest request) {
         if  (request ==  null ) {
             throw  new  IllegalArgumentException( "Request cannot be null" );
        }
         this . request  = request;
    }
在StrutsRequestWrapper类中重写了getAttribute方法,没有重写getParameter方法。其父类HttpServletRequestWrapper中对这两个方法都没有进行重写。所以,本项目中request对象调用的getParameter方法是来自于ServletRequestWrapper的,代码如下
   @Override
     public  String getParameter(String name) {
         return  this  . request  .getParameter(name);
    }
结合其构造函数来看,具体其作用的还是在生成 StrutsRequestWrapper对象时传递进来的HttpServletRequest对象。

那就从Struts框架的启动配置入手,通过在web.xml中配置filter来将Struts框架引入项目。在web.xml中雨filter相关的配置代码如下。也就是说,tomcat在加载项目的时候,会以StrutsPrepareAndExecuteFilter作为入口,下面顺藤摸瓜。
< filter >
                < filter-name >  struts </  filter-name >
                < filter-class >  org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter  </ filter-class >
         </ filter >
StrutsPrepareAndExecuteFilter实现了Filter接口,每次进行请求的时候,tomcat会调用其doFilter方法。在doFilter代码如下
public  void  doFilter(ServletRequest req, ServletResponse res, FilterChain chain)  throws  IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

         try  {
             prepare .setEncodingAndLocale(request, response);
             prepare .createActionContext(request, response);
             prepare .assignDispatcherToThread();
                       if  (  excludedPatterns  !=  null  &&  prepare .isUrlExcluded(request,  excludedPatterns  )) {
                           chain.doFilter(request, response);
                     }  else  {
                           request =  prepare .wrapRequest(request);
                           ActionMapping mapping =  prepare .findActionMapping(request, response,  true );
                             if  (mapping ==  null ) {
                                    boolean  handled =  execute .executeStaticResourceRequest(request, response);
                                    if  (!handled) {
                                         chain.doFilter(request, response);
                                  }
                           }  else  {
                                    execute .executeAction(request, response, mapping);
                           }
                     }
        }  finally  {
             prepare .cleanupRequest(request);
        }
    }
其中先调用createActionContext创建了一个ActionContext对象。prePare是PrepareOpearation类型的对象,类的 createAction方法中部分代码如下
ActionContext oldContext = ActionContext.getContext();
         if  (oldContext !=  null ) {
             // detected existing context, so we are probably in a forward
            ctx =  new  ActionContext( new  HashMap<String, Object>(oldContext.getContextMap()));
        }  else  {
            ValueStack stack =  dispatcher .getContainer().getInstance(ValueStackFactory. class ).createValueStack();
            stack.getContext().putAll(  dispatcher .createContextMap(request, response,  null ,  servletContext  ));
            ctx =  new  ActionContext(stack.getContext());
        }
        request.setAttribute(  CLEANUP_RECURSION_COUNTER , counter);
        ActionContext. setContext(ctx);
         return  ctx;
也就是说,这里生成的Map<String,Object> context对象来自旧的ActionContext对象。如果旧的不存在,那就用最初的配置文件构造一个出来,也就是servletContext对象,在PrepareOperations类的构造函数中被初始化,也就是根据tomcat调用StrutsPrepareAndExecuteFilter的init方法时,传递进来的配置内容产生。
然后parepare.wrapRequest方法实现对reques对象的包装,转成StrutsRequestWrapper对象。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值