SpringBoot 学习笔记 Part09
1. 请求映射
从@RequestMapping标注处理什么请求,到控制器方法的方法体返回值,这个过程就叫做请求映射,如下:
@RequestMapping("hello")
public String hello(){
return "Hello SpringBoot 2 !";
}
2. Rest映射
Rest风格支持,即使用HTTP请求方式动词来表示对资源的操作。
- 以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户
- 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
Rest风格的请求映射,它们映射到的地址都是同一个,再根据请求方式的不同来区分不同的处理。代码如下:
@RequestMapping(value = "user",method = RequestMethod.GET)
public String getUser(){
return "GET-张三";
}
@RequestMapping(value = "user",method = RequestMethod.POST)
public String saveUser(){
return "POST-张三";
}
@RequestMapping(value = "user",method = RequestMethod.PUT)
public String putUser(){
return "PUT-张三";
}
@RequestMapping(value = "user",method = RequestMethod.DELETE)
public String deleteUser(){
return "DELETE-张三";
}
使用Rest风格进行映射,我们需要使用到一个核心Filter:HiddenHttpMethodFilter,我们进入这个Filter的底层可以发现,这个过滤器对于请求方式的处理过程。
那么SpringMVC有为我们自动配置这个Filter吗,前往底层源码可以发现,并没有。因此,必须手动配置。
使用方法总结:
-
将表单的 method 设置为 post ,并将隐藏域 _method 设置为 put/delete/get (即 _method 里设置真正的请求方式)
<form action="user" method="post"> <input type="hidden" name="_method" value="put"> <input type="submit" value="REST-PUT提交"> </form> <form action="user" method="post"> <input type="hidden" name="_method" value="delete"> <input type="submit" value="REST-DELETE提交"> </form>
-
SpringBoot中 手动开启
spring: mvc: hiddenmethod: filter: enabled: true
3. Rest的派生注解
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping:它们就是@RequestMapping派生出来的注解,默认携带某个提交方式属性,源码如下:
@RequestMapping(method = {RequestMethod.GET})
public @interface GetMapping{}
将上面的示例全都改写为用派生注解,代码如下:
@GetMapping("user")
public String getUser(){
return "GET-张三";
}
@PostMapping("user")
public String saveUser(){
return "POST-张三";
}
@PutMapping("user")
public String putUser(){
return "PUT-张三";
}
@DeleteMapping("user")
public String deleteUser(){
return "DELETE-张三";
}
4. Rest映射的原理
springmvc底层源码:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest requestToUse = request;
if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
}
}
}
filterChain.doFilter((ServletRequest)requestToUse, response);
}
分析基于表单提交时使用的Rest映射过程:(下面以 DELETE 请求方式为例)
- 表单提交时会带上隐藏域 _method=DELETE
- 请求过来时会被 HiddenHttpMethodFilter拦截
- 判断请求是否有异常,并且要求请求方式是 POST
- 获取 _method 的值并转成大写(这一步说明我们在编写html时,请求方式大小写可以随意)
- 判断允许的请求方式中包不包含 _method的值(这里可以发现除了HTTP传统的 GET、POST外,还兼容PUT、DELETE、PATCH)
- 调用HttpMethodRequestWrapper方法。(原生request的请求是post,包装模式requestWrapper重写了原生request的getMethod方法,返回的就变成了_method的值)
- 过滤器链放行时放行的是Wrapper,以后的方法调用getMethod都会调用到包装模式requestWrapper重写过的,所以以后获取到的都是_method的值了。
注意:Http只兼容两种原生请求方式,才需要过滤器的支持。Rest使用客户端工具时,如安卓或Postman模拟,就可以直接发送PUT、DELETE请求,无需Filter。
在此我们也能够意识到为什么springboot默认没有把HiddenHttpMethodFilter开启。因为如果不做页面开发,springboot就是用于微服务的开发,微服务开发简单来说就是给别人提供接口,别人发给我们请求,我们提供JSON数据。不会经常交互页面,且前后端分离,页面也可能是别人写的。
5. 更换隐藏域的属性名
由于 SpringMVC 的自动配置时加载 HiddenHttpMethodFilter 组件是根据 @ConditionalOnMissingBean 按需加载的,因此我们可以自己给容器中放一个 HiddenHttpMethodFilter,并且隐藏域的属性名自己喜欢取什么就取什么。
@Configuration(proxyBeanMethods = false) //没有什么依赖,所以弄成多例可以减少开销
public class WebConfig {
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m"); // HiddenHttpMethodFilter有一个set方法可以更改隐藏域属性
return methodFilter;
}
}
用 HiddenHttpMethodFilter 里的一个set方法 setMethodParam( ) 可以更改隐藏域属性。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/93562.html