REST與RESTful:
REST:表現層狀態轉移,資源在網絡中以某種形式進行狀態轉移。
RESTful是基於REST理念的一套開發風格,是具體的開發規則。
服務器端只返回數據,以json或者xml的格式。
RESTful開發規范:
• 使用URL作為用戶交互入口
• 明確的語義規范(GET|POST|PUT|DELETE)
• 只返回數據(JSON|XML),不包含任何展現
RESTful命名要求:
1.第一個RESTful應用
@Controller @RequestMapping("/restful") //URL中所有的都是名詞 public class RestfulController { @GetMapping(value = "/request",produces = "application/json;charset=utf-8") @ResponseBody public String doGetRequest(){ return "{\"message\":\"測試\"}"; //使用\原義輸出 } }
2.實現RESTful實驗室
一般PC和移動端都可以調用API接口,下面模擬PC端調用,使用Ajax:
通過ajax發送頁面請求:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>RESTful</title> <script src="jquery-3.4.1.min.js"></script> <script> $(function () { $("#btnGet").click(function () { $.ajax({ url : "/restful/request", type : "get", dataType : "json", success : function (json) { $("#message").text(json.message) } }) }) }) </script> </head> <body> <input type="button" id="btnGet" value="發送Get請求"> <h2 id="message"></h2> </body> </html>
因為定義了webapp為靜態文件的根目錄,所以client.html可以直接訪問。
竟然產生了亂碼,查看請求頭,發現采用不正確的字符集。
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>test/html;charset=utf-8</value> <!--通知瀏覽器以這種格式加載數據--> <value>application/json;charset=utf-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
添加以上配置就可以了。(只能解決ajax亂碼問題)
3.RestController注解與路徑變量
(1)RestController
@Controller @RequestMapping("/restful") //URL中所有的都是名詞 public class RestfulController { @GetMapping(value = "/request",produces = "application/json;charset=utf-8") @ResponseBody public String doGetRequest(){ return "{\"message\":\"測試\"}"; //使用\原義輸出 } }
如果我們希望返回純文本數據,我們必須要使用@ResponseBody這個注解。
如果我們使用@RestController這個注解,那么類下面所有方法都是返回純文本數據。
@RestController @RequestMapping("/restful") //URL中所有的都是名詞 public class RestfulController { @GetMapping(value = "/request",produces = "application/json;charset=utf-8") public String doGetRequest(){ return "{\"message\":\"測試\"}"; //使用\原義輸出 } }
@RestController可以幫我們簡化開發。
(2)路徑變量
/request/1 對於放在URL中的變量我們可以稱之為路徑變量。那么如何取值了?
@RestController @RequestMapping("/restful") //URL中所有的都是名詞 public class RestfulController { @GetMapping(value = "/request/{rid}",produces = "application/json;charset=utf-8") public String doGetRequest(@PathVariable("rid") Integer requestId){ System.out.println(requestId); return "{\"message\":\"測試\"}"; //使用\原義輸出 } }
使用@PathVariable路徑變量注解進行接收,而后賦值給方法參數。
4.JSON序列化
(1)引入步驟
導入依賴包:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <!--一定要使用2.9.9之后的版本,否則會有安全問題--> <version>2.9.9</version> </dependency> <!--jackson與目標對象交互的根源--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.9</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.9</version> </dependency>
spring非常智能,只要檢查有jackson-core和jackson-databind這兩個依賴包。
就會自動啟用jackson為我們提供json序列化服務。
創建實體類:
public class Person { private String name; private String address; }
編寫控制器:
@GetMapping("/person/{pid}") public Person findByPersonId(@PathVariable("pid") Integer personId){ Person person = new Person(); if (personId == 1){ person.setName("科比"); person.setAddress("湖北羅田"); } else if (personId == 2){ person.setName("星爺"); person.setAddress("湖北安陸"); } else { person.setName("無名氏"); } return person; }
如果我們返回一個實體對象,並且配置了@RestController或者@ResponseBody,那么jackson就會自動提供序列化服務。
訪問:
(2)返回多個對象
如果一次返回多個對象,我們可以List集合:
@GetMapping("/persons") public List<Person> findPersons(){ List list = new ArrayList(); Person p1 = new Person(); p1.setName("科比"); p1.setAddress("湖北羅田"); Person p2 = new Person(); p2.setName("科比"); p2.setAddress("湖北羅田"); list.add(p1); list.add(p2); return list; }
在前端,我們會收到如下數據:
在頁面中,我們可以通過如下方式進行提取:
$(function () { $("#btnPersons").click(function () { $.ajax({ url : "/restful/persons", type : "get", datatype : "json", success : function (json) { console.info(json) for(var i=0;i<json.length;i++){ var p = json[i]; $("#divPersons").append("<h2>" + p.name + "-" + p.address + "</h2>") } } }) }) })
(3)時間處理
需要注意的是,jackson對時間處理並不友好:
添加事件屬性:
private Date birthday;
如果不做處理,就是直接返回事件戳的形式。
我們只需要添加對應時間注解:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date birthday;
就可以正常輸出了:
還有需要注意的是默認使用格林時間,需要指定時區:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date birthday;
5.瀏覽器的同源策略
同源策略:阻止從一個域加載的腳本去獲取另一個域上的資源。
兩個不同域名的網站不能通過Ajax訪問,這是出於安全的因素考慮。
比如下面兩個地址,雖然本質是一個頁面,但是卻屬於不同源.
只要協議、域名、端口有任何不同,都被當做是不同的域。
瀏覽器Console看到Access-Control-Allow-Origin就代表跨域了。
HTML中允許跨域的標簽:
<img> 顯式遠程圖片
<script> 加載遠程JS
<link> 加載遠程CSS
6.SpringMVC解決跨域
CORS是一種機制,使用額外的HTTP頭通知瀏覽器訪問其他域。
URL響應頭中包含Access-Control-*指明請求允許跨域。
(1)@CrossOrigin - Controller跨域注解
@RestController @RequestMapping("/restful") @CrossOrigin(origins = {"*"}) public class RestfulController { @GetMapping(value = "/request/{rid}",produces = "application/json;charset=utf-8") public String doGetRequest(@PathVariable("rid") Integer requestId){ System.out.println(requestId); return "{\"message\":\"測試\"}"; } }
(2)<mvc:cors> Spring MVC全局跨域配置
<mvc:cors> <!--path哪一個路徑允許跨域訪問--> <!--allowed-origins允許誰進行跨域訪問--> <!--max-age設置緩存時間--> <mvc:mapping path="*" allowed-origins="*"/> </mvc:cors>