本文介紹了Spring Boot 開發REST接口最佳實踐,分享給大家,具體如下:
HTTP動詞與SQL命令對應
GET
1
2
3
4
5
|
從服務器獲取資源,可一個或者多個,對應SQL命令中的SELECT GET /users 獲取服務器上的所有的用戶信息 GET /users/ID 獲取指定ID的用戶信息 |
POST
1
2
3
|
在服務器上創建一個新資源,對應SQL命令中的CREATE POST /users 創建一個新的用戶 |
PUT
1
2
3
|
在服務器上更新一個資源,客戶端提供改變后的完整資源,對應SQL命令中的UPDATE PUT /users/ID 更新指定ID的用戶的全部信息 |
DELETE
1
2
3
|
從服務器上刪除一個資源,對應SQL命令中的DELETE DELETE /users/ID 刪除指定ID的用戶信息 |
PATCH
1
2
3
|
在服務器更新一個資源的部分屬性,對應SQL命令中的UPDATE PATCH /users/ID 更新指定ID的用戶的某個屬性 |
URL中的約定
URL中名詞使用復數形式
URL中的名稱是使用單數還是使用復數的問題,爭議由來已久。URL中的名詞一般對應數據庫中的表,表中存儲的是同類數據, 在實踐中我是強制使用復數形式 ,看上去更舒服些。
1
2
3
4
|
/users /users/1 /roles /roles/1 |
至于一些不規則的、不可數的名詞就見仁見智吧。
1
2
3
4
5
6
7
8
|
/heroes /heroes/1 /people /people/1 /foots /foots/1 /feet /feet/1 |
版本
講版本號加入到URL中以應對不兼容的和破壞性的更改。發布新API時,客戶端可以自如的遷移到新API,不會因調用完全不同的新API而陷入窘境。使用直觀的“V”前綴來表示后面的數字是版本號,不需要次級版本號,不應該頻繁的發布API版本。
1
2
|
/edu/v1/users /edu/v1/roles |
對可選的、復雜的參數使用查詢字符串
為了讓URL更小、更簡潔,為資源設置一個基本URL,講可選的、復雜的參數用查詢字符串表示。
1
|
/edu/v1/users?enabled=1&roleid=1 |
提供分頁信息
一次性返回數據庫中的所有的資源不是一個好主意,因此需要提供分頁機制。通常使用數據庫中眾所周知的參數offset和limit
1
|
/edu/v1/users?enabled=1&offset=1&limit=15 |
如果客戶端沒有傳遞這些參數,則應使用默認值,通常offset=0,limit=10。
非資源請求使用動詞
有時API調用并不涉及資源,在這種情況下,服務器執行一個操作病將結果返回給客戶端。
1
|
/edu/v1/calc?p=100 |
考慮特定資源和跨資源搜索
提供對特定止緣的搜索很容易,只需要使用相應的資源集合,并將搜索字符串附加到查詢參數中即可。
1
|
/edu/v1/users?username=李慶海 |
如果需要對所有資源提供全局搜索,則需要使用其他方法。
1
|
/edu/v1/search?key=李慶海 |
響應結果
使用小駝峰命名法作為屬性標識符
通常,RESTful Web服務將被JavaScript編寫的客戶端使用。客戶端會將JSON響應轉換為JavaScript對象,然后調用其屬性。因此,最好遵循JavaScript代碼通用規范。
1
2
3
|
person.year_of_birth // 不推薦,違反JavaScript代碼通用規范 person.YearOfBirth // 不推薦,JavaScript構造方法命名 person.yearOfBirth // 推薦 |
提供分頁信息
返回結果比較多時,應提供分頁信息。
1
2
3
4
5
6
7
8
|
{ "page": 0, "size": 10, "total": 3465, "obj": [ ] } |
Spring MVC開發REST接口
常用注解
@RestController
@RestController是@ResponseBody和@Controller的組合注解。
@RequestMapping
此注解即可以作用在控制器的某個方法上,也可以作用在此控制器類上。當控制器在類級別上添加@RequestMapping注解時,這個注解會應用到控制器的所有處理器方法上。處理器方法上的@RequestMapping注解會對類級別上的@RequestMapping的聲明進行補充。
@PostMapping
組合注解,是@RequestMapping(method =RequestMethod.POST)的縮寫。
@PutMapping
組合注解,是@RequestMapping(method = RequestMethod.PUT)的縮寫。
@PatchMapping
組合注解,是@RequestMapping(method = RequestMethod.PATCH)的縮寫。
@DeleteMapping
組合注解,是@RequestMapping(method = RequestMethod.DELETE)的縮寫。
@GetMapping
組合注解,是@RequestMapping(method = RequestMethod.GET)的縮寫。
@PathVariable
獲取url中的數據。
@RequestParam
獲取請求參數的值。
REST接口及Swagger 編寫API文檔示例
關于Swagger的使用可參考Spring Boot 項目中使用Swagger2 。方法體中的代碼不重要,重要的是方法的簽名以及與HTTP動詞的映射。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
import java.util.Date; import javax.persistence.EntityNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import cn.com.infcn.jianshu.Service.UserService; import cn.com.infcn.jianshu.exception.BizException; import cn.com.infcn.jianshu.exception.LoginNameOrPasswordErrorException; import cn.com.infcn.jianshu.exception.ResourceExistsException; import cn.com.infcn.jianshu.model.User; import cn.com.infcn.jianshu.util.JsonResult; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; /** * 系統用戶Controller * * @author 李慶海 * */ @Api (value = "系統用戶接口" , tags = "系統管理" ) @RestController @RequestMapping ( "/v3/edu/users" ) public class UserController { @Autowired private UserService userService; /** * 添加用戶,注冊 * * @param loginName * 登錄賬號 * @param userName * 用戶名稱 * @param password * 登錄密碼 * @param roleId * 用戶角色 * @return * @throws ResourceExistsException */ @ApiOperation (value = "添加用戶" ) @PostMapping ( "/" ) public JsonResult create( @ApiParam (name = "loginName" , value = "登錄賬號" , required = true ) @RequestParam (required = true ) @RequestBody String loginName, @ApiParam (name = "userName" , value = "用戶名稱" , required = true ) @RequestParam (required = true ) @RequestBody String userName, @ApiParam (name = "password" , value = "登錄密碼" , required = true ) @RequestParam (required = true ) @RequestBody String password, @ApiParam (name = "roleId" , value = "用戶角色編號" , required = true ) @RequestParam (required = true ) @RequestBody String roleId) throws ResourceExistsException { boolean exists = this .userService.exists(loginName); if (exists) { throw new ResourceExistsException(loginName); } User user = userService.create(loginName, password, userName, roleId); return JsonResult.success(user); } /** * 用戶憑借登錄賬號和登錄密碼進行登錄 * * @param loginName * 登錄賬號 * @param password * 登錄密碼 * @throws EntityNotFoundException */ @ApiOperation (value = "根據用戶編號查詢用戶信息" ) @GetMapping ( "/login" ) public JsonResult login( @ApiParam (name = "loginName" , value = "登錄賬號" , required = true ) @RequestParam (required = true ) String loginName, @ApiParam (name = "password" , value = "登錄密碼" , required = true ) @RequestParam (required = true ) String password) throws LoginNameOrPasswordErrorException { User user = this .userService.login(loginName, password); if ( null == user) { throw new LoginNameOrPasswordErrorException(); } return JsonResult.success(user); } /** * 根據用戶編號查詢用戶信息 * * @param id * 用戶編號 * @throws EntityNotFoundException */ @ApiOperation (value = "根據用戶編號查詢用戶信息" ) @GetMapping ( "/{id}" ) public JsonResult read( @ApiParam (name = "id" , value = "用戶編號,主鍵" , required = true ) @PathVariable (required = true ) String id) throws EntityNotFoundException { User user = this .userService.getOne(id); return JsonResult.success(user); } /** * 賬戶注銷,不刪除用戶的數據 * * @param userId * 用戶編號 * @return */ @ApiOperation (value = "注銷賬戶" ) @PatchMapping ( "/{id}" ) public JsonResult cancel( @ApiParam (name = "id" , value = "用戶編號,主鍵" , required = true ) @PathVariable (required = true ) String id) throws EntityNotFoundException { this .userService.cancel(id); return JsonResult.success(); } /** * 重置密碼 * * @param id * 用戶編號 * @param password * 新登錄密碼 * @return */ @ApiOperation (value = "重置密碼" ) @PatchMapping ( "/" ) public JsonResult updatePassword( @ApiParam (name = "id" , value = "用戶編號,主鍵" , required = true ) @RequestParam (required = true ) String id, @ApiParam (name = "password" , value = "新登錄密碼" , required = true ) @RequestParam (required = true ) String password) { this .userService.updatePassword(id, password); return JsonResult.success(); } /** * 多條件組合查詢 * * @param userName * 用戶名稱 * @param roleId * 用戶角色 * @param start * 開始日期 * @param end * 結束日期 * @param page * 分頁,從0開始 * @param size * 每頁的行數,默認10 * @return * @throws BizException */ @ApiOperation (value = "用戶信息查詢" ) @GetMapping ( "/" ) public JsonResult query( @ApiParam (name = "userName" , value = "用戶名稱,查詢關鍵詞" , required = false ) @RequestParam (required = false ) String userName, @ApiParam (name = "roleId" , value = "用戶角色編號" , required = false ) @RequestParam (required = false ) String roleId, @ApiParam (name = "start" , value = "用戶角色編號" , required = false ) @RequestParam (required = false ) Date start, @ApiParam (name = "end" , value = "用戶角色編號" , required = false ) @RequestParam (required = false ) Date end, @ApiParam (name = "page" , value = "分頁,第幾頁,從1開始" , defaultValue = "1" , required = true ) @RequestParam (defaultValue = "1" , required = true ) int page, @ApiParam (name = "size" , value = "每頁的行數,正整數" , defaultValue = "10" , required = true ) @RequestParam (defaultValue = "10" , required = true ) int size) throws BizException { Page<User> datas = this .userService.findDatas(userName, roleId, start, end, page, size); if ( null == datas || null == datas.getContent() || datas.getContent().isEmpty()) { throw new BizException( "用戶不存在" ); } return JsonResult.success(datas); } } |
Swagger2接口文檔效果圖
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://www.jianshu.com/p/1dbb71f78104