13.Rest风格映射以及源码解析
rest风格,即请求路径相同,但是请求方式不同代表不同处理
1.get请求:获取对象
2.post请求:修改对象
3.delete请求:删除对象
4.put请求:增加对象
1.controler代码
@RequestMapping(value = "/user" , method = RequestMethod.GET)
public String getUser(){
return "get-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String postUser(){
return "post-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.PUT)
public String putUser(){
return "put-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.DELETE)
public String deleteUser(){
return "delete-张三";
}
2.页面代码:发现页面的form表单请求方式只有get/post
<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="delete">
<input value="delet-提交" type="submit">
</form>
<form action="/user" method="put">
<input value="put-提交" type="submit">
</form>
结论:
当页面点击对应的get/post请求时可以调用到对应的方法,但是点击delete和put请求时返回的仍是get的处理方法
这是为什么呢?
分析源码:
1.向容器中注册hiddenHttpMethodFilter,用来处理rest风格的请求问题
@Bean
@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
@ConditionalOnProperty(
prefix = "spring.mvc.hiddenmethod.filter",
name = {"enabled"},
//发现默认是不注册,需要在配置文件中配置为true
matchIfMissing = false
)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
2.OrderedHiddenHttpMethodFilter的父类HiddenHttpMethodFilter方法
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) {
//注意点1:this.methodParam的值是:_method,即获取表单中name="_method"的值,即请求方式(put/delete)
//<form action="/user" method="post">
// <input name="_method" value="put" type="hidden">
// <input value="put-提交" type="submit">
//</form>
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
//注意点2:会将获取到的请求方式(put/delete)全部置换成大写:所以在表单中的请求方式可以是任意大小写的格式,这里都会置换成大写
String method = paramValue.toUpperCase(Locale.ENGLISH);
//注意点3:ALLOWED_METHODS是一个list集合,里面包含了/put/delete/patch请求
ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
if (ALLOWED_METHODS.contains(method)) {
//注意点4:判断这里的请求是否是/put/delete/patch的一种,如果是,将request对象重新封装下,method的值改为/put/delete/patch,原始的请求都是以post形式提交过来
requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
}
}
}
//放行:方位到具体的方法上
filterChain.doFilter((ServletRequest)requestToUse, response);
}
此时的代码结构更改为:
配置文件中:
1.启用该方法过滤器,默认是false
spring:
mvc:
hiddenmethod:
filter:
enabled: true
2.页面代码改为:
//改造点1:将delete和put形式的请求都改为post
<form action="/user" method="post">
//改造点2:设置一个隐藏的input标签,name值必须是:_method,值是请求方式
<input name="_method" value="delete" type="hidden">
<input value="delet-提交" type="submit">
</form>
<form action="/user" method="post">
<input name="_method" value="put" type="hidden">
<input value="put-提交" type="submit">
</form>
总结:
按照源码分析,在配置文件中加上启用隐藏方法过滤器,将hiddenHttpMethodFilter加载到容器中,当请求过来时,判断是否是post请求,是的话,判断是否是put/patch/delete的一种
是的话,重新包装一个request以供使用
重要点:
1.在表单中新增一个隐藏的input标签,name值必须是_method,value的是自己的特殊请求方式:/put/delete/patch
<input name="_method" value="put" type="hidden">
2.form表单的请求方式必须是post
<form action="/user" method="post">
重要的重要的:上述操作只针对以页面的表单提交问题
上述的操作只针对于springboot页面表单的提交
如果通过第三方插件或其他途径调用如postman直接调用http://localhost:8080/user,选择请求方式为delete,不需要任何配置都会进入到delete的处理方法中
注解的妙用
1.
@RequestMapping(value = "/user" , method = RequestMethod.GET)
等同
@GetMapping(value = "/user")
2.
@RequestMapping(value = "/user",method = RequestMethod.POST)
等同于
@PostMapping(value = "/user")
3.
@RequestMapping(value = "/user",method = RequestMethod.PUT)
等同于
@PutMapping(value = "/user")
4.
@RequestMapping(value = "/user",method = RequestMethod.DELETE)
等同于
@DeleteMapping(value = "/user")