第三章 HiddenHttpMethodFilter (REST)
REST风格是什么?
REST:即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用
- 资源(Resources):【万物皆资源】网络上的一个实体,或者说是网络上的一个具体信息。
它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。
可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。
获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。 - 表现层(Representation):【每一种资源都有对应的表现形式】把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
- 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。
而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。 - 具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
REST
系统希望以非常简洁的URL地址来发请求;怎么表示对一个资源的增删改查用请求方式来区分
旧方式
/getBook?id=1 :查询图书 /deleteBook?id=1 :删除1号图书 /updateBook?id=1 :更新1号图书 /addBook :添加图书
REST推荐:简洁的URL提交请求,以请求方式区分
url地址这么起名; /资源名/资源标识符 /book/1 :GET 查询1号图书 /book/1 :PUT 更新1号图书 /book/1 :DELETE 删除1号图书 /book : POST 添加图书 系统的URL地址就这么来设计即可
REST风格增删改查环境搭建
问题:从页面上只能发送两种请求,GET 、POST 其他的请求方式没法使用 如果强制使用默认为get
package com.project.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class MyController { @RequestMapping(value="book/{bid}" , method = RequestMethod.GET) public String getBook(@PathVariable("bid") Integer id ) { System.out.println("get"+id); return "hello"; } @RequestMapping(value="book/{bid}" , method = RequestMethod.PUT) public String updateBook(@PathVariable("bid") Integer id ) { System.out.println("update"+id); return "hello"; } @RequestMapping(value="book/{bid}" , method = RequestMethod.DELETE) public String deleteBook(@PathVariable("bid") Integer id ) { System.out.println("delete"+id); return "hello"; } @RequestMapping(value="book" , method = RequestMethod.POST) public String addBook( ) { System.out.println("add"); return "hello"; } }
页面代码
《%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 《html> 《body> 《h2>Hello World!《/h2> 《/body> 《a href="book/1" >查询1号图书《/a>《!-- "book/1"不能写/ 写/要加项目名 默认是GET请求--> 《form action="book" method="post">《!-- post请求 --> 《input type="submit" value="添加1号图书"> 《/form> 《form action="book/1" method="delete">《!-- delete请求 --> 《input type="submit" value="添加1号图书"> 《/form> 《form action="book/1" method="put">《!-- put请求 --> 《input type="submit" value="更新1号图书"> 《/form> 《/html>
从页面发起put、DELETE 形式的请求 利用过滤器HiddenHttpMethodFilter 来配置 Spring提供了对Rest风格的支持
- SpringMVC中有一个Filter:它可以把普通的请求转化为规定形式的请求 POST->delete/put
<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>
- jsp的代码
《%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 《html> 《body> 《h2>Hello World!《/h2> 《/body> 《a href="book/1" >查询1号图书《/a>《!-- "book/1"不能写/ 写/要加项目名 默认是GET请求--> 《form action="book" method="post">《!-- post请求 --> 《input type="submit" value="添加1号图书"> 《/form> 《form action="book/1" method="post">《!-- delete请求 --> 《input name="_method" value="delete" /> 《input type="submit" value="添加1号图书"> 《/form> 《form action="book/1" method="post">《!-- put请求 --> 《input name="_method" value="put" /> 《input type="submit" value="更新1号图书"> 《/form> 《/html>
因为Tomcat高版本问题 需要加isErrorPage="true"
瞒天过海原理
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String paramValue = request.getParameter(this.methodParam); //判断如果表单是一个post 且_method有值 if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) { String method = paramValue.toUpperCase(Locale.ENGLISH);//delete put 都转为大写 HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);//实现了HttpServletRequest 且复写了request.getMethod() ; 得到的值是_method的值 filterChain.doFilter(wrapper, response); } else { //否则直接放行 filterChain.doFilter(request, response); } }
高版本 Tomcat 8.0以上 Rest会405