一、REST 风格的请求
发送 REST 风格的增删改查请求:
发起图书的增删改查请求;使用REST风格的URL地址
/book/1 GET:查询1号图书
/book/1 DELETE:删除1号图书
/book/1 PUT:更新1号图书
/book POST:添加图书
http://localhost:8080/index.jsp
具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删
思考:浏览器的 form 表单只提供了 get 与 post 这两种提交方式,如何进行 put 和 delete 方式的提交呢?
为了支持页面发起 PUT 和 DELETE 的请求,Spring 提供了对 REST 风格的支持:
(1)SpringMVC 中有一个 Filter,可以把普通的请求转化为规定形式的请求,配置这个 Filter;
(2)如何发起其他形式请求?
按照以下要求:
① 创建一个 post 类型的表单;
② 表单项中携带一个 _method 的参数;
③ 这个 _method 的值就是 DELETE 或者 PUT;
HiddenHttpMethodFilter:浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与 DELETE 请求。
二、实验代码
1、控制器代码
@Controller
public class RestTestController {
@RequestMapping(value = "/book/{bid}", method = RequestMethod.GET)
public String getBook(@PathVariable("bid")Integer bid) {
System.out.println("查询到了" + bid + "图书");
return "success";
}
@RequestMapping(value = "/book", method = RequestMethod.POST)
public String saveBook() {
System.out.println("添加了新的图书");
return "success";
}
@RequestMapping(value = "/book/{bid}", method = RequestMethod.DELETE)
public String deleteBook(@PathVariable("bid")Integer bid) {
System.out.println("删除了" + bid + "图书");
return "success";
}
@RequestMapping(value = "/book/{bid}", method = RequestMethod.PUT)
public String updateBook(@PathVariable("bid")Integer bid) {
System.out.println("更新了" + bid + "图书");
return "success";
}
}
2、配置 HiddenHttpMethodFilter 过滤器(SpringMVC提供的过滤器)
<!-- 支持REST风格的过滤器:可以将POST请求转换为PUT或DELETE请求 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、页面请求链接
</body>
<a href="book/1">查询图书</a>
<form action="book" method="post">
<input type="submit" value="添加图书">
</form>
<form action="book/1" method="post">
<input name="_method" value="PUT">
<input type="submit" value="更新1号图书">
</form>
<form action="book/1" method="post">
<input name="_method" value="DELETE">
<input type="submit" value="删除1号图书">
</form>
</body>
4、测试
5、可能会出现的问题
(1)这个代码的运行环境需要 Tomcat7.0以及以下版本。
(2)使用 Tomcat8.0或以上会报JSPs only permit GET POST or HEAD 的错误。
解决方式一:在jsp页面设置为 isErrorPage
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
解决方式二:
三、HiddenHttpMethodFilter过滤器源码分析
1、为什么请求隐含参数名称必须叫做 "_method"?
因为在过滤器中默认是获取参数名为 "_method" 的参数值的。
2、HiddenHttpMethodFilter 的处理过程
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//获取表单上 _method 带来的值(delete、put)
String paramValue = request.getParameter(this.methodParam);
//获取表单方式为 POST 而且 _method 有值
if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
//把参数转为大写(DELETE、PUT)
String method = paramValue.toUpperCase(Locale.ENGLISH);
//包装了一下request对象,并且重写了request对象的 getMethod
HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);
//wrapper.getMethod (PUT 或 DELETE)
filterChain.doFilter(wrapper, response);
}
else {
//直接放行
filterChain.doFilter(request, response);
}
}
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
//重写了 getMethod 方法
@Override
public String getMethod() {
return this.method;
}
}
3、图解