本文介紹了Spring Boot 開發(fā)REST接口最佳實(shí)踐,分享給大家,具體如下:
HTTP動詞與SQL命令對應(yīng)
GET
1
2
3
4
5
|
從服務(wù)器獲取資源,可一個(gè)或者多個(gè),對應(yīng)SQL命令中的SELECT GET /users 獲取服務(wù)器上的所有的用戶信息 GET /users/ID 獲取指定ID的用戶信息 |
POST
1
2
3
|
在服務(wù)器上創(chuàng)建一個(gè)新資源,對應(yīng)SQL命令中的CREATE POST /users 創(chuàng)建一個(gè)新的用戶 |
PUT
1
2
3
|
在服務(wù)器上更新一個(gè)資源,客戶端提供改變后的完整資源,對應(yīng)SQL命令中的UPDATE PUT /users/ID 更新指定ID的用戶的全部信息 |
DELETE
1
2
3
|
從服務(wù)器上刪除一個(gè)資源,對應(yīng)SQL命令中的DELETE DELETE /users/ID 刪除指定ID的用戶信息 |
PATCH
1
2
3
|
在服務(wù)器更新一個(gè)資源的部分屬性,對應(yīng)SQL命令中的UPDATE PATCH /users/ID 更新指定ID的用戶的某個(gè)屬性 |
URL中的約定
URL中名詞使用復(fù)數(shù)形式
URL中的名稱是使用單數(shù)還是使用復(fù)數(shù)的問題,爭議由來已久。URL中的名詞一般對應(yīng)數(shù)據(jù)庫中的表,表中存儲的是同類數(shù)據(jù), 在實(shí)踐中我是強(qiáng)制使用復(fù)數(shù)形式 ,看上去更舒服些。
1
2
3
4
|
/users /users/1 /roles /roles/1 |
至于一些不規(guī)則的、不可數(shù)的名詞就見仁見智吧。
1
2
3
4
5
6
7
8
|
/heroes /heroes/1 /people /people/1 /foots /foots/1 /feet /feet/1 |
版本
講版本號加入到URL中以應(yīng)對不兼容的和破壞性的更改。發(fā)布新API時(shí),客戶端可以自如的遷移到新API,不會因調(diào)用完全不同的新API而陷入窘境。使用直觀的“V”前綴來表示后面的數(shù)字是版本號,不需要次級版本號,不應(yīng)該頻繁的發(fā)布API版本。
1
2
|
/edu/v1/users /edu/v1/roles |
對可選的、復(fù)雜的參數(shù)使用查詢字符串
為了讓URL更小、更簡潔,為資源設(shè)置一個(gè)基本URL,講可選的、復(fù)雜的參數(shù)用查詢字符串表示。
1
|
/edu/v1/users?enabled=1&roleid=1 |
提供分頁信息
一次性返回?cái)?shù)據(jù)庫中的所有的資源不是一個(gè)好主意,因此需要提供分頁機(jī)制。通常使用數(shù)據(jù)庫中眾所周知的參數(shù)offset和limit
1
|
/edu/v1/users?enabled=1&offset=1&limit=15 |
如果客戶端沒有傳遞這些參數(shù),則應(yīng)使用默認(rèn)值,通常offset=0,limit=10。
非資源請求使用動詞
有時(shí)API調(diào)用并不涉及資源,在這種情況下,服務(wù)器執(zhí)行一個(gè)操作病將結(jié)果返回給客戶端。
1
|
/edu/v1/calc?p=100 |
考慮特定資源和跨資源搜索
提供對特定止緣的搜索很容易,只需要使用相應(yīng)的資源集合,并將搜索字符串附加到查詢參數(shù)中即可。
1
|
/edu/v1/users?username=李慶海 |
如果需要對所有資源提供全局搜索,則需要使用其他方法。
1
|
/edu/v1/search?key=李慶海 |
響應(yīng)結(jié)果
使用小駝峰命名法作為屬性標(biāo)識符
通常,RESTful Web服務(wù)將被JavaScript編寫的客戶端使用。客戶端會將JSON響應(yīng)轉(zhuǎn)換為JavaScript對象,然后調(diào)用其屬性。因此,最好遵循JavaScript代碼通用規(guī)范。
1
2
3
|
person.year_of_birth // 不推薦,違反JavaScript代碼通用規(guī)范 person.YearOfBirth // 不推薦,JavaScript構(gòu)造方法命名 person.yearOfBirth // 推薦 |
提供分頁信息
返回結(jié)果比較多時(shí),應(yīng)提供分頁信息。
1
2
3
4
5
6
7
8
|
{ "page": 0, "size": 10, "total": 3465, "obj": [ ] } |
Spring MVC開發(fā)REST接口
常用注解
@RestController
@RestController是@ResponseBody和@Controller的組合注解。
@RequestMapping
此注解即可以作用在控制器的某個(gè)方法上,也可以作用在此控制器類上。當(dāng)控制器在類級別上添加@RequestMapping注解時(shí),這個(gè)注解會應(yīng)用到控制器的所有處理器方法上。處理器方法上的@RequestMapping注解會對類級別上的@RequestMapping的聲明進(jìn)行補(bǔ)充。
@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中的數(shù)據(jù)。
@RequestParam
獲取請求參數(shù)的值。
REST接口及Swagger 編寫API文檔示例
關(guān)于Swagger的使用可參考Spring Boot 項(xiàng)目中使用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; /** * 系統(tǒng)用戶Controller * * @author 李慶海 * */ @Api (value = "系統(tǒng)用戶接口" , tags = "系統(tǒng)管理" ) @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); } /** * 用戶憑借登錄賬號和登錄密碼進(jìn)行登錄 * * @param loginName * 登錄賬號 * @param password * 登錄密碼 * @throws EntityNotFoundException */ @ApiOperation (value = "根據(jù)用戶編號查詢用戶信息" ) @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); } /** * 根據(jù)用戶編號查詢用戶信息 * * @param id * 用戶編號 * @throws EntityNotFoundException */ @ApiOperation (value = "根據(jù)用戶編號查詢用戶信息" ) @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); } /** * 賬戶注銷,不刪除用戶的數(shù)據(jù) * * @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 * 結(jié)束日期 * @param page * 分頁,從0開始 * @param size * 每頁的行數(shù),默認(rèn)10 * @return * @throws BizException */ @ApiOperation (value = "用戶信息查詢" ) @GetMapping ( "/" ) public JsonResult query( @ApiParam (name = "userName" , value = "用戶名稱,查詢關(guān)鍵詞" , 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 = "每頁的行數(shù),正整數(shù)" , 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接口文檔效果圖
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://www.jianshu.com/p/1dbb71f78104