軟件測(cè)試 | Spring Boot的RESTful設(shè)計(jì)與實(shí)現(xiàn)
RESTful API 簡(jiǎn)介
RESTful 是一種規(guī)范,符合 RESTful 的 Api 就是 RESTful Api。簡(jiǎn)單的說就是可聯(lián)網(wǎng)設(shè)備利用 HTTP 協(xié) 議通過 GET、POST、DELETE、PUT、PATCH 來操作具有 URI 標(biāo)識(shí)的服務(wù)器資源,返回統(tǒng)一格式的資 源信息,包括 JSON、XML、CSV、ProtoBuf、其他格式。
RESTful 的核心思想是,客戶端發(fā)出的數(shù)據(jù)操作指令都是"動(dòng)詞 + 賓語"的結(jié)構(gòu)。比如,GET /case 這個(gè) 命令,GET 是動(dòng)詞,/case 是賓語。
為什么使用 RESTful API
簡(jiǎn)捷、快速:RESTful 由于其面向資源接口設(shè)計(jì)以及操作抽象簡(jiǎn)化了開發(fā)者的不良設(shè)計(jì),同時(shí)也最 大限度的利用了 http 最初的應(yīng)用協(xié)議設(shè)計(jì)理念。
RESTful 架構(gòu)遵循統(tǒng)一接口原則,不論什么樣的資源,都是通過使用相同的接口進(jìn)行資源的訪問。 接口應(yīng)該使用標(biāo)準(zhǔn)的 HTTP 方法如 GET ,PUT 和 POST ,并遵循這些方法的語義
設(shè)計(jì)規(guī)范
HTTP 請(qǐng)求動(dòng)詞
常用的動(dòng)詞有以下5個(gè)

HTTP響應(yīng)狀態(tài)碼

Spring Boot 實(shí)現(xiàn) RESTful API
我們可以通過 Spring Boot 注解來實(shí)現(xiàn) RESTful API 。
SPRING BOOT 注解
本章節(jié)需要編寫的是對(duì)一個(gè)用戶的增刪改查操作,如下表是一個(gè)非 RESTful 和 標(biāo)準(zhǔn) RESTful 的對(duì)比 表。
下面我們著重介紹下以下兩對(duì)注解。
Controller 與 RestController
Controller 一般應(yīng)用在有返回界面的應(yīng)用場(chǎng)景下。 例如,管理后臺(tái)使用了模板技術(shù)如 thymeleaf 開發(fā), 需要從后臺(tái)直接返回 Model 對(duì)象到前臺(tái),那么這時(shí)候就需要使用 Controller 來注解。
RestController 一般應(yīng)用在只有接口的應(yīng)用場(chǎng)景下. 例如開發(fā)前后端分離的項(xiàng)目時(shí),通過 Ajax 請(qǐng)求服務(wù) 端接口,那么接口就使用 RestController 統(tǒng)一注解。
需要注意的是 RestController 是 Controller 的子集。RestController 是 Spring4 后新加的注解,從 RestController 注解源碼可以看出 RestController 是 Controller 和 ResponseBody 兩個(gè)注解的結(jié)合體,即 Controller=RestController+ResponseBody。
RestController注解源碼
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Controller@ResponseBodypublic @interface RestController {@AliasFor(
annotation = Controller.class
)
String value() default "";}
RequestMapping 與 GetMapping/PostMapping/PutMapping/DeleteMapping
RequestMapping 和GetMapping/PostMapping/PutMapping/DeleteMapping 作用一樣,其實(shí)可以相互替 換,后者是前者的簡(jiǎn)化版本。
GetMapping 其實(shí)就等于將 RequestMapping 注解的 method 屬性設(shè)置為 GET,PostMapping 其實(shí)就等 于將 RequestMapping 注解的 method 屬性設(shè)置為 POST,PutMapping、DeleteMapping 其實(shí)就等于將 RequestMapping 注解的 method 屬性分別設(shè)置為 PUT、DELETE。
也就是說GetMapping、PostMapping、PutMapping、DeleteMapping 是 RequestMapping 的子集。 我們來看看 RequestMapping 的源碼:
@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Mappingpublic @interface RequestMapping {
String name() default "";
//請(qǐng)求URI
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
//請(qǐng)求類型,如 GET、POST、PUT、DELETE 等
RequestMethod[] method() default {};
//請(qǐng)求參數(shù)中必須包含某些參數(shù)值,才讓該方法處理。
String[] params() default {};
//請(qǐng)求參數(shù)中必須包含某些指定的header值,才能讓該方法處理請(qǐng)求。
String[] headers() default {};
//請(qǐng)求的內(nèi)容類型(Content-Type),例如application/json, text/html;
String[] consumes() default {};
//響應(yīng)的內(nèi)容類型,僅當(dāng) request 請(qǐng)求頭中的( Accept )類型中包含該指定類型才返回;
String[] produces() default {};}
示例說明:
API形式
示例代碼
新增 2 個(gè)文件: dto/UserDto.java 和 controller/HogwartsTestUserController.java ,其中 UserController 類中包括了對(duì)用戶的 4 個(gè)操作增刪改查。
public class UserDto {
private String name;
private String pwd;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
/**
* RESTful API 風(fēng)格示例 對(duì)資源 user 進(jìn)行操作
* 本示例沒有使用數(shù)據(jù)庫,也沒有使用 service 類來輔助完成,所有操作在本類中完成
* */
@Api(tags = "霍格沃茲測(cè)試學(xué)院-用戶管理模塊", hidden = true)
@RestController
@RequestMapping("/api/user")
public class HogwartsTestUserController {
/**
* 查詢用戶列表,返回一個(gè)JSON數(shù)組
* */
@ApiOperation("查詢用戶列表")
@GetMapping("/users")
@ResponseStatus(HttpStatus.OK)
public Object getUsers(){
List<UserDto> list = getData();
return list;
}
/**
* 查詢用戶信息,返回一個(gè)新建的JSON對(duì)象
* */
@ApiOperation("查詢用戶信息")
@GetMapping("/users/{id}")
@ResponseStatus(HttpStatus.OK)
public Object getUser(@PathVariable("id") Long id){
if(Objects.isNull(id)){
return null;
}
List<UserDto> list= getData();
UserDto userDto = getUserDto(id, list);
return userDto;
}
/**
* 新增用戶
* */
@ApiOperation("新增用戶")
@PostMapping("/users")
@ResponseStatus(HttpStatus.CREATED)
public Object addUser(@RequestBody UserDto user){
List<UserDto> list= getData();
list.add(user);//模擬向列表中增加數(shù)據(jù)
return user;
}
/**
* 編輯用戶
* */
@ApiOperation("編輯用戶")
@PutMapping("/users/{id}")
@ResponseStatus(HttpStatus.CREATED)
public Object editUser(@PathVariable("id") Long id,@RequestBody UserDto user)
{
List<UserDto> list = getData();
for (UserDto userDto:list) {
if(id.equals(userDto.getId())){
userDto = user;
break;
}
}
return user;
}
/**
* 刪除用戶
* */
@ApiOperation("刪除用戶")
@DeleteMapping("/users/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public Object deleteUser(@PathVariable("id") Long id){
List<UserDto> list = getData();
UserDto userDto = getUserDto(id, list);
return userDto;
}
/**
* 模擬數(shù)據(jù)
* */
private List<UserDto> getData(){
List<UserDto> list=new ArrayList<>();
UserDto userDto = new UserDto();
userDto.setId(1L);
userDto.setName("admin");
userDto.setPwd("admin");
list.add(userDto);
userDto = new UserDto();
userDto.setId(2L);
userDto.setName("HogwartsTest1");
userDto.setPwd("HogwartsTest1");
list.add(userDto);
userDto = new UserDto();
userDto.setId(3L);
userDto.setName("HogwartsTest2");
userDto.setPwd("HogwartsTest2");
list.add(userDto);
userDto = new UserDto();
userDto.setId(4L);
userDto.setName("HogwartsTest3");
userDto.setPwd("HogwartsTest3");
list.add(userDto);
return list;
}
/**
* 模擬根據(jù)id查詢列表中的數(shù)據(jù)
* @param id
* @param list
* @return
*/
private UserDto getUserDto( Long id, List<UserDto> list) {
UserDto UserDto = null;
for (UserDto user : list) {
if (id.equals(user.getId())) {
UserDto = user;
break;
}
}
return UserDto;
}
}
使用 Postman 測(cè)試
獲取全部資源 獲取所有用戶
GET?http://127.0.0.1:8081/api/user/users/
響應(yīng)參數(shù)
[
{
"id": 1,
"name": "admin",
"pwd": "admin"
},
{
"id": 2,
"name": "HogwartsTest1",
"pwd": "HogwartsTest1"
},
{
"id": 3,
"name": "HogwartsTest2",
"pwd": "HogwartsTest2"
},
{
"id": 4,
"name": "HogwartsTest3",
"pwd": "HogwartsTest3"
}
]
獲取單個(gè)資源 獲取用戶
GET?http://127.0.0.1:8081/api/user/users/3
新增一個(gè)資源 新增一個(gè)用戶
POST?http://127.0.0.1:8081/api/user/users
請(qǐng)求參數(shù)
{
"id": 4,
"name": "HogwartsTest5",
"pwd": "HogwartsTest5"
}
編輯更新一個(gè)資源
PUT?http://1270.0.1:8081/api/user/users/3
請(qǐng)求參數(shù)
{
"name": "HogwartsTest6",
"pwd": "HogwartsTest6"
}
刪除一個(gè)資源
DELETE?http://1270.0.1:8081/aip/user/users/3
常用配置項(xiàng)
下面介紹一些 Spring Boot 常用配置項(xiàng),通過這些常用配置項(xiàng),我們可以修改 Spring Boot 的一些默認(rèn) 配置。 修改服務(wù)默認(rèn)端口:
server:
?port:8093
指定服務(wù)名稱:
spring:
application:
name:aitest
多環(huán)境配置
spring:
profiles:
active:dev

如上圖新建 application-dev.yml、application-test.yml、application-uat.yml、application-prod.yml 四套配 置文件環(huán)境,我們?cè)谒奶着渲梦募袑⒃O(shè)置服務(wù)端口號(hào)分別設(shè)置為 8091/8092/8093/8094,然后啟動(dòng) 服務(wù),可以看到服務(wù)的端口號(hào)會(huì)和 application.yml 中激活的環(huán)境配置信息一致.