1 REST 的概念

REST 为“Representational State Transfer”的缩写,中文释义为“表现层状态转换”,REST 不是一种标准,而是一种设计风格。是目前最流行的一种互联网软件架构风格。它倡导结构清晰、符合标准、易于理解、扩展方便的 Web 架构体系,主张严格按照 HTTP 协议中定义的规范设计结构严谨的 Web 应用架构体系。由于 REST 所倡导的理念让 Web 应用更易于开发和维护,更加优雅简洁,所以正得到越来越多网站的采用。

  • 资源(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 用来删除资源
HTTP 方法名使用场景资源操作是否幂等是否安全
GET从服务器取出资源(一项或多项)SELECT
POST在服务器新建一个资源INSERT
PUT在服务器更新资源(客户端提供完整资源数据)UPDATE
DELETE从服务器删除资源DELETE
  • 幂等性:对同一 REST 接口的多次访问,得到的资源状态是相同的。
  • 安全性:对该 REST 接口访问,不会使服务器端资源的状态发生改变。

RESTful:就是符合 REST 原则的架构方式即可称为 RESTful。

2 REST 风格的 URL 请求

一般在非 RESTful 风格设计的应用中基本上只使用 POST、GET 类型的 HTTP 动作方法,而在 RESTful 风格设计的应用中充分利用了 HTTP 协议的另外动作方法,统一了数据操作的接口,使得 URL 请求变得简洁化、透明化。

image

百度百科的请求地址:
SpringMVC-4 实现 RESTful 风格.png

3 REST 风格 URL 的好处

①、含蓄,安全:使用问号键值对的方式给服务器传递数据太明显,容易被人利用来对系统进行破坏。使用 REST 风格携带数据不再需要明显的暴露数据的名称。

②、风格统一:URL 地址整体格式统一,从前到后始终都使用斜杠划分各个内容部分,用简单一致的格式表达语义。

③、无状态:在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了系统设计的复杂度。

④、严谨,规范:严格按照 HTTP1.1 协议中定义的请求方式本身的语义进行操作。

⑤、简洁,优雅:过去做增删改查操作需要设计 4 个不同的 URL,现在一个就够了。

⑥、丰富的语义:通过 URL 地址就可以知道资源之间的关系,如下所示:

http://localhost:8080/shop
http://localhost:8080/shop/product
http://localhost:8080/shop/product/cellPhone
http://localhost:8080/shop/product/cellPhone/iPhone

4 SpringMVC 对四种请求方式的支持

在@RequestMapping 注解中,我们可以使用 method 熟悉来设置对四种请求的支持:

  • @RequestMapping(value = “/get”,method = RequestMethod.GET)
  • @RequestMapping(value = “/post”,method = RequestMethod.POST)
  • @RequestMapping(value = “/put”,method = RequestMethod.PUT)
  • @RequestMapping(value = “/delete”,method = RequestMethod.DELETE)

但是可以发现上面的注解中大体都是相似了,所以 SpringMVC 给我们提供了简化的版本:

  • @GetMapping(value = “/get”):对应 GET 请求
  • @PostMapping(value = “/post”):对应 POST 请求
  • @PutMapping(value = “/put”):对应 PUT 请求
  • @DeleteMapping(value = “/delete”):对应 DELETE 请求

注:在 SpringMVC 中对 RESTful 支持,主要通过注解来实现,所以下面再介绍三个相关注解:

  • @ResponseBody:响应内容转换为 JSON 格式
  • @RequestBody:请求内容转换为 JSON 格式
  • @RestContrller:等同@Controller+@ResponsrBody

5 HiddenHttpMethodFilter

浏览器对 REST 的支持:

由于浏览器表单只支持 GET 和 POST 请求,所以为了让浏览器实现 DELETE 和 PUT 请求,Spring 为我们提供了一个过滤器:org.springframework.web.filter.HiddenHttpMethodFilter,可以为我们将 GET 和 POST 请求通过过滤器转化成 PUT 或 DELETE 等其他形式。

5.1 HiddenHttpMethodFilter 配置

在 web.xml 中进行配置,拦截所有资源,注意:它必须作用于解决乱码过滤器 CharacterEncodingFilter 的后面,否则处理乱码的过滤器就会失效。

<!-- 配置 org.springframework.web.filter.HiddenHttpMethodFilter 过滤器 -->
<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>

5.2 HiddenHttpMethodFilter 条件及原理

HiddenHttpMethodFilter 处理 put 和 delete 请求的条件:
a>当前请求的请求方式必须为 post
b>当前请求必须传输请求参数 _method

SpringMVC-4 实现 RESTful 风格-1.png

5.3 HiddenHttpMethodFilter 使用

转 PUT 请求

POST 请求转为 PUT 请求非常简单,只需在表单隐藏域中通过 _method 请求参数附带请求方式名称即可。

<!-- Themeleaf 代码 -->
<form th:action="@{/user}" method="post">
  <input type="hidden" name="_method" value="PUT" />
  用户名:<input type="text" name="username" /><br />
  密码:<input type="password" name="password" /><br />
  <input type="submit" value="修改" /><br />
</form>
<!-- JSP 代码 -->
<!-- 将POST请求转为PUT请求 -->
<!-- 表单需要按照HiddenHttpMethodFilter的要求来写 -->
<!-- 要求1:请求本身是必须是POST -->
<!-- 要求2:指定新请求方式的请求参数名称必须是_method -->
<form action="${pageContext.request.contextPath}/update/emp" method="post">
  <input type="hidden" name="_method" value="PUT" />
  .......
</form>

转 DELETE 请求

一般通过点击超链接执行删除操作。

这是一个难点,超链接中没有表单隐藏域,所以需要将超链接转换为表单进行提交,这就需要借助于 JavaScript。

①、在页面上创建一个 action 属性为空的 form 表单

<!-- 将超链接的GET请求转换为DELETE请求 -->
<!-- 1、提供一个通用的表单,用来将GET请求先转换为POST,然后再发送_method请求参数 -->
<!-- action属性不能写死,将来点击哪一个超链接,目标地址就和那个超链接一致 -->
<form id="commonForm" action="" method="post">
  <input type="hidden" name="_method" value="delete" />
</form>

②、给所有超链接绑定单击响应函数

<script type="text/javascript" src="${pageContext.request.contextPath}/script/jquery-1.7.2.js"></script>
<script type="text/javascript">
	$(function () {
		$(".removeEmp").click(function () {
 
			// 在单击响应函数中获取当前点击的超链接的URL地址
			var targetUrl = this.href;
			console.log(targetUrl);
 
			// 通过id获取到表单的jQuery对象,然后设置action属性值,再提交表单
			$("#commonForm").attr("action", targetUrl).submit();
 
			// 取消控件的默认行为
			return false;
		});
	});
</script>

③、超链接

<a class="removeEmp" href="${pageContext.request.contextPath}/remove/emp/1"
  >模拟删除</a
><br />
<a class="removeEmp" href="${pageContext.request.contextPath}/remove/emp/2"
  >模拟删除</a
><br />
<a class="removeEmp" href="${pageContext.request.contextPath}/remove/emp/3"
  >模拟删除</a
><br />

在 web.xml 中注册时,必须先注册 CharacterEncodingFilter,再注册 HiddenHttpMethodFilter。

6 @PathVariable 注解

SpringMVC-2 绑定请求方法 中部分。

@PathVariable 作用:通过 URL 地址携带的数据需要通过@PathVariable 注解来获取。它的用法如下:

<a href="${pageContext.request.contextPath}/emp/2">一个参数情况</a><br />
//请求路径为:/emp/2
@RequestMapping("/emp/{empId}")
public String testPathVariable(@PathVariable("empId") Integer empId) {
    System.out.println("empId="+empId);
    return "result";
}

对于请求路径中有多个数据,@PathVariable 注解也是支持的。

<a href="${pageContext.request.contextPath}/send/message/tom/tell/jerry"
  >多个参数情况</a
><br />
//请求路径为:/send/message/tom/tell/jerry
@RequestMapping("/send/message/{foo}/tell/{bar}")
public String sendMessage(@PathVariable("foo") String foo,
                          @PathVariable("bar") String bar) {
    System.out.println("foo = " + foo);
    System.out.println("bar = " + bar);
    return "target";
}