SpringMVC常用注解使用
- 三、SpringMVC常用注解使用
- 3.1 @RequestMapping
- 3.1.1 属性
- 3.1.2 请求路径Ant Path匹配规则
- 3.1.3 指定请求方法
- 3.1.4 一般的RequestMapping格式
- 3.2 @ResponseBody
- 3.2.1 作用
- 3.2.2 示例
- 3.3 @ResponseStatus
- 3.3.1常见的HTTP状态码
- 3.3.2 @ResponseStatus使用
- 3.4 @Mapping相关注解
- 3.5 @RequestAttribute
- 3.5.1 http请求中的属性(attribute)和参数(parameter)的区别
- 3.5.2 @RequestAttribute的使用
- 3.5.3 扩展:`/`与`/*`的区别
- 3.6 @ModelAttribute
- 3.6.1 Model对象
- 3.6.2 @ModelAttribute使用
- 3.7 @RestController
三、SpringMVC常用注解使用
3.1 @RequestMapping
之前我们使用RequestMapping最多的是使用value属性指定URL与Controller方法上的映射,但是如果我们有一个查询用户GET /user/{id}接口和删除用户接口DELETE /user/{id},那该怎么区分呢?下面就来具体介绍一下RequestMapping各种属性来解决上诉类似问题
3.1.1 属性
- value
指定请求路径上的url,符合AntMatcher匹配规则 - path
同value - method
指定方法的请求方式RequestMethodGET、HEAD、POST、PUT、PATCH、DELETE、OPTIONS、TRACE - params
指定限制请求参数的条件
- 要求请求映射所匹配的请求必须携带param请求参数 param
- 要求请求映射所匹配的请求必须不能携带params请求参数 !param
- 要求请求映射所匹配的请求必须携带param请求参数且param=value param=value
- 要求请求映射所匹配的请求必须携带param请求参数但是param!=value param!=value
- headers
发送的请求中必须包含的请求头
类似于params的四种条件 - consumes
指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;MediaType.APPLICATION_JSON_VALUE、MediaType.TEXT_HTML_VALUE - produces
指定返回的内容类型
取值为MediaType

3.1.2 请求路径Ant Path匹配规则
RequestMapping的value属性指定的请求路径满足ant路径匹配规则,且Spring还提供了一个AntPathMatcher工具类。下面介绍一下ant路径匹配规则。
特殊符号 | 作用 |
? | 匹配任意单个字符 |
* | 匹配当前路径下(以/作为一层路径)的0个或任意个字符 |
** | 匹配0个或任意个路径 |
{id: [a-z0-9A-Z_-]+} | 将正则表达式[a-z0-9A-Z_-]+匹配到的值,赋值给名为id 的路径参数,且必须完全匹配 |
可以在工程下建立测试类,使用AntPathMatcher进行测试,新建一个AntPathMatcherTest测试类

编写测试用例如下:
package org.numb.common.util;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.util.AntPathMatcher;
public class AntPathMatcherTest {
@Test
public void testAntPath() {
AntPathMatcher matcher = new AntPathMatcher();
boolean result;
String path = "/user/00112233";
result = matcher.match("/user/{id}", path);
Assert.assertTrue(result);
path = "/user/00112233";
result = matcher.match("/user/?", path);
Assert.assertFalse(result);
path = "/user/00112233";
result = matcher.match("/user/*", path);
Assert.assertTrue(result);
path = "/user/00112233/ZhangSan";
result = matcher.match("/user/*", path);
Assert.assertFalse(result);
path = "/user/00112233/ZhangSan";
result = matcher.match("/user/**", path);
Assert.assertTrue(result);
path = "/user/00112233";
result = matcher.match("/user/{id:[a-z0-9A-Z_-]+}", path);
Assert.assertTrue(result);
path = "/user/00112233$";
result = matcher.match("/user/{id:[a-z0-9A-Z_-]+}", path);
Assert.assertFalse(result);
}
}注意AntPathMatcher的match(String pattern, String path)方法,要匹配的路径在前,请求的路径在后,换言之RequestMapping的value属性类比于这里的pattern参数。分析一下上面的测试用例
请求路径 | 匹配路径 | 结果 | 说明 |
/user/00112233 | /user/{id} | true | 一般的请求路径映射 |
/user/00112233 | /user/? | false | ?只能匹配一个字符,00112233有多个字符 |
/user/00112233 | /user/* | true | *匹配当前路径下的任意字符 |
/user/00112233/ZhangSan | /user/* | false | *只能匹配一层路径,/00112233/ZhangSan是两层路径,所以无法匹配 |
/user/00112233/ZhangSan | /user/** | true | **匹配任意层路径 |
/user/00112233 | /user/{id:[a-z0-9A-Z_-]+} | true | 满足[a-z0-9A-Z_-]+正则表达式 |
/user/00112233$ | /user/{id:[a-z0-9A-Z_-]+} | false | 不满足[a-z0-9A-Z_-]+正则表达式 |
通过上面例子可以更好的理解RequestMapping的请求路径匹配规则。
3.1.3 指定请求方法
现在来解决如何区分相同请求路径参数的不同http方法,即类似查询用户GET /user/{id}接口和删除用户接口DELETE /user/{id}的区分。可以用RequestMapping的method属性指定请求方法,从而完成请求的映射。
可以改写上述UserController的接口如下,满足Restful风格:
@Controller
public class UserController {
@Resource
private UserService userService;
@RequestMapping(value = "/user/{user_id}", method = RequestMethod.GET)
@ResponseBody
public String getUser(@PathVariable(value = "user_id") String id) {
return userService.getUserName(id);
}
@RequestMapping(value = "/user/{user_id}", method = RequestMethod.DELETE)
@ResponseBody
public String deleteUser(@PathVariable(value = "user_id") String userId) {
System.out.println(userId);
return "success";
}
}3.1.4 一般的RequestMapping格式
一般常用的value、method、consumes和produces来确定一个接口,如下所示
package org.numb.controller;
import org.numb.model.User;
import org.numb.service.UserService;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@Controller
public class UserController {
@Resource
private UserService userService;
@RequestMapping(value = "/user/{user_id}", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody public String getUser(@PathVariable(value = "user_id") String id) {
return userService.getUserName(id);
}
@RequestMapping(value = "/users", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody public String getUser(@RequestBody List<User> users) {
System.out.println(users);
return "success";
}
@RequestMapping(value = "/user/{user_id}", method = RequestMethod.DELETE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String deleteUser(@PathVariable(value = "user_id") String userId) {
System.out.println(userId);
return "success";
}
}3.2 @ResponseBody
3.2.1 作用
将函数返回值装入responsebody中返回到前端,也就是将return返回值作为请求返回值,return的数据不会解析成返回跳转路径。
3.2.2 示例
当使用@ResponseBody标注时,如果返回的是一个对象,则直接将这个对象序列化成字符串返回。这里注意必须依赖序列化组件,由于在2.2章节中已经引入jackson,在这里直接引用。增加UserService中的getUser方法,并用Map模拟数据库操作,返回一个User对象
UserService
public User getUser(String userId) {
String userName = getUserName(userId);
User user = new User();
user.setId(userId);
user.setName(userName);
return user;
}UserController
@RequestMapping(value = "/user/{user_id}", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public User getUser(@PathVariable(value = "user_id") String id) {
return userService.getUser(id);
}测试:

注意要增加请求头Content-Type:application/json,否则由于我们指定了RequestMapping的consumes属性,会报415不支持的媒体类型(Unsupported media type)错误。
3.3 @ResponseStatus
用应返回的状态代码和原因消息标记方法或异常类。 调用处理程序方法时或抛出指定的异常时,状态代码将应用于 HTTP 响应。 它会覆盖通过其他方式设置的状态信息,例如ResponseEntity或redirect:。这里我们简单讲一下controller方法利用@ResponseStatus返回http状态码。
3.3.1常见的HTTP状态码
状态码 | 状态 | 说明 |
200 | OK | 客户端请求成功 |
202 | Accepted | 已接受处理请求,但处理尚未完成 |
204 | No Content | 服务器已成功完成请求,并且不会返回响应体 |
302 | Found | 临时跳转,跳转的地址通过Location指定 |
400 | Bad Requet | 客户端请求有语法错误,不能被服务器识别 |
401 | Unauthorized | 客户端尝试在受保护资源上运行而未提供适当的授权 |
403 | Forbidden | 服务器收到请求,但是拒绝提供服务 |
404 | Not Found | 请求的资源不存在 |
405 | Method Not Allowed | 表示客户端尝试使用资源不允许的HTTP方法 |
415 | Unsupported Media Type | 表明无法处理客户端提供的媒体类型 |
500 | Internal Server Error | 服务器发生不可预期的错误 |
509 | Bandwidth Limit Exceeded | 服务器达到带宽限制。当前访问太频繁被限流 |
3.3.2 @ResponseStatus使用
这里希望post:/users请求返回202,但是默认返回200,此时可以用@ResponseStatus返回202。
@RequestMapping(value = "/users", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@ResponseStatus(code = HttpStatus.ACCEPTED)
public String getUser(@RequestBody List<User> users) {
System.out.println(users);
return "success";
}测试:

3.4 @Mapping相关注解
@Mapping、@RequestMapping和@GetMapping等相关注解的关系。
从@RequestMapping的源码可以看出之间的关系:


- @Mapping:表明请求映射的元注解
- @RequestMapping:实际表示将一个 Web 请求映射到Controller类中方法的注解,可以理解为@Mapping的实现者。
- @GetMapping:在@GetMapping注解上加了
@RequestMapping(method = RequestMethod.GET),即指定了get的请求映射注解,其余类似。 - @PostMapping:表明post请求映射的注解。
- @PutMapping:表明put请求映射的注解。
- @DeleteMapping:表明delete请求映射的注解。
- @PatchMapping:表明patch请求映射的注解。
关系图为:

3.5 @RequestAttribute
@RequestAttribute注解的作用是获取请求中的属性值(attribute),属性(attribute)和参数(parameter)容易混淆,特在此说明。
3.5.1 http请求中的属性(attribute)和参数(parameter)的区别
- 来源不同:
参数(parameter)是从客户端(浏览器)中由用户提供的,是直接由前端传到后端来的值。
属性(attribute)是服务器端的组件(JSP或者Servlet)利用requst.setAttribute()设置的,在SpringMVC体系中一般在**过滤器(filter)或拦截器(interceptor)**中进行设置。 - 操作不同:
参数(parameter)的值只能读取不能修改,读取可以使用request.getParameter()读取;
属性(attribute)的值既可以读取也可以修改,读取可以使用request.getAttribute(),设置可使用request.setAttribute()。 - 数据类型不同:
参数(parameter)不管前台传来的值语义是什么,在服务器获取时都以String类型看待,并且客户端的参数值只能是简单类型的值,不能是复杂类型,比如一个对象。
属性(attribute)的值可以是任意一个Object类型。
从ServletRequest接口源码中便可以看出

参考链接:request中参数(parameter)和属性(Attribute)的区别
3.5.2 @RequestAttribute的使用
可以用filter验证@RequestAttribute的使用。在成熟项目的中,会对一个用户的登录信息进行身份验证,此时会引入token信息来作为验证手段。本节中可以在filter中设置一个token的attribute,然后在controller中获取到token信息并进行验证,这里仅实现filter中request.setAttribute("token", token)来做@RequestAttribute使用的演示说明。
- 添加一个自定义filter
- 自定义AuthenticationFilter
package org.numb.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.stereotype.Component;
// 生成一个AuthenticationFilter的bean,被spring托管
@Component
public class AuthenticationFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)
|| !(response instanceof HttpServletResponse)) {
throw new ServletException("AuthenticationFilter can handle http requests");
}
request.setAttribute("token", "I am root");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}- 在web.xml中配置filter
<filter>
<filter-name>authenticationFilter</filter-name>
<filter-class>org.numb.filter.AuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>authenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 测试@RequestAttribute的使用
- 在UserController中添加@RequestAttribute
@RequestMapping(value = "/user/{user_id}", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@ResponseStatus(code = HttpStatus.OK)
public User getUser(@PathVariable(value = "user_id") String id,
@RequestAttribute(value = "token") String tokenInfo) {
System.out.println(tokenInfo);
return userService.getUser(id);
}- postman测试
3.5.3 扩展:<url-pattern>/</url-pattern>与<url-pattern>/*</url-pattern>的区别
/:表示匹配所有请求,其中包含除.jsp和.jspx外的所有后缀。
/*:会覆盖其他所有的servlet,包括servlet容器提供的所有servlet。即无论你发出什么请求,都会在该servlet拦截处理,当然也包括.jsp和.html等静态资源。
/**:什么请求都不能拦截处理,相当于没有设置。
3.6 @ModelAttribute
@ModelAttribute,用来将请求参数绑定到 Model 对象。
3.6.1 Model对象
模型(Mode)对象的作用主要是保存数据,可以借助它们将数据带到前端。前端可以获取model数据,并且实现相应的业务逻辑
3.6.2 @ModelAttribute使用
- 应用于Controller内普通方法上
被@ModelAttribute标注的方法会在Controller的每个请求映射方法(带@RequestMapping的方法)执行之前都执行,因此对于一个Controller中包含多个请求映射方法的时候,要谨慎使用。
方法一:方法参数上带Model参数,使用 model.addAttribute()设置。
/**
* ModelAttribute的使用 <br/>
* 方法一:方法参数上带Model参数,使用 model.addAttribute()设置
*
* @param model
*/
@ModelAttribute
public void addModel(Model model) {
model.addAttribute("requestId", UUID.randomUUID().toString());
}方法二:使用返回值,返回值会被自动调用设置进隐含的Model。
/**
* ModelAttribute的使用 <br/>
* 方法二:使用返回值,返回值会被自动调用设置进隐含的Model。
* 在Model中的key为返回值首字母小写,value为返回的值
*/
@ModelAttribute
public String addModel() {
return UUID.randomUUID().toString();
}- 应用于方法参数上
可以获取Model中的attribute,这一点有点类似于@RequestAttribute
@ModelAttribute
public void addModel(Model model) {
model.addAttribute("requestId", UUID.randomUUID().toString());
}
@RequestMapping("/hello")
@ResponseBody
public String helloUser(@RequestParam(value = "user_name", required = false) String userName, @ModelAttribute(value = "request_id") String requestId) {
System.out.println(requestId);
return "Hi, " + userName;
}测试:

- 应用于Controller内请求映射方法(带@RequestMapping的方法)上
表明请求映射方法的返回值不再是视图,而是将返回值放入到Model中
3.7 @RestController
@RestController的作用于一个Controller类上,表明这个类是一个Controller,且会给每个请求映射方法都会追加@ResponseBody注解,表明方法返回值不是一个视图,直接将结果返回至前台处理。
@RestController的源码如下:

被@RestController注解的Controller类,可以不用在每个方法上再加@ResponseBody,但是注意一点,如果是重定向方法,可能会导致重定向失效。因为表明了方法返回值是直接返回至前端的,所以就不再重定向方法,返回值被当作字符串返回到前端
















