非rest的url寫法:
查詢 GET /user/query?name=tom 詳情 GET /user/getinfo?id=1 創建 POST /user/create?name=tom 修改 POST /user/update?id=1&name=tom 刪除 GET /user/delete?id=1
rest風格的寫法
查詢 GET /user?name=tom 詳情 GET /user/1 創建 POST /user 修改 PUT /user 刪除 DELETE /user/1
rest接口設計參考:https://github.com/huobiapi/API_Docs/wiki/REST_api_reference
https://github.com/huobiapi/API_Docs
coinflext api: https://github.com/coinflex-exchange/API
1、Rest概念,來自百度百科
REST即表述性狀態傳遞(英文:Representational State Transfer,簡稱REST)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟件架構風格。它是一種針對網絡應用的設計和開發方式,可以降低開發的復雜性,提高系統的可伸縮性。
目前在三種主流的Web服務實現方案中,因為REST模式的Web服務與復雜的SOAP和XML-RPC對比來講明顯的更加簡潔,越來越多的web服務開始采用REST風格設計和實現。
2、RESTful API的要求
1)用URL描述資源;
2)使用HTTP方法描述行為;使用HTTP狀態碼來表示不同的結果;
3)使用json來交互數據;
4)RESTful只是一種風格,並不是強制的標准。
總結:使用URL定位資源,使用HTTP方法操作資源。
GET 用來獲取資源;
POST 用來新建資源(也可以用於更新資源);
PUT 用來更新資源;
DELETE 用來刪除資源
3、Glory of REST
REST是一種軟件接口設計的模型。REST 成熟度模型:(搜索關鍵字:steps toward the glory of REST)
level0: 使用http作為傳輸方式;
level1: 引入資源概念,每個資源都有對應的URL;
level2: 使用http方法進行不同的操作,使用http狀態碼來表示不同的結果。
level3: 使用超媒體,在資源的表達中包含了鏈接信息。
4、springmvc/springboot開發restful API
IndexController
@RestController public class IndexController { @Autowired private UserService userService; @GetMapping("/user/{id}") public Object getUserById(@PathVariable Integer id) { return userService.getUserById(id); } }
測試結果:
5、使用MockMVC 編寫測試用例(單元測試)
參考:https://www.cnblogs.com/xy-ouyang/p/10681965.html
選中IndexController,右鍵/new/Junit Test Case
測試用例代碼:
package com.imooc.controller; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; /** * @author oy * @date 2019年6月22日 下午11:14:56 * @version 1.0.0 */ @RunWith(SpringRunner.class) @SpringBootTest public class IndexControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mocMvc; @Before public void setUp() throws Exception { mocMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void testGetUserById() throws Exception { String mvcResult = mocMvc.perform(MockMvcRequestBuilders.get("/user/1") .contentType(MediaType.APPLICATION_FORM_URLENCODED)) .andDo(MockMvcResultHandlers.print()) // 打印信息 .andExpect(MockMvcResultMatchers.status().isOk()) // 期望返回的狀態碼為200 .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(2)) // 期望返回的json數據中有兩個字段 .andExpect(MockMvcResultMatchers.jsonPath("$.username").value("張三")) // 期望返回的json數據中username字段的值為"張三" .andReturn().getResponse().getContentAsString(); System.out.println("mvcResult: " + mvcResult); } }
控制台打印結果:
MockHttpServletRequest: HTTP Method = GET Request URI = /user/1 Parameters = {} Headers = {Content-Type=[application/x-www-form-urlencoded]} Handler: Type = com.imooc.controller.IndexController Method = public java.lang.Object com.imooc.controller.IndexController.getUserById(java.lang.Integer) Async: Async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: Attributes = null MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[application/json;charset=UTF-8]} Content type = application/json;charset=UTF-8 Body = {"username":"張三","password":"123"} Forwarded URL = null Redirected URL = null Cookies = [] mvcResult: {"username":"張三","password":"123"}
測試用例的代碼簡潔寫法:使用靜態導入
package com.imooc.controller; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; /** * @author oy * @date 2019年6月22日 下午11:14:56 * @version 1.0.0 */ @RunWith(SpringRunner.class) @SpringBootTest public class IndexControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mocMvc; @Before public void setUp() throws Exception { mocMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void testGetUserById() throws Exception { String mvcResult = mocMvc.perform(get("/user/1") .contentType(MediaType.APPLICATION_FORM_URLENCODED)) .andDo(print()) // 打印信息 .andExpect(status().isOk()) // 期望返回的狀態碼為200 .andExpect(jsonPath("$.length()").value(2)) // 期望返回的json數據中有兩個字段 .andExpect(jsonPath("$.username").value("張三")) .andReturn().getResponse().getContentAsString(); System.out.println("mvcResult: " + mvcResult); } }
6、@PageableDefault指定默認的分頁參數
測試代碼:
@RunWith(SpringRunner.class) @SpringBootTest public class IndexControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mocMvc; @Before public void setUp() throws Exception { mocMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void testGetUserById() throws Exception { String mvcResult = mocMvc.perform(get("/user/1") // .param("page", "2") // .param("size", "10") // .param("sort", "id,desc") .contentType(MediaType.APPLICATION_FORM_URLENCODED)) .andDo(print()) // 打印信息 .andExpect(status().isOk()) // 期望返回的狀態碼為200 .andExpect(jsonPath("$.length()").value(2)) // 期望返回的json數據中有兩個字段 .andExpect(jsonPath("$.username").value("張三")) .andReturn().getResponse().getContentAsString(); System.out.println("mvcResult: " + mvcResult); } }
IndexController
@RestController public class IndexController { @Autowired private UserService userService; @GetMapping("/user/{id}") public Object getUserById(@PathVariable Integer id, @PageableDefault(page = 1, size = 10, sort = "id,asc") Pageable pageable) { String str = ReflectionToStringBuilder.toString(pageable, ToStringStyle.MULTI_LINE_STYLE); System.out.println(str); return userService.getUserById(id); } }
控制台打印結果:
org.springframework.data.domain.PageRequest@7d522180[ sort=id,asc: ASC page=1 size=10 ]
7、測試用例中jsonpath的用法
github上面搜索jsonpath ==> https://github.com/json-path/JsonPath
8、@PathVariable 以及url映射中使用正則表達式
@GetMapping("/user/{id:\\d+}") public Object getUserById(@PathVariable Integer id) { return userService.getUserById(id); }
此時,請求url為 /user/a 時,報404。
參考:
1)詳解REST架構風格:http://www.uml.org.cn/zjjs/201805142.asp
2)REST,以及RESTful的講解:https://blog.csdn.net/qq_21383435/article/details/80032375