Spring MVC 4.2.4.RELEASE 中文文档
  • Introduction
  • Part I: 目录与翻译注记(Table of contents and Notes)
    • 目录
    • 翻译注记
  • Part II: 文档内容(Documentation contents)
    • Spring Web MVC框架简介
      • Spring Web MVC的新特性
      • 允许其他MVC实现
    • DispatcherServlet
      • WebApplicationContext中特殊的Bean类型
      • 默认的DispatcherServlet配置
      • DispatcherServlet的处理流程
    • 控制器的实现
      • 使用@Controller注解定义一个控制器
      • 使用@RequestMapping注解映射请求路径
      • 定义@RequestMapping注解的处理方法
      • 异步请求的处理
      • 对控制器测试
    • 处理器映射
      • 使用HandlerInterceptor拦截请求
    • 视图解析
      • 使用ViewResolver接口解析视图
      • 视图链
      • 视图重定向
      • 内容协商解析器ContentNegotiatingViewResolver
    • 使用闪存属性FlashAttributes
    • URI构造
      • 为控制器和方法指定URI
      • 在视图中为控制器和方法指定URI
    • 地区信息
      • 获取时区信息
      • Accept请求头解析器AcceptHeaderLocaleResolver
      • Cookie解析器CookieLocaleResolver
      • Session解析器SessionLocaleResolver
      • 地区更改拦截器LocaleChangeInterceptor
    • 主题 themes
      • 关于主题:概览
      • 定义主题
      • 主题解析器
    • Spring的multipart(文件上传)支持
      • 概述
      • 使用MultipartResolver与Commons FileUpload传输文件
      • Servlet 3.0下的MultipartResolver
      • 处理表单中的文件上传
      • 处理客户端发起的文件上传请求
    • 异常处理
      • 处理器异常解析器HandlerExceptionHandler
      • @ExceptionHandler注解
      • 处理一般的Spring MVC异常
      • 使用@ResponseStatus注解业务异常
      • Servlet默认容器错误页面的定制化
    • Web安全
    • "约定优于配置"的支持
      • 控制器类名-处理器映射ControllerClassNameHandlerMapping
      • 模型ModelMap(ModelAndView)
      • 视图-请求与视图名的映射
    • HTTP缓存支持
      • HTTP请求头Cache-Control
      • 对静态资源的HTTP缓存支持
      • 在控制器中设置Cache-Control、ETag和Last-Modified响应头
      • 弱ETag
    • 基于代码的Servlet容器初始化
    • 配置Spring MVC
      • 启用MVC Java编程配置或MVC命名空间
      • 默认配置的定制化
      • 转换与格式化
      • 验证
      • 拦截器
      • 内容协商
      • 视图控制器
      • 视图解析器
      • 资源的服务
      • 回到默认的Servlet来进行资源服务
      • 路径匹配
      • 消息转换器
      • 使用MVC Java编程进行高级定制
      • 使用MVC命名空间进行高级定制
Powered by GitBook
On this page
  • 支持的方法参数类型
  • 支持的方法返回类型
  • 使用@RequestParam将请求参数绑定至方法参数
  • 使用@RequestBody注解映射请求体
  • 使用@ResponseBody注解映射响应体
  • 使用@RestController注解创建REST控制器
  • 使用HTTP实体HttpEntity
  • 对方法使用@ModelAttribute注解
  • 在方法参数上使用@ModelAttribute注解
  • 在请求之间使用@SessionAttributes注解,使用HTTP会话保存模型数据
  • 使用"application/x-www-form-urlencoded"数据
  • 使用@CookieValue注解映射cookie值
  • 使用@RequestHeader注解映射请求头属性
  • 方法参数与类型转换
  • 定制WebDataBinder的初始化
  • 数据绑定的定制:使用@InitBinder
  • 配置定制的WebBindingInitializer
  • 使用@ControllerAdvice辅助控制器
  • Jackson Serialization View Support
  • Jackson JSONP Support

Was this helpful?

  1. Part II: 文档内容(Documentation contents)
  2. 控制器的实现

定义@RequestMapping注解的处理方法

Previous使用@RequestMapping注解映射请求路径Next异步请求的处理

Last updated 5 years ago

Was this helpful?

使用@RequestMapping注解的处理方法可以拥有非常灵活的方法签名,它支持的方法参数及返回值类型将在接下来的小节讲述。大多数参数都可以任意的次序出现,除了唯一的一个例外:BindingResult参数。这在下节也会详细描述。

Spring 3.1中新增了一些类,用以增强注解了@RequestMapping的处理方法,分别是RequestMappingHandlerMapping类和RequestMappingHandlerAdapter类。我们鼓励使用这组新的类,如果要使用Spring 3.1及以后版本的新特性,这组类甚至是必须使用的。这些增强类在MVC的命名空间配置和MVC的Java编程方式配置中都是默认开启的,如果不是使用这两种方法,那么就需要显式地配置。

支持的方法参数类型

下面列出所有支持的方法参数类型:

  • 请求或响应对象(Servlet API)。可以是任何具体的请求或响应类型的对象,比如,ServletRequest或HttpServletRequest对象等。

  • HttpSession类型的会话对象(Servlet API)。使用该类型的参数将要求这样一个session的存在,因此这样的参数永不为null。

存取session可能不是线程安全的,特别是在一个Servlet的运行环境中。如果应用可能有多个请求同时并发存取一个session场景,请考虑将RequestMappingHandlerAdapter类中的"synchronizeOnSession"标志设置为"true"。

  • org.springframework.web.context.request.WebRequest或org.springframework.web.context.request.NativeWebRequest。允许存取一般的请求参数和请求/会话范围的属性(attribute),同时无需绑定使用Servlet/Portlet的API

  • 当前请求的地区信息java.util.Locale,由已配置的最相关的地区解析器解析得到。在MVC的环境下,就是应用中配置的LocaleResolver或LocaleContextResolver

  • 与当前请求绑定的时区信息java.util.TimeZone(java 6以上的版本)/java.time.ZoneId(java 8),由LocaleContextResolver解析得到

  • 用于存取请求正文的java.io.InputStream或java.io.Reader。该对象与通过Servlet API拿到的输入流/Reader是一样的

  • 用于生成响应正文的java.io.OutputStream或java.io.Writer。该对象与通过Servlet API拿到的输出流/Writer是一样的

  • org.springframework.http.HttpMethod。可以拿到HTTP请求方法

  • 包装了当前被认证用户信息的java.security.Principal

  • 带@PathVariable注解的方法参数,其存放了URI模板变量中的值。详见

  • 带@MatrixVariable注解的方法参数,其存放了URI路径段中的键值对。详见

  • 带@RequestParam注解的方法参数,其存放了Servlet请求中所指定的参数。参数的值会被转换成方法参数所声明的类型。详见

  • 带@RequestHeader注解的方法参数,其存放了Servlet请求中所指定的HTTP请求头的值。参数的值会被转换成方法参数所声明的类型。详见.

  • 带@RequestBody注解的参数,提供了对HTTP请求体的存取。参数的值通过HttpMessageConverter被转换成方法参数所声明的类型。详见

  • 带@RequestPart注解的参数,提供了对一个"multipart/form-data请求块(request part)内容的存取。更多的信息请参考和[21.10 “Spring对多部分文件上传的支持”一节]( "21.10 Spring's multipart (file upload) support")

  • HttpEntity<?>类型的参数,其提供了对HTTP请求头和请求内容的存取。请求流是通过HttpMessageConverter被转换成entity对象的。详见

  • java.util.Map/org.springframework.io.Model/org.springframework.ui.ModelMap类型的参数,用以增强默认暴露给视图层的模型(model)的功能

  • org.springframework.web.servlet.mvc.support.RedirectAttributes类型的参数,用以指定重定向下要使用到的属性集以及添加flash属性(暂存在服务端的属性,它们会在下次重定向请求的范围中有效)。详见

  • 命令或表单对象,它们用于将请求参数直接绑定到bean字段(可能是通过setter方法)。你可以通过@InitBinder注解和/或HanderAdapter的配置来定制这个过程的类型转换。具体请参考RequestMappingHandlerAdapter类webBindingInitializer属性的文档。这样的命令对象,以及其上的验证结果,默认会被添加到模型model中,键名默认是该命令对象类的类名——比如,some.package.OrderAddress类型的命令对象就使用属性名orderAddress类获取。ModelAttribute注解可以应用在方法参数上,用以指定该模型所用的属性名

  • org.springframework.validation.Errors / org.springframework.validation.BindingResult验证结果对象,用于存储前面的命令或表单对象的验证结果(紧接其前的第一个方法参数)。

  • org.springframework.web.bind.support.SessionStatus对象,用以标记当前的表单处理已结束。这将触发一些清理操作:@SessionAttributes在类级别注解的属性将被移除

  • org.springframework.web.util.UriComponentsBuilder构造器对象,用于构造当前请求URL相关的信息,比如主机名、端口号、资源类型(scheme)、上下文路径、servlet映射中的相对部分(literal part)等

在参数列表中,Errors或BindingResult参数必须紧跟在其所绑定的验证对象后面。这是因为,在参数列表中允许有多于一个的模型对象,Spring会为它们创建不同的BindingResult实例。因此,下面这样的代码是不能工作的:

BindingResult与@ModelAttribute错误的参数次序

@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, Model model, BindingResult result) { ... }

上例中,因为在模型对象Pet和验证结果对象BindingResult中间还插了一个Model参数,这是不行的。要达到预期的效果,必须调整一下参数的次序:

@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, Model model) { ... }

对于一些带有required属性的注解(比如@RequestParam、@RequestHeader等),JDK 1.8的java.util.Optional可以作为被它们注解的方法参数。在这种情况下,使用java.util.Optional与required=false的作用是相同的。

支持的方法返回类型

以下是handler方法允许的所有返回类型:

  • ModelAndView对象,其中model隐含填充了命令对象,以及注解了@ModelAttribute字段的存取器被调用所返回的值。

  • Model对象,其中视图名称默认由RequestToViewNameTranslator决定,model隐含填充了命令对象以及注解了@ModelAttribute字段的存取器被调用所返回的值

  • Map对象,用于暴露model,其中视图名称默认由RequestToViewNameTranslator决定,model隐含填充了命令对象以及注解了@ModelAttribute字段的存取器被调用所返回的值

  • View对象。其中model隐含填充了命令对象,以及注解了@ModelAttribute字段的存取器被调用所返回的值。handler方法也可以增加一个Model类型的方法参数来增强model

  • String对象,其值会被解析成一个逻辑视图名。其中,model将默认填充了命令对象以及注解了@ModelAttribute字段的存取器被调用所返回的值。handler方法也可以增加一个Model类型的方法参数来增强model

  • void。如果处理器方法中已经对response响应数据进行了处理(比如在方法参数中定义一个ServletResponse或HttpServletResponse类型的参数并直接向其响应体中写东西),那么方法可以返回void。handler方法也可以增加一个Model类型的方法参数来增强model

  • HttpHeaders对象,返回一个不含响应体的response

  • Callable<?>对象。当应用希望异步地返回方法值时使用,这个过程由Spring MVC自身的线程来管理

  • DeferredResult<?>对象。当应用希望方法的返回值交由线程自身决定时使用

  • ListenableFuture<?>对象。当应用希望方法的返回值交由线程自身决定时使用

  • ResponseBodyEmitter对象,可用它异步地向响应体中同时写多个对象,also supported as the body within a ResponseEntity

  • SseEmitter对象,可用它异步地向响应体中写服务器端事件(Server-Sent Events),also supported as the body within a ResponseEntity

  • StreamingResponseBody对象,可用它异步地向响应对象的输出流中写东西。also supported as the body within a ResponseEntity

  • 其他任何返回类型,都会被处理成model的一个属性并返回给视图,该属性的名称为方法级的@ModelAttribute所注解的字段名(或者以返回类型的类名作为默认的属性名)。model隐含填充了命令对象以及注解了@ModelAttribute字段的存取器被调用所返回的值

使用@RequestParam将请求参数绑定至方法参数

你可以使用@RequestParam注解将请求参数绑定到你控制器的方法参数上。

下面这段代码展示了它的用法:

@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {
    // ...
    @RequestMapping(method = RequestMapping.GET)
    public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }

    // ,..
}

若参数使用了该注解,则该参数默认是必须提供的,但你也可以把该参数标注为非必须的:只需要将@RequestParam注解的required属性设置为false即可(比如,@RequestParam(path="id", required=false))。

若@RequestParam注解的参数类型是Map<String, String>或者MultiValueMap<String, String>,则该Map中会自动填充所有的请求参数。

使用@RequestBody注解映射请求体

方法参数中的@RequestBody注解暗示了方法参数应该被绑定了HTTP请求体的值。举个例子:

@RequestMapping(path = "/something", method = RequestMethod.PUT)
public void handle(@RequestBody String body, Writer writer) throws IOException {
    writer.write(body);
}

请求体到方法参数的转换是由HttpMessageConverter完成的。HttpMessageConverter负责将HTTP请求信息转换成对象,以及将对象转换回一个HTTP响应体。对于@RequestBody注解,RequestMappingHandlerAdapter提供了以下几种默认的HttpMessageConverter支持:

  • ByteArrayHttpMessageConverter用以转换字节数组

  • StringHttpMessageConverter用以转换字符串

  • FormHttpMessageConverter用以将表格数据转换成MultiValueMap<String, String>或从MultiValueMap<String, String>中转换出表格数据

  • SourceHttpMessageConverter用于javax.xml.transform.Source类的互相转换

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <util:list id="beanList">
            <ref bean="stringHttpMessageConverter"/>
            <ref bean="marshallingHttpMessageConverter"/>
        </util:list>
    </property
</bean>

<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/>

<bean id="marshallingHttpMessageConverter"
        class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
    <property name="marshaller" ref="castorMarshaller"/>
    <property name="unmarshaller" ref="castorMarshaller"/>
</bean>

<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>

注解了@RequestBody的方法参数还可以被@Valid注解,这样框架会使用已配置的Validator实例来对该参数进行验证。若你的应用是使用MVC命令空间或MVC Java编程的方式配置的,框架会假设在classpath路径下存在一个符合JSR-303规范的验证器,并自动将其作为默认配置。

与@ModelAttribute注解的参数一样,Errors也可以被传入为方法参数,用于检查错误。如果没有声明这样一个参数,那么程序会抛出一个MethodArgumentNotValidException异常。该异常默认由DefaultHandlerExceptionResolver处理,处理程序会返回一个400错误给客户端。

使用@ResponseBody注解映射响应体

@ResponseBody注解与@RequestBody注解类似。@ResponseBody注解可被应用于方法上,标志该方法的返回值(更正,原文是return type,看起来应该是返回值)应该被直接写回到HTTP响应体中去(而不会被被放置到Model中或被解释为一个视图名)。举个例子:

@RequestMapping(path = "/something", method = RequestMethod.PUT)
@ResponseBody
public String helloWorld() {
    return "Hello World"
}

上面的代码结果是文本Hello World将被写入HTTP的响应流中。

使用@RestController注解创建REST控制器

当今让控制器实现一个REST API是非常常见的,这种场景下控制器只需要提供JSON、XML或其他自定义的媒体类型内容即可。你不需要在每个@RequestMapping方法上都增加一个@ResponseBody注解,更简明的做法是,给你的控制器加上一个@RestController的注解。

使用HTTP实体HttpEntity

HttpEntity与@RequestBody和@ResponseBody很相似。除了能获得请求体和响应体中的内容之外,HttpEntity(以及专门负责处理响应的ResponseEntity子类)还可以存取请求头和响应头,像下面这样:

@RequestMapping("/something")
public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException {
    String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader");
    byte[] requestBody = requestEntity.getBody();

    // do something with request header and body

    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.set("MyResponseHeader", "MyValue");
    return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}

上面这段示例代码先是获取了MyRequestHeader请求头的值,然后读取请求体的主体内容。读完以后往影响头中添加了一个自己的响应头MyResponseHeader,然后向响应流中写了字符串Hello World,最后把响应状态码设置为201(创建成功)。

对方法使用@ModelAttribute注解

@ModelAttribute注解可被应用在方法或方法参数上。本节将介绍其被注解于方法上时的用法,下节会介绍其被用于注解方法参数的用法。

注解在方法上的@ModelAttribute说明了方法的作用是用于添加一个或多个属性到model上。这样的方法能接受与@RequestMapping注解相同的参数类型,只不过不能直接被映射到具体的请求上。在同一个控制器中,注解了@ModelAttribute的方法实际上会在@RequestMapping方法之前被调用。以下是几个例子:

// Add one attribute
// The return value of the method is added to the model under the name "account"
// You can customize the name via @ModelAttribute("myAccount")

@ModelAttribute
public Account addAccount(@RequestParam String number) {
    return accountManager.findAccount(number);
}

// Add multiple attributes

@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
    model.addAttribute(accountManager.findAccount(number));
    // add more ...
}

@ModelAttribute方法通常被用来填充一些公共需要的属性或数据,比如一个下拉列表所预设的几种状态,或者宠物的几种类型,或者去取得一个HTML表单渲染所需要的命令对象,比如Account等。

留意@ModelAttribute方法的两种风格。在第一种写法中,方法通过返回值的方式默认地将添加一个属性;在第二种写法中,方法接收一个Model对象,然后可以向其中添加任意数量的属性。你可以在根据需要,在两种风格中选择合适的一种。

一个控制器可以拥有数量不限的@ModelAttribute方法。同个控制器内的所有这些方法,都会在@RequestMapping方法之前被调用。

属性名没有被显式指定的时候又当如何呢?在这种情况下,框架将根据属性的类型给予一个默认名称。举个例子,若方法返回一个Account类型的对象,则默认的属性名为"account"。你可以通过设置@ModelAttribute注解的值来改变默认值。当向Model中直接添加属性时,请使用合适的重载方法addAttribute(..)-即,带或不带属性名的方法。

在方法参数上使用@ModelAttribute注解

如上一小节所解释,@ModelAttribute注解既可以被用在方法上,也可以被用在方法参数上。这一小节将介绍它注解在方法参数上时的用法。

注解在方法参数上的@ModelAttribute说明了该方法参数的值将由model中取得。如果model中找不到,那么该参数会先被实例化,然后被添加到model中。在model中存在以后,请求中所有名称匹配的参数都会填充到该参数中。这在Spring MVC中被称为数据绑定,一个非常有用的特性,节约了你每次都需要手动从表格数据中转换这些字段数据的时间。

@RequestMapping(path = "/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Pet pet) { }

以上面的代码为例,这个Pet类型的实例可能来自哪里呢?有几种可能:

  • 它可能因为在同个控制器中使用了@ModelAttribute方法已经存在于model中——正如上一小节所叙述的

  • 它可能是由URI模板变量和类型转换中取得的(下面会详细讲解)

  • 它可能是调用了自身的默认构造器被实例化出来的

@ModelAttribute方法常用于从数据库中取一个属性值,该值可能通过@SessionAttributes注解在请求中间传递。在一些情况下,使用URI模板变量和类型转换的方式来取得一个属性是更方便的方式。这里有个例子:

@RequestMapping(path = "/accounts/{account}", method = RequestMethod.PUT)
public String save(@ModelAttribute("account") Account account) {

}

上面这个例子中,model属性的名称("account")与URI模板变量的名称相匹配。如果你配置了一个可以将String类型的账户值转换成Account类型实例的转换器Converter<String, Account>,那么上面这段代码就可以工作的很好,而不需要再额外写一个@ModelAttribute方法。

进行了数据绑定后,则可能会出现一些错误,比如没有提供必须的字段、类型转换过程的错误等。若想检查这些错误,可以在注解了@ModelAttribute的参数紧跟着声明一个BindingResult参数:

@RequestMapping(path = "/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
    if (result.hasErrors()) {
        return "petForm";
    }

    // ...

}

拿到BindingResult参数后,你可以检查是否有错误。有时你可以通过Spring的<errors>表单标签来在同一个表单上显示错误信息。

BindingResult被用于记录数据绑定过程的错误,因此除了数据绑定外,你还可以把该对象传给自己定制的验证器来调用验证。这使得数据绑定过程和验证过程出现的错误可以被搜集到一处,然后一并返回给用户:

@RequestMapping(path = "/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {

    new PetValidator().validate(pet, result);
    if (result.hasErrors()) {
        return "petForm";
    }

    // ...

}

又或者,你可以通过添加一个JSR-303规范的@Valid注解,这样验证器会自动被调用。

@RequestMapping(path = "/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {

    if (result.hasErrors()) {
        return "petForm";
    }

    // ...

}

在请求之间使用@SessionAttributes注解,使用HTTP会话保存模型数据

类型级别的@SessionAttributes注解声明了某个特定处理器所使用的会话属性。通常它会列出该类型希望存储到session或converstaion中的model属性名或model的类型名,一般是用于在请求之间保存一些表单数据的bean。

以下的代码段演示了该注解的用法,它指定了模型属性的名称

@Controller
@RequestMapping("/editPet.do")
@SessionAttributes("pet")
public class EditPetForm {
    // ...
}

使用"application/x-www-form-urlencoded"数据

上一小节讲述了如何使用@ModelAttribute支持客户端浏览器的多次表单提交请求。对于不是使用的浏览器的客户端,我们也推荐使用这个注解来处理请求。但当请求是一个HTTP PUT方法的请求时,有一个事情需要注意。浏览器可以通过HTTP的GET方法或POST方法来提交表单数据,非浏览器的客户端还可以通过HTTP的PUT方法来提交表单。这样设计是个挑战,因为在Servlet规范中明确规定,ServletRequest.getParameter*()系列的方法只能支持通过HTTP POST方法的方式提交表单,而不支持HTTP PUT的方式。

为了支持HTTP的PUT类型和PATCH类型的请求,Spring的spring-web模块提供了一个过滤器HttpPutFormContentFilter。你可以在web.xml文件中配置它:

    <filter>
        <filter-name>httpPutFormFilter</filter-name>
        <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>httpPutFormFilter</filter-name>
        <servlet-name>dispatcherServlet</servlet-name>
    </filter-mapping>

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

上面的过滤器将会拦截内容类型(content type)为application/x-www-form-urlencoded、HTTP方法为PUT或PATCH类型的请求,然后从请求体中读取表单数据,把它们包装在ServletRequest中。这是为了使表单数据能够通过ServletRequest.getParameter*()系列的方法来拿到。

因为HttpPutFormContentFilter会消费请求体的内容,因此,它不应该用于处理那些依赖于其他application/x-www-form-urlencoded转换器的PUT和PATCH请求,这包括了@RequestBodyMultiValueMap<String, String>和HttpEntity<MultiValueMap<String, String>>。

使用@CookieValue注解映射cookie值

@CookieValue注解能将一个方法参数与一个HTTP cookie的值进行绑定。

看一个这样的场景:以下的这个cookie存储在一个HTTP请求中:

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

下面的代码演示了拿到JSESSIONID这个cookie值的方法:

@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) {
    //...
}

这个注解可以注解到处理器方法上,在Servlet环境和Portlet环境都能使用。

使用@RequestHeader注解映射请求头属性

@RequestHeader注解能将一个方法参数与一个请求头属性进行绑定。

以下是一个请求头的例子:

    Host                    localhost:8080
    Accept                  text/html,application/xhtml+xml,application/xml;q=0.9
    Accept-Language         fr,en-gb;q=0.7,en;q=0.3
    Accept-Encoding         gzip,deflate
    Accept-Charset          ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Keep-Alive              300

以下的代码片段展示了如何取得Accept-Encoding请求头和Keep-Alive请求头的值:

@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,
        @RequestHeader("Keep-Alive") long keepAlive) {
    //...
}

如果@RequestHeader注解应用在Map<String, String>、MultiValueMap<String, String>或HttpHeaders类型的参数上,那么所有的请求头属性值都会被填充到map中。

Spring内置支持将一个逗号分隔的字符串(或其他类型转换系统所能识别的类型)转换成一个String类型的列表/集合。举个例子,一个注解了@RequestHeader("Accept")的方法参数可以是一个String类型,但也可以是String[]或List<String>类型的。

这个注解可以注解到处理器方法上,在Servlet环境和Portlet环境都能使用。

方法参数与类型转换

定制WebDataBinder的初始化

数据绑定的定制:使用@InitBinder

使用@InitBinder注解控制器的方法,你可以直接在你的控制器类中定制应用的数据绑定。@InitBinder用来标记一些方法,这些方法会初始化一个WebDataBinder并用以为处理器方法填充命令对象和表单对象的参数。

除了命令/表单对象以及相应的验证结果对象,这样的“绑定器初始化”方法能够接收@RequestMapping所支持的所有参数类型。“绑定器初始化”方法不能有返回值,因此,一般将它们声明为void返回类型。特别地,当WebDataBinder与WebRequest或java.util.Locale一起作为方法参数时,你可以在代码中注册上下文相关的编辑器。

下面的代码示例演示了如何使用@InitBinder来配置一个CustomerDateEditor,后者会对所有java.util.Date类型的表单字段进行操作:

@Controller
public class MyFormController {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }

    // ...
}

或者,你可以使用Spring 4.2提供的addCustomFormatter来指定Formatter的实现,而非通过PropertyEditor实例。这在你拥有一个需要Formatter的setup方法,并且该方法位于一个共享的FormattingConversionService中时非常有用。这样对于控制器级别的绑定规则的定制,代码更容易被复用。

@Controller
public class MyFormController {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }

    // ...
}

配置定制的WebBindingInitializer

为了externalize数据绑定的初始化过程,你可以为WebBindingInitializer接口提供一个自己的实现,在其中你可以为AnnotationMethodHandlerAdapter提供一个默认的配置bean,以此来覆写默认的配置。

以下的代码来自PetClinic的应用,它展示了为WebBindingInitializer接口提供一个自定义实现:org.springframework.samples.petclinic.web.ClinicBindingInitializer完整的配置过程。后者中配置了PetClinic应用中许多控制器所需要的属性编辑器PropertyEditors。

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="cacheSeconds" value="0"/>
    <property name="webBindingInitializer">
        <bean class="org.springframework.samples.petclinic.web.ClinicBindingInitializer"/>
    </property>
</bean>

使用@ControllerAdvice辅助控制器

@ControllerAdvice是一个组件注解,它使得其实现类能够被classpath扫描自动发现。若应用是通过MVC命令空间或MVC Java编程方式配置,那么该特性默认是自动开启的。

注解@ControllerAdvice的类可以拥有@ExceptionHandler、@InitBinder或@ModelAttribute注解的方法,并且这些方法会被应用至控制器类层次??的所有@RequestMapping方法上。

你也可以通过@ControllerAdvice的属性来指定其只对一个子集的控制器生效:

// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class AnnotationAdvice {}

// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class BasePackageAdvice {}

// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class AssignableTypesAdvice {}

下面两节,还看不太懂,待译。

Jackson Serialization View Support

To use it with an @ResponseBody controller method or controller methods that return ResponseEntity, simply add the @JsonView annotation with a class argument specifying the view class or interface to be used:

_@RestController_
public class UserController {

    _@RequestMapping(path = "/user", method = RequestMethod.GET)_
    _@JsonView(User.WithoutPasswordView.class)_
    public User getUser() {
        return new User("eric", "7!jd#h23");
    }
}

public class User {

    public interface WithoutPasswordView {};
    public interface WithPasswordView extends WithoutPasswordView {};

    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    _@JsonView(WithoutPasswordView.class)_
    public String getUsername() {
        return this.username;
    }

    _@JsonView(WithPasswordView.class)_
    public String getPassword() {
        return this.password;
    }
}

Note

Note that despite @JsonView allowing for more than one class to be specified, the use on a controller method is only supported with exactly one class argument. Consider the use of a composite interface if you need to enable multiple views.

For controllers relying on view resolution, simply add the serialization view class to the model:

_@Controller_
public class UserController extends AbstractController {

    _@RequestMapping(path = "/user", method = RequestMethod.GET)_
    public String getUser(Model model) {
        model.addAttribute("user", new User("eric", "7!jd#h23"));
        model.addAttribute(JsonView.class.getName(), User.WithoutPasswordView.class);
        return "userView";
    }
}

Jackson JSONP Support

_@ControllerAdvice_
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

    public JsonpAdvice() {
        super("callback");
    }
}

For controllers relying on view resolution, JSONP is automatically enabled when the request has a query parameter named jsonp or callback. Those names can be customized through jsonpParameterNames property.

如果处理器方法注解了ResponseBody,那么返回类型将被写到HTTP的响应体中,而返回值会被HttpMessageConverters转换成所方法声明的参数类型。详见

HttpEntity<?>或ResponseEntity<?>对象,用于提供对Servlet HTTP响应头和响应内容的存取。对象体会被HttpMessageConverters转换成响应流。详见

若所注解的方法参数类型不是String,则类型转换会自动地发生。详见

关于这些转换器的更多信息,请参考。另外,如果使用的是MVC命名空间或Java编程的配置方式,会有更多默认注册的消息转换器。更多信息,請參考。

若你更倾向于阅读和编写XML文件,那么你需要配置一个MarshallingHttpMessageConverter并为其提供org.springframework.oxm包下的一个Marshaller和Unmarshaller实现。下面的示例就为你展示如何直接在配置文件中配置它。但如果你的应用是使用MVC命令空间或MVC Java编程的方式进行配置的,则请参考。

关于如何通过MVC命令空间或MVC Java编程的方式配置消息转换器和验证器,也请参考。

与@RequestBody注解类似,Spring使用了一个HttpMessageConverter来将返回对象转换到响应体中。关于这些转换器的更多信息,请参考。

是一个原生内置的注解,它结合了@ResponseBody与@Controller注解的功能。不仅如此,它也让你的控制器更表义,而且在框架未来的发布版本中,它也可能承载更多的意义。

与普通的@Controller无异,@RestController也可以与@ControllerAdvicebean配合使用。更多细节,请见。

与@RequestBody与@ResponseBody注解一样,Spring使用了HttpMessageConverter来对请求流和响应流进行转换。关于这些转换器的更多信息,请阅读上一小节以及。

@ModelAttribute方法也可以定义在@ControllerAdvice注解的类中,并且这些@ModelAttribute可以同时对许多控制器生效。具体的信息可以参考。

@ModelAttribute注解也可以被用在@RequestMapping方法上。这种情况下,@RequestMapping方法的返回值将会被解释为model的一个属性,而非一个视图名。此时视图名将以视图命名约定来方式来决议,与返回值为void的方法所采用的处理方法类似——请见。

它可能因为@SessionAttributes注解的使用已经存在于model中——详见

下一步就是数据的绑定。WebDataBinder类能将请求参数——包括字符串的查询参数和表单字段等——通过名称匹配到model的属性上。成功匹配的字段在需要的时候会进行一次类型转换(从String类型到目标字段的类型),然后被填充到model对应的属性中。数据绑定和数据验证的问题在中提到。如何在控制器层来定制数据绑定的过程,在中提及。

关于如何配置并使用验证,可以参考和。

若注解的目标方法参数不是String类型,则类型转换会自动进行。详见一节。

若注解的目标方法参数不是String类型,则类型转换会自动进行。一节。

从请求参数、路径变量、请求头属性或者cookie中抽取出来的String类型的值,可能需要被转换成其所绑定的目标方法参数或字段的类型(比如,通过@ModelAttribute将请求参数绑定到方法参数上)。如果目标类型不是String,Spring会自动进行类型转换。所有的简单类型诸如int、long、Date都有内置的支持。如果想进一步定制这个转换过程,你可以通过WebDataBinder(详见一节),或者为Formatters配置一个FormattingConversionService(详见一节)来做到。

如果想通过Spring的WebDataBinder在属性编辑器中做请求参数的绑定,你可以使用在控制器内使用@InitBinder注解的方法、在注解了@ControllerAdvice的类中使用@InitBinder注解的方法,或者提供一个定制的WebBindingInitializer。更多的细节,请参考一节。

@InitBinder方法也可以定义在@ControllerAdvice注解的类上,这样配置可以为许多控制器所共享。这提供了除使用WebBindingInitializer外的另外一种方法。更多细节请参考一节。

更多的细节,请查阅。

It can sometimes be useful to filter contextually the object that will be serialized to the HTTP response body. In order to provide such capability, Spring MVC has built-in support for rendering with .

In order to enable support for @ResponseBody and ResponseEntity methods, declare an @ControllerAdvice bean that extends AbstractJsonpResponseBodyAdvice as shown below where the constructor argument indicates the JSONP query parameter name(s):

“URI模板变量”一节
“矩阵变量”一节
“使用@RequestParam注解绑定请求参数至方法参数”一节
“使用@RequestHeader注解映射请求头属性”一节
“使用@RequestBody注解映射请求体”一节"
21.10.5 “处理客户端文件上传的请求”一节
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web.html#mvc-multipart
“HttpEntity”一节
“向重定向请求传递参数”一节
使用"@ResponseBody注解映射响应体"一节
使用HttpEntity一节
"方法参数与类型转换"一节
"HTTP信息转换器"一节
"启用MVC Java编程配置或MVC XML命令空间配置"一节
"启用MVC Java编程配置或MVC XML命令空间配置"这一节
"启用MVC Java编程配置或MVC XML命令空间配置"一节
"HTTP信息转换器"一节
@RestController
使用@ControllerAdvice辅助控制器
"HTTP信息转换器"这一节
使用@ControllerAdvice辅助控制器
视图:请求与视图名的对应
"在请求之间使用@SessionAttributes注解,使用HTTP会话保存模型数据"一节
第8章 验证,数据绑定和类型转换
这一节 "定制WebDataBinder的初始化"
第8.8小节 "Spring验证"
第8章 验证,数据绑定和类型转换
"方法参数与类型转换"
"方法参数与类型转换"
"定制WebDataBinder的初始化"
8.6节 "Spring字段格式化"
使用@ControllerAdvice辅助控制器
使用@ControllerAdvice辅助控制器
@ControllerAdvice的文档
Jackson's Serialization Views
JSONP
[Note]