Rest请求常用方式:get, post, put, delete…
好处:
相对于以前的请求方式,每一个请求都需要重新命名一个如deleteUser, saveUser, updateUser。。。只需要/user + method方法 就可以
@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-张三";
}
<form action="/user" method="get">
<input value="get提交" type="submit">
</form>
<form action="/user" method="post">
<input value="post提交" type="submit">
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="delete">
<input value="delete提交" type="submit">
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="put">
<input value="put提交" type="submit">
</form>
注意这里面只是form表单的形式,form表单只有get和post.先来看springboot2源码(我这里的版本是2.3.4.RELEASE)
会默认找配置文件的spring.mvc.hiddenmethod.filter 前缀,如果没有默认是不会像spring容器中注入这个实例,也就是这个没法用,所以要在配置文件中配置
继续点开这个类
private static final List<String> ALLOWED_METHODS;
public static final String DEFAULT_METHOD_PARAM = "_method";
...
static {
ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
}
...
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);
}
当一个请求过来,会判断是不是post请求并且这个请求没有异常,获取请求_method这个参数(这也是上面为什么要在html表单中加隐藏input框原因),如果有将值转成大写,并判断是不是包含put, delete,patch这几个值,如果有将
requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
public String getMethod() {
return this.method;
}
}
继承HttpServletRequestWrapper 点进去发现最终还是实现了HttpServletRequest ,这里是一个装饰者模式,重写了method方法,这个method方法是我们传进来的参数,相当于给原生的HttpServletRequest 包装了一下
public class HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest {
然后filterChain.doFilter进入下一级过滤器,,最终到controller层,这样才有delete,put方法
如果其他客户端,如postman请求,不会重新包装下HttpServletRequest,这里只是针对页面的form表单提交
上面的RequestMapping直接简写成
// @RequestMapping(value = "/user",method = RequestMethod.GET)
@GetMapping("/user")
public String getUser(){
return "GET-张三";
}
// @RequestMapping(value = "/user",method = RequestMethod.POST)
@PostMapping("/user")
public String saveUser(){
return "POST-张三";
}
// @RequestMapping(value = "/user",method = RequestMethod.PUT)
@PutMapping("/user")
public String putUser(){
return "PUT-张三";
}
// @RequestMapping(value = "/user",method = RequestMethod.DELETE)
@DeleteMapping("/user")
public String deleteUser(){
return "DELETE-张三";
}
里面也一样,看着简洁些