6、Spring MVC 之 定义@RequestMapping处理方法

@RequestMapping处理器方法可以非常灵活的签名。支持的方法参数和返回值在以下部分中描述。大多数参数可用于任意顺序除了BindingResult这个唯一的参数例外。下一节中将会描述。

note:Spring 3.1引入了一套新的@RequestMapping方法的支持类.分别是RequestMappingHandlerMapping和RequestMappingHandlerAdapter。它们被推荐使用,甚至你在使用Spring MVC的新特性时必须使用它们。在MVC命名空间与MVC的Java配置这些新的支持类是默认启用的。如果不使用新特性必须明确的配置。

1、支持的方法参数类型

下面是是支持的方法参数:
1. Servlet API中的Request或者Response对象。选择一些特殊的request或者response类型。例如:ServletRequest或者HttpServletRequest
2. Servlet API中的Session对象:HttpSession对象。论证这种类型的执行存在相应的会话。因此,这个参数永远不会为Null
note : 在Servlet环境中使用session对象可能不会线程安全。如果多个request被允许使用同一个session可以考虑把RequestMappingHandlerAdapter的synchronizeOnSession属性设置为true。
3. org.springframework.web.context.request.WebRequest或者org.springframework.web.context.request.NativeWebRequest.如果没有依赖本地Servlet / Portlet API,允许使用通用请求参数访问request/session属性。
4. java.util.Locale.当前请求的locale。在Spring MVC中可以通过配置LocaleResolver/LocaleContextResolver,来决定使用可用的具体的语言环境解析器。
5. java.util.TimeZone (Java 6+) / java.time.ZoneId (on Java 8): 与当前请求相关联的时区,通过LocaleContextResolver来决定。
6. java.io.InputStream / java.io.Reader.访问request的内容.这个值是Servlet API暴露的原始的InputStream /Reader.
7. java.io.OutputStream / java.io.Writer.生成reponse的内容.这个值是Servlet API暴露的原始的OutputStream/Writer.
8. org.springframework.http.HttpMethod.HTTP请求的方法。
9. java.security.Principal.包含当前身份验证的用户。
10. @PathVariable.被注释的参数用于获取URI模板变量。
11. @MatrixVariable.注解的参数访问位于URI路径段名称-值对。
12. @RequestParam.注解的参数访问特定的Servlet请求参数。参数值转换为声明的方法参数类型。
13. @RequestHeader.注解的参数访问Servlet的HTTP请求中特殊的headers。参数值转换为声明的方法参数类型。
14. @RequestBody.注解的参数访问HTTP请求的body.参数值使用HttpMessageConverters转换为声明的方法参数类型。
15. @RequestPart.注解的参数获取的content中的”multipart/form-data”要求的部分。主要用于Spring MVC支持文件上传。
16. HttpEntity. 用于访问Servlet中的HTTP请求headers与content中的属性.request流将使用HttpMessageConverters被转换成entity的body.
17. java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap.装饰web视图暴露的的隐式模型.
18. org.springframework.web.servlet.mvc.support.RedirectAttributes.指定的精确的属性用于如果发生重定向并添加flash属性。(把属性临时的储存在服务端,当进行重定向的时候,可以从request里面获取它)
19. Command或者form对象来绑定请求参数到bean(通过setters)或者通过字段。通过@InitBinder注解方法或者HandlerAdapter配置,我们也可以自定义类型转换。可以参考RequestMappingHandlerAdapterwebBindingInitializer这个属性。这样的命令对象及其验证结果将会默认以model的属性暴露.使用command类的类名 – 例如.一个command对象的的类型为”some.package.OrderAddress”对应的model属性就是”orderAddress”.@ModelAttribute注释可用于自定义一个方法参数模型属性名称使用。
20. org.springframework.validation.Errors / org.springframework.validation.BindingResult.前命令之前或表单对象验证结果.(方法参数的前面)
21. org.springframework.web.bind.support.SessionStatus.状态处理用于将表单处理标记为完成.如果在处理类(Controller)上面声明@SessionAttributes这个注解,就会引用清除session属性。
22. org.springframework.web.util.UriComponentsBuilder.一个builder用于准备一个URL相对于当前请求的host,port,scheme,context path和servlet映射的文字部分。

注意:
Errors或者BindingResult必须作为Model对象的参数。Model对象是与方法绑定在一起的。Spring MVC会给写个Model创建一个单独的BindingResult的对象。下面这个例子是错误的,不会运行:

BindingResult与@ModelAttribute的顺序不正确.

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

注意
如果在PetBindingResult中有Model对象。如果你想这段逻辑工作,需要把这些参数像下面进行重新排序。

@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, Model model) { ... }
2、方法支持的返回值类型

下面的是方法支持的返回值类型:
1. A ModelAndView object,这个model隐含command对象和@ModelAttribute注释的结果.
2. A Model object,返回一个Model对象来表示模型,而视图名则利用RequestToViewNameTranslator把请求转换为视图名称。这个model隐含command对象和@ModelAttribute注释的结果.
3. A Map object,返回一个Map对象来表示模型,而视图名则利用RequestToViewNameTranslator把请求转换为视图名称。这个model隐含command对象和@ModelAttribute注释的结果.
4. A View object,这个model隐含command对象和@ModelAttribute注释的结果.处理方法通过声明的Model类型的参数来编程填充这个模型。
5. A String value,这个String值被Spring MVC解读为合理的页面name.这个model隐含command对象和@ModelAttribute注释的结果.处理方法通过声明的Model类型的参数来编程填充这个模型。
6. void,返回空void表示方法自己处理响应,一种办法是:通过声明一个ServletResponseHttpServletResponse类型的参数来直接输出响应内容,第二种是:通过RequestToViewNameTranslator把请求转化为视图名,此方法不用在处理方法中声明一个response参数,不过这种方法是能在Servlet环境下使用。
7. 如果方法使用@ResponseBody,返回值将会被写入到response的HTTP的body中。将通过HttpMessageConverters把返回值转换为声明方法参数类型.
8. An HttpEntity<?> or ResponseEntity<?> object,用来提供使用Servlet中HTTP中response中的headers和contents.通过HttpMessageConverters把entity的body转换成response流.
9. An HttpHeaders object,返回reponse没有body.
10. A Callable<?> object,当Spring MVC管理的一个应用想要通过异常的形式返回参数。
11. A DeferredResult<?>,当应用想要通过它选择的线程来产生返回值,可以使用这个参数。
12. A ListenableFuture<?>,当应用想要通过它选择的线程来产生返回值,可以使用这个参数。
13. A ResponseBodyEmitter,使用异步的方法写多个对象到response中可以返回这个类型;同样也支持作为ResponseEntity的body.
14. An SseEmitter,可以返回用于写异步服务器发送的事件给response;同样也支持作为ResponseEntity的body.
15. A StreamingResponseBody,可以返回用于异步的写入response的OutputStream;同样也支持作为ResponseEntity的body.
16. Any other return type,被认为是做为是暴露的view中的model属性。可以在方法级别使用@ModelAttribute用来指定属性名称.(默认的属性名称是返回类型的class name).这个model隐含command对象和@ModelAttribute注释的结果.

3、@RequestParam – Binding request parameters to method parameters

在Controller中可以使用@RequestParam绑定请求参数到方法的参数。
下面的代码片段展现它的用法:

@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {

    // ...

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

    // ...

}

如果方法中参数使用了这个@RequestParam,那么request中必须有对应的参数.当然你也可以通过设置@RequestParam的required属性是false来指定这个参数不是强制request需要传递这个参数。(e.g., @RequestParam(path="id", required=false))如果方法中的参数不是String类型,Spring MVC会进行自动转换。

@RequestParam注解使用到Map[String, String]或者MultiValueMap[String, String]类型时,这个map会用request中的所有参数来填充。

4、@RequestBody – Mapping the request body

方法参数中使用@RequestBody表明,这个方法中的参数是使用HTTP请求中的request中的body中的值。(当你使用传json给后面的时候,可以使用这个注解把这个json转换成被注解的对象).例如:

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

你使用一种HttpMessageConverter把HTTP的request中的body转换成方法参数。HttpMessageConverter的作用是把HTTP的request中的信息转换成一个对象和把一个对象转换成HTTP的response中的body.Spring MVC中的RequestMappingHandlerAdapter默认支持@RequestBody使用下面的HttpMessageConverters:
1. ByteArrayHttpMessageConverter converts byte arrays.
2. StringHttpMessageConverter converts strings.
3. FormHttpMessageConverter converts form data to/from a MultiValueMap[String, String>.
4. SourceHttpMessageConverter converts to/from a javax.xml.transform.Source.

如果你想使用Spring MVC中更多的信息转换,可以使用Spring MVC中的namespace与Spring MVC的Java config来进行注册。如果你打算读/写XML,你需要配置MarshallingHttpMessageConverter通过org.springframework.oxm包下面的MarshallerUnmarshaller的实现类。下面的就是使用Spring MVC的namespace的例子:

<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"/>

当你在方法参数上使用@RequsetBody时还可以使用@Valid来注解它。在这种情况下,它将会使用配置了的Validator的实例来验证这个对象。当使用Spring MVC的namespace或者使用java config的时候,JSR-303 validator会自动检测classpath中的JSR-303的实现是可用的。

与注解了@ModelAttribute的参数一样,Errors可以用来检查errors.如果这样的argument没有声明,就会报MethodArgumentNotValidException异常。这个异常会被DefaultHandlerExceptionResolver处理,将会发送400错误给客户端。

5、@ResponseBody – Mapping the response body

@ResponseBody注解的用法与@RequestBody相似,这个注解可以用在一个方法上,用来表明这个方法的返回值将会直接写到HTTP的response的body中。(不会被放在Model或者被认为是一个页面名称).例如:

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

上面的例子将会导致"Hello Word"被写入HTTP的response流中。说得通俗一点就是返回一个Json格式给client.与@RequestBody一样,Spring MVC能够使用HttpMessageConverter把方法的返回对象转换成HTTP的response的body。

6、@RestController – Creating REST Controllers

这是一个非常常见的用例用于Controller实现一个REST API,因此只为JSON、XML或自定义MediaType。你现在不需要在你的所有注解了@RequestMapping的方法上使用@ResponseBody,你只需要在你的Controller类上面使用@RestController代替使用Controller

@RestController@ResponseBody@Controller结合体的模板注解.不仅如此,它还使得controller具有更多的意义。也可能在将来的框架版本中携带额外的语义。与常规的@Controllers一样,@RestController也可以通过@ControllerAdvice来协助.

7、Using HttpEntity

HttpEntity@RequestBody@ResponseBody类似。除了有权使用request和response的body之外,HttpEntity(与response特殊实现类ResponseEntity)同样允许有权使用request与response的headers,例如:

@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);
}

在上面的例子中,获取request header中MyRequestHeader的值,并且读取读取request的bosy作为一个byte array.它添加MyResponseHeader到response中,把"Hello World"写入到response流中,并且设置response的status code为201(Created).

@RequestBody@ResponseBody一样,Spring使用HttpMessageConverter把输入数据转换到request与response的流当中.

8、@ModelAttribute on a method

注解@ModelAttribute可以应用到方法上也可以应用在方法参数上。这个章节将介绍它在方法上的用法,下个章节将会介绍它在方法参数上的用法。
@ModelAttribute用在方法上时表明这个方法目的是添加一个或者多个model属性。这种方法支持相同的参数类型作为@RequestMapping方法但不能直接映射到请求。反而在一个Controller中注解了@ModelAttribute的方法会比同一个controller中@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方法用于填充Modle通常需要的属性,例如填充下拉状态或pet类型,检索一个像帐户的命令对象为了使用它来代表一个HTML表单上的数据.在下一节中进一步讨论后一种情况。

注意@ModelAttribute方法的两种风格.首先,添加一个属性的方法隐式返回它.第二,该方法接受一个Model并为这个Modle添加任意数量的属性。你可以根据你的需求任意的选择这两种风格。

在一个Controller中可以有许多个@ModelAttribute方法。在同一个Controller中,这些方法总是比@RequestMapping方法先被调用。

@ModelAttribute方法同样也可定义在一个标注了@ControllerAdvice的类上。这些方法可以应用于多个Controller上。你可以看"@ControllerAdvice -- Advising controllers"章节获取更多信息.

@ModelAttribute注解也能够使用到@RequestMapping方法上.在这种情况下,@RequestMapping方法的返回值被解释为一个Model的属性而不是视图名称。视图名称来源于视图名称转换相反就像方法返回void. – Section 21.13.3, “The View - RequestToViewNameTranslator”. // TODO

9、@ModelAttribute – on a method argument(bathPath,casInfo)

在上一个章节中@ModelAttribute可以被应用到方法与方法参数上.这个章节将介绍它在方法参数上的用法.一个@ModelAttribute方法参数表明参数可以从Model中重新取回。如果没有从Model中取出,这个内容将会第一时间初始化并且添加到Model中.一旦出现在模型中,参数的字段应该填充所有请求参数匹配的名称。在Spring MVC中这被称为数据绑定.一个非常用有的机制,节省你不必逐个解析每个表单字段。

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

鉴于上面的例子可以Pet实例从何而来?有下面几种可能:
1. 由于@SessionAttributes的使用,它可能已经在Model中. – 看下面的章节,叫做"@SessionAttributes -- store model attributes in the HTTP session between requests."
2. 在同一个Controller中由于使用了@ModelAttribute方法,可能已经在Model中. – 在上面的章节中已经解释过了.
3. 它可能已经在URI模板变量或者type转换中获取到了.
4. 它可以已经使用它的默认constructor初始化好了。

一个@ModelAttribute方法是一种通常的方法用来从database获取属性。通过使用@SessionAttributes这可以被存储在这个请求之间.大多数情况下,它可以很方便的从URI模板变量或者type转换中获取这个属性.下面就是一个例子:

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

}

在这个例子中,model属性的名称(“account”)与URI模板变量的名称相匹配.如果你注册Converter[String, Account],那么就可以把字符串类型类型account值转换成一个Account实例,然后上面的例子将会在不需要@ModelAttribute方法前提下运行.

下一步就是数据绑定,WebDataBinder这个类匹配request参数名 – 包含query的String类型的参数以及form字段 – model属性字段名.匹配字段在必须的类型转换(String类型到目标fiedl类型)之后进行填充.Controller级别的自定义数据绑定将会在"Customizing WebDataBinder initialization."章节中细说。

当进行数据绑定的时候可能会有一些错误,比如说:缺少必须的fields或者类型转换errors。你如果需要check这个errors,可以再@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来check在渲染同个一表单的时候是否出错了.而且你可以使用Spring的<errors>form标签来展现错误.除了数据绑定你也可以通过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";
    }

    // ...

}
10、@SessionAttributes – store model attributes in the HTTP session between requests

类级别的注解@SessionAttributes声明session属性被一个特殊的handler使用.代表的用法是遍历model属性的name,或者model属性的类型.它们将会被储存在session中或者进行会话储存.主要用于后续请求的form表单需要的bean.

下面的代码片段展示了这个注解的用法,并且指明了model属性的名称:

@Controller
@RequestMapping("/editPet.do")
@SessionAttributes("pet")
public class EditPetForm {
    // ...
}
11、Working with “application/x-www-form-urlencoded” data

前一节介绍了从浏览器客户端使用@ModelAttribute支持表单提交请求.这个注释同样也推荐用来处理自非浏览器客户端的请求。然而当使用HTTP的PUT请求时,会有一个显著的不同.浏览器可以通过HTTP的GET或者POST来提交表单数据.非浏览器客户端还能够通过HTTP的PUT请求来提交表单数据.这提出了一个挑战,因为在Servlet规范要求ServletRequest.getParameter*()的一系列方法只支持HTTP的POST请求来储存表单字段,而不是HTTP的PUT请求.

为了支持HTTP的PUT请求或者PATCH请求,spring-web模块提供了filter – 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>

上面的filter会拦截HTTP中的PUT与PATCH请求通过在content的类型为"application/x-www-form-urlencoded",读取表单request的body中的表单数据.并且包装ServletRequest类,为了表单数据可以通过ServletRequest.getParameter*()系列方法来获取.
注意:因为HttpPutFormContentFilter需要消费request的body,它不应该为"application/x-www-form-urlencoded"被配置PUT或PATCH依赖其他转换器的url.其中包括@RequestBody ````MultiValueMap[String, String>HttpEntity[MultiValueMap[String, String>>.

@CookieValue注解被来用方法参数绑定HTTP中的cookie值.让我们来看一下下面这个被request接收的cookie.

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

下面的例子是如何获取JSESSIONID这个cookie值:

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

如果方法参数不是String类型,Spring会自动进行类型转换.具体可以看”Method Parameters And Type Conversion”.这个标签支持Servlet与Portlet环境下的handler方法.

13、@RequestHeader – Mapping request header attributes

@RequestHeader注解允许方法参数绑定request中的header.
下面是一个简单的request的header:

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

下面的代码就是简单的展示如何获取headers中Accept-EncodingKeep-Alive的值:

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

如果方法参数不是String类型,Spring会自动进行类型转换.具体可以看"Method Parameters And Type Conversion".当@RequestHeader注解的方法参数是Map[String, String>, MultiValueMap[String, String>,或者HttpHeaders时,这个map会被request中header的所有值自己填充.

注意:Spring MVC内嵌的支持以逗号分隔的String转换成String类型的array/collection或者其它转换系统能够识别的类型.这个标签支持Servlet与Portlet环境下的handler方法.

14、Method Parameters And Type Conversion

从request中取出的String类型的值request参数,path变量,request headers和cookie值可以被用来转换成方法参数或者field(e.g.,使用在@ModelAttribute绑定一个request参数到一个field)的目标类型。如果目标类型不是String,Spring会自动转换成相应的类型.所有简单的数据类型,比如说int,long,Date等等都是支持的.你甚至可以使用WebDataBinder来自定义转换处理.(看下面的章节,称为"Customizing WebDataBinder initialization")或者通过FormattingConversionService注册Formatters

15、Customizing WebDataBinder initialization

可以通过Spring的WebDataBinder来自己请求参数绑定的自定义属性操作.你可以使用@InitBinder注解在你的Controller中的方法中,在@ControllerAdvice注解的类上使用@InitBinder方法,或者提供自定义的WebBindingInitializer。更多细节可以看看下面的章节,"@ControllerAdvice -- Advising controllers".
init-binder方法支持所有的@RequestMapper支持的参数,除了command/form对象和相应的验证结果对象.init-binder方法必须有返回值.但是它们通常被声明为void。典型的参数包括WebDataBinderWebRequest或者java.util.Locale的结合,允许代码注册特殊的上下文来编辑.

下面就是一个简单的例子用来表示@InitBinder为所有的java.util.Date类型的表单对象配置一个CustomDateEditor:

@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));
    }

    // ...
}

在Spring4.2中,一般考虑使用addCustomFormatter来指定Formatter的实现来代替PropertyEditor的实例.这个特别的重要如果你碰巧有一个基本的Formatter需要设置在一个共享FormattingConversionService,用同样的方法来重用特殊的controller调整的绑定规则。

@Controller
public class MyFormController {

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

    // ...
}
16、Configuring a custom WebBindingInitializer

在进行数据绑定的时候,你可以提供一个自定义的WebBindingInitializer实例的实例.你可以通过配置WebBindingInitializer来实现.但是这样会覆盖默认的配置.
下面的例子是来自于PetClinic应用,展示了使用自定义的WebBindingInitializer实现的实例.org.springframework.samples.petclinic.web.ClinicBindingInitializer,通过几个PetClinic的Controller配置必须的属性编辑器。

<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>

@InitBinder方法同样能够定义在注解了@Controller的类上面,它就会适用于匹配的controllers。Spring提供使用WebBindingInitializer.具体细节可以看下一个章节,叫做"@ControllerAdvice -- Advising controllers".

17、@ControllerAdvice – Advising controllers

@ControllerAdvice注解是一个component的注解,它允许应用类被classpath自动扫描到.它也能够使用MVC namespace或者MVC Java config。
一个类如果被@ControllerAdvice注解,那么它可以包含@ExceptionHandler, @InitBinder@ModelAttribute 注解的方法。并且这些方法将应用到所有的Controller级别的@RequestMapping方法中。而不是在他们宣布控制器层次结构。

@ControllerAdvice注解同样可以用它的属性来指定一个controlers的一个子集.

// 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 {}

Check out the @ControllerAdvice documentation for more details.

18、Jackson Serialization View Support

有时候需要过滤的将序列化的对象上下文到HTTP中的resonse的body。实了提供这个功能,Spring MVC已经内置了 Jackson’s Serialization Views翻译。
在controller的方法中使用@RequestBody或者controller的方法返回ResponseEntity,添加@JsonView注解到class上表明表明这个view类或者interface已经使用了.

@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;
    }
}

注意:@JsonView允许多个类被指定,但是使用到controller方法上只能支持一个class。考虑使用一个复合interface,如果需要支持多个视图。

Controller依赖视图解析,只需序列化视图类添加然后添加到模型:

@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";
    }
}
19、Jackson JSONP Support

为了使@ResponseBodyResponseEntity方法支持JSONP,声明@ControllerAdvice bean继承AbstractJsonpResponseBodyAdvice.如下所示的构造函数参数表明JSONP查询参数名称(s):

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

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

controllers依赖view解析,当request的请求参数中有一个叫做"jsonp"或者"callback"的时候JSONP会自动激活。这些名称可以通过jsonpParameterNames的property文件来定制属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值