form表单的提交方式只支持GET或者POST,为了实现restful风格,需要使用form表单实现PUT和DELETE方式的提交,对于这种情况,spring提供了过滤器 HiddenHttpMethodFilter
,可以将POST方式提交的表单转换成PUT或者DELETE。
案例环境:
- springboot 2.4.3
- IntelliJ IDEA 2021.1 (Ultimate Edition)
- Google Chrome版本 89.0.4389.114(正式版本)
过滤器 HiddenHttpMethodFilter
在springboot中配置在自动配置类WebMvcAutoConfiguration
中:
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter",
name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
OrderedHiddenHttpMethodFilter
继承自HiddenHttpMethodFilter
,然后看HiddenHttpMethodFilter
的源码:
public static final String DEFAULT_METHOD_PARAM = "_method";
private String methodParam = DEFAULT_METHOD_PARAM;
@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);
}
14行, String paramValue = request.getParameter(this.methodParam);
在request请求中获取_method
参数:
- 转换成大写,所以这个
_method
参数大小写都行; - 检查传入的
_method
是否在ALLOWED_METHODS
中,ALLOWED_METHODS
包含PUT
、DELETE
、PATCH
- 调用
HttpMethodRequestWrapper()
方法,将POST请求包装成其他HTTP请求
HttpMethodRequestWrapper()
源码:
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
@Override
public String getMethod() {
return this.method;
}
}
至此,POST请求被转换成其他的HTTP请求了。
写个例子,验证一下:
@RestController
public class RestfulController {
@PostMapping("rest")
public String post() {
return "post";
}
@GetMapping("rest")
public String get() {
return "get";
}
@DeleteMapping("rest")
public String delete() {
return "delete";
}
@PutMapping("rest")
public String put() {
return "put";
}
}
该版本的springboot默认没有向容器中注入这个过滤器,所以需要在配置文件application.yml中开启:
# 开启过滤器
spring:
mvc:
hiddenmethod:
filter:
enabled: true
写一个表单测试:
<form method="post" action="rest">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="PUT">
</form>
浏览器验证结果: