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请求变得简洁化、透明化。
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
浏览器对REST的支持:
由于浏览器表单只支持 GET 和 POST 请求,所以为了让浏览器实现 DELETE 和 PUT 请求,Spring 为我们提供了一个过滤器:org.springframework.web.filter.HiddenHttpMethodFilter,可以为我们将 GET 和 POST 请求通过过滤器转化成 PUT 或 DELETE 等其他形式。
下面是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>
[1]、转PUT请求:
POST请求转为PUT请求非常简单,只需在表单隐藏域中通过_method
请求参数附带请求方式名称即可。
<!-- 将POST请求转为PUT请求 -->
<!-- 表单需要按照HiddenHttpMethodFilter的要求来写 -->
<!-- 要求1:请求本身是必须是POST -->
<!-- 要求2:指定新请求方式的请求参数名称必须是_method -->
<form action="${pageContext.request.contextPath}/update/emp" method="post">
<input type="hidden" name="_method" value="PUT" />
.......
</form>
[2]、转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/>
5、@PathVariable注解
@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";
}