以下是工作中整理出来的SpringMVC注解的使用方式:
1.请求处理类和方法的注解:
将请求映射到控制器处理方法的工作包含一系列映射规则,这些规则是根据HTTP请求中的各种信息制定的,具体包括请求URL、请求参数、请求方法、请求头这4个方面的信息项。
@Controller:在POJO类定义处标注@Controller,再通过Spring IOC容器注入相应的类,即可使POJO成为一个能处理HTTP请求的控制器。
@RestController:为了方便开发,从Spring4.0开始引入了@RestController注解,该注解标注了@Controller和@ResponseBody。通过直接在控制器上标注@RestController,就不需要在每个@RequestMapper方法上添加@ResponseBody了。
@RequestMapper:使用@RequestMapper映射请求。@RequestMapper使用value值指定请求的URL。在类定义处指定的URL相对于Web应用的部署路径,在方法定义处指定的URL相对于类定义处指定的URL。@RequestMapper的value、method、params、headers分别对应HTTP的请求的URL、请求方法、请求参数、报文头,他们之间是”与”的关系,联合使用可让请求映射更加精确化。如下代码:
/**
* Created by xieyuhui on 2018/7/4.
*/
@Controller
@RequestMapping("/base")
public class BaseController {
/**
* url : 请求路径 select
* method : 请求方法 post
* params : 请求参数 userId
* headers : 请求头 content-type=text/*
* @param userId:
* @return
*/
@RequestMapping(path = "/select", method = RequestMethod.POST, params = "userId", headers = "content-type=text/*")
public String test(@RequestParam("userId") String userId) {
//TODO
return "";
}
}
@RequestMapper不但支持标准的URL,还支持Ant风格和带{xxx}占位符的URL。如下表:
example | pattern |
---|---|
/root/*/select | /root/aaa/select 、/root/bbb/select … |
/root/**/select | /user/select、/user/aaa/bbb/select … |
/root/select?? | /root/selectaaa、 /root/selectbbb … |
/root/{id} | /root/123、/root/456 … |
/root/**/{id} | /root/aaa/bbb/123、/root/aaa/456 … |
/root/{id}/user/{path}/detail | /root/123/user/aaa/detail … |
@PathVariable:使用@PathVariable可以把@RequestMapper中的占位符参数绑定到控制器处理方法的入参中,类定义处@RequestMapping的URL如果使用占位符的参数,也可以绑定到处理方法的入参中。如下代码:
@Controller
@RequestMapping("/open/{ownerId}")
public calss BaseController{
/**
*
* @param ownerId 绑定 {ownerId}的值
* @param petId 绑定 {petId}的值
*/
@RequestMapping("/select/{petId}")
public void select(@PathVariable String ownerId, @PathVariable String petId){
//TODO
}
}
2.请求处理方法签名的注解
对处理方法进行签名,包括如何设置方法入参以绑定请求信息、如何定义返回值类型等
@RequestParam:在方法入参处使用@RequestParam注解指定其对应的请求参数,该注解有3个参数:
- value:参数名。
- required:是否必需,默认为true,表示请求中必需包含对应的参数名,如果不存在则抛出 400 bad request 错误。
- defaultValue:默认参数名,在设置该参数时,自动将required设为false。不推荐使用该参数。
example如下:
/**
* userName和age绑定到handle()方法的 aaa和bbb参数中,并自动完成类型转换。
* 如果不存在age请求参数,则抛出400错误。
*
* @param aaa
* @param bbb
* @return
*/
@RequestMapping("/handle")
public String handle(@RequestParam(value = "userName", required = false) String aaa, @RequestParam("age") int bbb) {
//TODO
return "";
}
@CookieValue:使用@CookieValue绑定请求中的Cookie值。和@RequestParam注解拥一样的参数。example如下:
/**
* HTTP请求中如果有name为id的 cookie,则绑定到handleCookie()方法id参数中。
* required = false 即使没有 也不会抛出异常。
* @param id
* @return
*/
@RequestMapping("/handleCookie")
public String handleCookie(@CookieValue(value = "id", required = false) int id) {
//TODO
return "";
}
@RequestHeader:使用@RequestHeader绑定请求报文头的属性值,和@RequestParam注解拥一样的参数。请求报文包含了若干个报文头属性,服务器可据此获知客户端的信息,通过@RequestHeader即可将报文头属性值绑定到处理方法的入参中。example如下:
/**
* HTTP请求头中的Accept-Encoding和Keep-Alive属性将被绑定到handleHeader()方法encoding和keepAlive参数
* @param encoding
* @param keepAlive
* @return
*/
@RequestMapping("/handleHeader")
public String handleHeader(@RequestHeader(value = "Accept-Encoding") String encoding,
@RequestHeader(value = "Keep-Alive", required = false) long keepAlive) {
//TODO
return "";
}
基于HttpMessageConverter接口的注解:
HttpMessageConverter接口负责将请求信息转换为一个范型对象,也负责将范型对象输出作为响应信息。
SpringMVC默认装配了4个 HttpMessageConverter:
- StringHttpMessageConverter
- ByteArrayHttpMessageConverter
- SourceHttpMessageConverter
- ALLEncompassingFormHttpMessageConverter
如果需要装配其它类型的HttpMessageConverter,需要在Spring容器中配置RequestMappingHandlerAdapter,如下配置了一个MappingJackson2HttpMessageConverter:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=utf-8</value>
<value>text/html;charset=utf-8</value>
<value>text/json;charset=utf-8</value>
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
SpringMVC提供了两种注解方式来使用HttpMessageConverter。
@RequestBody/@ResponseBody:可以访问请求和响应报文体的数据。
/**
* @RequestBody: 根据方法中body的类型匹配HttpMessageConverter。
* 由于这里的body是String类型,所以匹配到了StringHttpMessageConverter。
* 然后用StringHttpMessageConverter把HTTP请求体信息进行转换并将结果绑定到body参数中。
*
* @ResponseBody: 由于方法返回类型是byte[],所以SpringMVC匹配到了ByteArrayHttpMessageConverter。
* ByteArrayHttpMessageConverter对返回值做处理 并返回给客户端。
*
* @param body
* @return
*/
@ResponseBody
@RequestMapping("/handle2")
public byte[] handle2(@RequestBody String body) {
return body.getBytes();
}
HttpEntity/ResponseEntity:这两个不是以注解的形式使用的,直接作为对象类型使用。它们不但可以访问请求和响应报文体的数据,还可以访问请求和响应报文头的数据。SpringMVC根据范型类型查找对应的HttpMessageConverter。改造一下@RequestBody/@ResponseBody的示例:
/**
* HttpEntity<T>:范型指定入参的类型,这里范型是String类型,则匹配到了StringHttpMessageConverter。
* <p>
* ResponseEntity<T>:范型指定返回的类型,这里是byte[],所以SpringMVC匹配到了ByteArrayHttpMessageConverter。
*
* @param httpEntity
* @return
*/
@RequestMapping("/handle3")
public ResponseEntity<byte[]> handle3(HttpEntity<String> httpEntity) {
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(httpEntity.getBody().getBytes(), HttpStatus.OK);
return responseEntity;
}
- 当控制器处理方法使用@RequestBody/@ResponseBody或HttpEntity/ResponseEntity时,SpringMVC才使用注册的HttpMessageConverter对请求/响应消息进行处理。
- SpringMVC首先根据请求头或响应头的Accept属性选择匹配的HttpMessageConverter,然后根据参数类型或范型类型的过滤得到匹配的HttpMessageConverter,如果找不到可用的HttpMessageConverter则报错。
- @RequestBody/@ResponseBody不需要成对出现。如果方法入参使用了@RequestBody,则SpringMVC选择匹配的HttpMessageConverter将请求消息转换并绑定到该入参数中。如果处理方法标注了@ResponseBody,则SpringMVC选择匹配的HttpMessageConverter将方法返回值转换并输出响应信息。
- HttpEntity/ResponseEntity的功能和@RequestBody/@ResponseBody的功能类似。
3.处理模型数据注解
方法逻辑处理完后,会产生模型数据,导向指定的视图。将模型数据暴露给视图是SpringMVC框架的一项重要工作。SpringMVC提供了多种途径输出模型数据。
ModelAndView:ModelAndView类型作为方法返回值,则即包含视图信息,又包含模型数据,这样SpringMVC就可以使用视图对模型数据进行渲染了。
@ModelAttribute:如果希望将方法入参对象添加到模型中,则使用该注解。该注解既可以在方法入参上使用,也可以在方法定义中使用。example如下:
/**
* Created by xieyuhui on 2018/7/4.
*/
@Controller
@RequestMapping("/base")
public class BaseController {
/**
* 在访问BaseController中任何一个请求处理方法前,
* SpringMVC先执行该方法,把"requiredString"这个字符串添加到模型中。
*
* @return
*/
@ModelAttribute
public String requiredAttribute() {
return "requiredString";
}
/**
* 先把"requiredString" 赋值给str,再根据HTTP请求参数进一步覆盖str的值。
*
* @param str
* @return
*/
@RequestMapping("/handle4")
public String handle4(@ModelAttribute("requiredString") String str) {
return str;
}
}
@SessionAttributes:该注解可以让多个请求共享某个数据模型,在控制器类中标注一个@SessionAttributes,SpringMVC会把模型数据暂存到HttpSession中。除了可以通过属性名指定需要放入会话的属性外,还可以通过模型属性的对象类型指定,也可以属性名和属性类型同时指定,二者都允许多值,放到会话的属性是二者的并集。
example如下:
/**
* Created by xieyuhui on 2018/7/5.
*/
@Controller
@RequestMapping("/root")
/**
*@SessionAttributes: SpringMVC会自动将当前Controller类中任何方法属性名为"xxx"的模型存储到HttpSession中。
* 此时"xxx"为会话属性。
*
* @SessionAttributes(value = {"aaa","bbb"}) 将名为aaa,bbb的模型属性添加到会话中
* @SessionAttributes(types = String.class) 将模型数据中所有String类型到的模型属性添加到会话中
* @SessionAttributes(value = {"aaa","bbb"},types = String.class)将名为aaa,bbb的模型属性和所有String类型到的模型属性添加到会话中
*/
@SessionAttributes("commonAttribute")
public class RootController {
/**
* 请求handle1是,SpringMVC通过@ModelAttribute将请求入参添加到模型中。
* @param commonAttribute
*/
@RequestMapping("/handle1")
public void handle1(@ModelAttribute("commonAttribute") String commonAttribute) {
//TODO
}
/**
* 通过ModelMap可以访问到模型中的所有数据,这里读取到模型中的"commonAttribute"属性值。
* @param modelMap
* @return
*/
@RequestMapping("/handle2")
public String handle2(ModelMap modelMap) {
String commonAttribute = (String) modelMap.get("commonAttribute");
return commonAttribute;
}
}