SpringBoot開發詳解(八) -- 使用Swagger2構建API文件
API文件
文件在開發中的價值與作用:
作為一個開發人員,平時看得最多的恐怕就是各式各樣的文件了。並且在開發中我們也避免不了的需要自己去書寫文件,比如作為後臺開發人員,我們書寫最多的應該就是介面文件了。前端人員會按照我們給出的文件來進行前端開發,並且按照文件細節來構建不同的傳輸協議,物件定義,欄位解析等等。
我曾長時間的使用EXCEl來書寫介面文件,可是逐漸的也暴露出一些問題:
- 介面過多,每一個介面需要一個入參定義以及出參定義,不同的請求型別。書寫過多,浪費時間。
- 輸出引數型別定義與文件不符,前端外無法解析,耗費時間。
- 介面修改需要同步修改文件,重複工作。
- 多人開發文件常常造成衝突。
為了解決以上所描述的問題,我們引入了Swagger2,它可以減少我們書寫文件的工作量,並且可以保持程式碼與文件的一致性。同時,可以通過頁面測試來直接挑事介面。說了這麼多的好處,我們來看看我們我們應該如何在SpringBoot中如何使用Swagger2吧。
這樣的文件是不是看起來很簡單明瞭呢。
引入Swagger2依賴:
<!--swagger2依賴,構建API文件-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId >
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.2.2</version>
</dependency>
在引入Swagger2的依賴後,我們需要建立一個配置類。這個配置類應該是和你的啟動類是同級的,這裡,我直接在啟動類中進行程式碼書寫了(就是這麼懶……)
/**
* 啟動類
*/
@RequestMapping(value = "/")
@RestController
@SpringBootApplication
@MapperScan(basePackages = "com.zzp.dao")
@Configuration
@EnableSwagger2
public class Round1Application {
@RequestMapping(value = "/",method = RequestMethod.GET)
public String helloWorld(){
return "Hello World";
}
public static void main(String[] args) {
SpringApplication.run(Round1Application.class, args);
}
@Bean
public Docket createApi(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
.apis(RequestHandlerSelectors.basePackage("com.zzp.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("API文件")
.description("API使用即引數定義")
.termsOfServiceUrl("http://blog.csdn.net/qq_31001665")
.contact("ZZP")
.version("0.1")
.build();
}
}
我們通過@Configuration註解,讓Spring啟動時載入配置,通過@EnableSwagger2開啟Swagger。話說一般開慶某個功能都是@EnableXXX的。
apiInfo中的內容是文件的一些基本配置資訊,而createApi中則是確定掃面哪些包下的介面形成文件,以及文件展示哪些資訊。注意這裡是一個Docket的bean。
完成配置類的書寫後我們已經可以直接訪問我們的文件了,啟動專案,訪問
是不是看見如下內容了呢:
沒錯這就是我們的四個controller,每個點選開來就可以看到我們的每一個介面了。不過沒有中文註釋的介面始終對於使用者不太友好,我們接下來的工作就是給每一個介面添加註釋。這裡我們使用@ApiOperation註解來註釋我們介面的一些基本資訊,使用@ApiImplicitParams,@ApiImplicitParam註解來註釋我們的入參資訊。
@RequestMapping("/user")
@RestController
public class UserController {
@Autowired
private UserService userService;
/**
* 新增使用者
* @param tel 註冊手機號
* @param pwd 設定密碼
*/
@ApiOperation(value = "建立使用者",notes = "使用手機以及密碼初始化使用者資訊")
@ApiImplicitParams({
@ApiImplicitParam(name = "tel",value = "使用者手機號",required = true,dataType = "String"),
@ApiImplicitParam(name = "pwd",value = "使用者初始密碼",required = true,dataType = "String")
})
@PostMapping("/createUser")
public void createUser(@RequestParam("tel") String tel, @RequestParam("pwd") String pwd){
userService.createUser(tel,pwd);
}
/**
* 新增使用者2
* @param userInfo
* @Valid新增表單驗證,BindingResult獲取驗證結果
*/
@ApiOperation(value = "建立使用者V2版本",notes = "使用UserInfo物件初始化使用者資訊")
@ApiImplicitParam(name = "userInfo",value = "使用者物件",required = true,dataType = "UserInfo")
@PostMapping("/createUser2")
public String createUser2(@Valid UserInfo userInfo, BindingResult bindingResult){
if (bindingResult.hasErrors()){
return bindingResult.getFieldError().getDefaultMessage();
}
userService.createUser(userInfo.getTel(),userInfo.getPassWord());
return "OK";
}
/**
* 更新使用者資訊
* @param user_id 使用者ID
* @param nickName 暱稱
*/
@PutMapping("/updateUser/{id}")
public void updateUser(@PathVariable("id") String user_id, @RequestParam("nickName") String nickName){
userService.updateUser(user_id,nickName);
}
/**
* 獲取使用者資訊
* @param id 使用者Id
* @return
*/
@GetMapping("/getUser/{id}")
public UserInfo getUser(@PathVariable("id") Integer id){
return userService.getUser(id);
}
/**
* 刪除使用者
* @param id
*/
@DeleteMapping("/deleteUserByUserId/{id}")
public void deleteUserByUserId(@PathVariable("id") Integer id){
userService.deleteUserByUserId(id);
}
/**
* 使用@RequestBody獲取引數,用map型別接收,再取出
* @param reqMap
*/
@PostMapping("/createUserByMap")
public void createUserByMap(@RequestBody Map<String,Object> reqMap){
String tel = reqMap.get("tel").toString();
String pwd = reqMap.get("pwd").toString();
userService.createUser(tel,pwd);
}
}
@RestController
@RequestMapping("/xml")
public class XMLController {
@Autowired
private XMLService service;
@Autowired
private ExceptionHandle handle;
/**
* 更新使用者資訊
* @param user_id 使用者ID
* @param nickName 暱稱
*/
@ApiOperation(value = "更新使用者資訊",notes = "更新使用者暱稱")
@ApiImplicitParams({
@ApiImplicitParam(name = "id",value = "使用者id",required = true,dataType = "String"),
@ApiImplicitParam(name = "nickName",value = "使用者暱稱",required = true,dataType = "String")
})
@PutMapping("/updateUser/{id}")
public Result updateUser(@PathVariable("id") String user_id, @RequestParam("nickName") String nickName){
Result result = ResultUtil.success();
try {
service.updateUser(user_id,nickName);
}catch (Exception e){
result = handle.exceptionGet(e);
}
return result;
// service.updateUser(user_id,nickName);
}
/**
* 獲取使用者資訊
* @param id 使用者Id
* @return
*/
@ApiOperation(value = "獲取使用者資訊",notes = "返回使用者資訊")
@ApiImplicitParam(name = "id",value = "使用者id",required = true,dataType = "Integer",paramType = "path")
@GetMapping("/getUser/{id}")
public Result getUser(@PathVariable("id") Integer id){
Result result = ResultUtil.success();
try {
result.setData(service.getUser(id));
}catch (Exception e){
result = handle.exceptionGet(e);
}
return result;
// return service.getUser(id);
}
/**
* 刪除使用者
* @param tel
*/
@ApiOperation(value = "刪除使用者",notes = "根據使用者id刪除使用者")
@ApiImplicitParam(name = "id",value = "使用者id",required = true,dataType = "Integer")
@DeleteMapping("/deleteUserByUserId/{tel}")
public Result deleteUserByUserId(@PathVariable("tel") String tel){
Result result = ResultUtil.success();
try {
UserInfo user = new UserInfo();
user.setTel(tel);
service.deleteUserByUserId(user);
}catch (Exception e){
result = handle.exceptionGet(e);
}
return result;
// UserInfo user = new UserInfo();
// user.setTel(tel);
// service.deleteUserByUserId(user);
}
/**
* 使用@RequestBody獲取引數,用map型別接收,再取出
* @param reqMap
*/
@ApiOperation(value = "建立使用者V3版本",notes = "返回使用者資訊")
@ApiImplicitParam(name = "Map",value = "map集合",required = true,dataType = "Map")
@PostMapping("/createUserByMap")
public Result createUserByMap(@RequestBody Map<String,Object> reqMap){
Result result = ResultUtil.success();
try {
service.createUser(reqMap);
}catch (Exception e){
result = handle.exceptionGet(e);
}
return result;
// service.createUser(reqMap);
}
}
這裡我給兩個controller都加入了直接配置,因為在使用mybatis後,spring會預設使用mybatis配置,jdbc連結資料庫會報錯:Invalid bound statement (not found): com.zzp.dao.UserInfoMapper.getUser。大家在做專案時,一定要使用一種方法來連結資料庫,不然各種錯誤會一直困擾著你。
我們完成上訴程式碼的新增後就可以在剛才的地址中看到我們配置的介面資訊了
並且我們可以點選 Try it out!來測試我們的介面了。我們這裡使用Get方法來獲取使用者資訊的介面測試一下,發現我們已經獲取了使用者資訊,要注意的是如果你也是直接通過URL路徑中獲取引數,那需要新增paramType = “path”這個引數,不然是無法獲取到id值的。
Swagger2寫在最後的話:
相比較之前我們使用EXCEl來書寫介面文件,Swagger2的確方便了許多,並且書寫量也大大減少,看似使用Swagger2來對API文件進行管理是一個不錯的選擇。其實不然(逃),因為Swagger2對於程式碼的汙染和侵入性我認為太大了。並且你應該也發現了,當你使用Map作為引數時,Swagger2很難對Map內的每一個引數進行說明(你可以寫超多文字描述)。所以在實際開發中,Swagger2的使用並不是很多,如果你是個人開發者,那使用簡單的Swagger2的確可以滿足需求。如果你構建的是龐大的介面系統時。我的建議是使用Swagger2和MarkDown配合完成文件的書寫。MarkDown書寫方便高效,語法簡單,是我們值得學習的。而Swagger2提供介面除錯以及欄位名匹配來保證入參與出參的一致性。