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>
瀏覽器驗證結果: