Spring Boot 核心技术之 Rest 映射以及源码的分析,java 从入门到放弃
<body>
<form action="/user" method="get">
<input value="REST-GET 提交" type="submit" />
</form>
<form action="/user" method="post">
<input value="REST-POST 提交" type="submit" />
</form>
<form action="/user" method="delete">
<input value="REST-DELETE 提交" type="submit"/>
</form>
<form action="/user" method="put">
<input value="REST-PUT 提交"type="submit" />
</form>
</body>
</html>
controller
package com.xbhong.Controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@RestController
public class myContro {
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getUser(){
return "GET-张三";
}
// @PostMapping("/user")
@RequestMapping(value = "/user",method = RequestMethod.POST)
publ
ic 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-张三";
}
}
测试功能是否可用:
观察效果:
可以看到最后两个请求都变成 Get 的请求了。由此我们可以引出来如下问题:
为什么不同的请求会出现相同的结果
怎么实现的才能完成我们的功能
后面的文章就是围绕上述的问题进行展开的。
解决问题:
像之前的 SpringMVC 中的表单请求通过 HiddenHttpMethodFilter 实现的,这样我们查一下在 SpringBoot 中是怎么样的。
默认双击 Shift 键,输入 WebMvcAutoConfiguration 这个类
找到默认配置的过滤器:
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
通过 OrderedHiddenHttpMethodFilter 进入父类 HiddenHttpMethodFilter:
在使用之前,我们需要将后两个的请求方式改写成 post 方式,并且需要在请求的时候传入一个_method
方法(设置隐藏域);
<form action="/user" method="post">
<input name="_method" type="hidden" value="DELETE"/>
<input value="REST-DELETE 提交" type="submit"/>
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="PUT" />
<input value="REST-PUT 提交"type="submit" />
</form>
为什么要这样设置呢?我们到 HiddenHttpMethodFilter 中看下。
流程:
第一步保存了传入的请求
当该请求时 post,并且请求没有异常,才能进入下面方法,不是 Post 请求将直接通过过滤器链放行。
获取请求中的参数(this.methodParam)
DEFAULT_METHOD_PARAM = _method 获得(作为真正的请求方式)
然后再测试,发现还是没有实现。
我再回到 WebMvcConfiguration 中:
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
首先该类存在于容器中。
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
当容器中不存在HiddenHttpMethodFilter
这个类的时候,下面内容开启(条件装配);
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
表示:绑定的配置文件中:spring.mvc.hiddenmethod.filter
名字为 enable 是默认不开启的(后续版本可能开启)。这样我们就找到了问题的所在。
所以我们需要在配置文件中配置(两种方法都可以)。
yaml:
spring:
mvc:
hiddenmethod:
filter:
enabled: true
properties:
spring.mvc.hiddenmethod.filter.enabled=true
重启项目:成功解决。
源码分析:
主要是分析 doFilterInternal:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpServletRequest requestToUse = request;
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
filterChain.doFilter(requestToUse, response);
}
评论