spring mvc参数绑定大全

  spring mvc是非常好用的mvc框架,不仅因为与spring的无缝集成,还因为每个细节都被考虑得及其周到。而且spring也是代码的典范,所有的开源项目中,spring的代码是我见过的层次最为清晰,结构最为规范,注释最为全面的开源项目。

  相信用过springmvc的人都对springmvc强大的参数绑定能力印象深刻,但是用的时候总是有些心有余悸,因为功能太多太强大,导致用的时候不清楚这样用可不可以,也不知道还有没有更强大的功能没被发掘。

  这篇文章主要是讲spring的参数绑定,各种annotation,用法及其原理。

  大家知道,处理请求的过程是在DispatchServlet中的doDispatch方法中,通过HandlerAdapter的handle方法进行的。

  spring默认的组件全都配置在DispatcherServlet.properties中,而关于我们Controller使用annotation注解的HandlerAdapter目前(3.2)是配置了AnnotationMethodHandlerAdapter,它的handle方法会调用invokeHandlerMethod方法,最终会调到HandlerMethodInvoker的invokeHandlerMethod。

  这个方法比较重要,主要做了这样几件事

  1. 将session中的参数放到Model里去,这样可以方便的用EL表达式暴露session中的变量。从这里我们可以得知spring的el表达式里天然可以使用session中的参数

  2. 处理有ModelAttribute这个annotation的方法,并将其结果放到对应的Model中去。从这里我们可以得知ModelAttribute的作用是帮助Model初始化参数,举个非常简单的例子,如果有一个计算item总数是每个页面都需要显示的,通常的做法是在每一个返回的页面之前都将该计算结果加入Model,这样会出现很多重复,如下。

        @RequestMapping(value = "/doSomething1")
        public String doSomething1(Model model,
			HttpServletRequest request) {
		model.addAttribute("maxCount", service.maxCount());
                return "result1";
	}
	@RequestMapping(value = "/doSomething2")
	public String doSomething2(Model model,
			HttpServletRequest request) {
		model.addAttribute("maxCount", service.maxCount());
                return "result2";
        }
    实际上更好的用法是,因为在进每个RequestMapping前,所有的ModelAttribute都会被自动扫描并将结果添加到Model里去,所以实际上可以省略每个方法里的设置参数。

	
        @ModelAttribute("maxCount")
        public int maxCount(){
		return service.maxCount();
	}
        @RequestMapping(value = "/doSomething1")
        public String doSomething1(Model model,
			HttpServletRequest request) {
		return "result1";
	}
	@RequestMapping(value = "/doSomething2")
	public String doSomething2(Model model,
			HttpServletRequest request) {
		return "result2";
	}

   3. 解析映射方法的参数。这个方法非常重要,因为所有的待解析的参数,springmvc是如何为我们做的数据绑定都在这里了。这个方法是resolveHandlerArguments,篇幅原因这里就不列出它的代码了。但是从这个方法可以发现springmvc所有对参数绑定的用法。

   下面一一介绍

   @RequestHeader:绑定一个http头,比如想要知道他的referer,可以这样写

public String test(@RequestHeader(value="Referer") String referer){
		return "";
	}
   @RequestParam:绑定一个请求参数,这个是最常见的要求了,但是通常也可以省略它,这个参数可以是从url来,也可以从post中来,比如

public String test(@RequestParam(value="id") String id){
		return "";
	}

   @RequestBody:绑定一个Post请求的content,这个方法通常可以用来做一些自定义的活动,比如post请求中放的是自定义格式的数据,或者是json数据要自己手动解析,比如

public String test(@RequestBody String body){
		return "";
	}
    @CookieValue:绑定一个请求中的cookie,这个也是让我们省不少事的方法

public String test(@CookieValue(value="loginId") String loginId){
		return "";
	}

    @PathVariable:绑定一个restful风格的变量

        @RequestMapping(value = "/test/{userName}")
	public String test(@PathVariable(value="userName") String userName){
		return "";
	}
    @ModelAttribute:将入参直接放到Model中

public String test(@ModelAttribute(value="userName") String userName){
		return "";
	}
     @Value:spring还支持将配置的值作为入参传入,方法就是使用@Value注解

public String test(@Value(value="${mysql.connectionUrl}") String url){
		return "";
	}
     @Valid*:有意思的是,只要注解是Valid开头的,spring都会试图帮你去做验证,这意味着约定大于配置

if (paramAnn.annotationType().getSimpleName().startsWith("Valid"))

     spring最牛的能力是你根本不需要写注释,它会根据你的需要去自动注入常见的参数。比如HttpServletRequest, HttpServletResponse, HttpSession, Principal, Locale, InputStream, Reader, OutputStream, Writer,你只要将这些写到方法的参数中,spring便会自动将这些参数在运行时自动当做参数调用,这是非常方便的地方,要注意的是,除了上面这些已知的参数,暂时不支持其他的参数。关于这部分代码,在ServletHandlerMethodInvoker的resolveStandardArgument中。

     而spring能够注入一些支持的参数,比如常用的Model(用来当做EL表达式的一个map),SessionStatus,HttpEntity(将http的head和body封装到一起)

     另外,对于未写注解@RequestParam简单类型,会自动从request中去获取并注入,这些简单类型包括原生类型及包装类,枚举,CharSequence的所有子类(所以包括常见的字符串,StringBuffer等),所有Number类及其子类(包括BigDecimal,BigInteger,Atomic*等常见类),另外,所有Date,URL,URI,Locale,Class都在简单类型之列,不得不感慨spring的强大。简单类型的定义在BeanUtils.isSimpleValueType

     那么,对于自定义的POJO类型,spring又是怎么处理的呢?在resolveModelAttribute中也给出了他的做法,首先去Model里找,找不到就去Session中找,还是找不到就自己新建一个。新建完之后一个主要动作是去调用被注解为@InitBinder的所有方法,它的作用是规定一些自定义的映射器,比如如下的例子,就是将multpart对象封装成byte数组。

@InitBinder
	protected void initBinder(WebDataBinder binder) throws ServletException {
		binder.registerCustomEditor(byte[].class,
				new ByteArrayMultipartFileEditor());
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		dateFormat.setLenient(false);
		binder.registerCustomEditor(Date.class, new CustomDateEditor(
				dateFormat, false));
	}


    当InitBinder调用完之后,由doBind这个方法来完成POJO对象中参数的注入,这个地方主要的做法就是将request中的参数拿出来注入到POJO对象中,从代码实现来看,不支持POJO嵌套的注入,所以使用上要注意。

  4. 真正的去调用该方法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值