springboot swagger
1. 介紹
目前大部分項目都是前后端分離,或者是以服務的形式暴露RESTful API接口,但是如何向調用方提供接口說明文檔?如何快速單元測試我們的接口?如何在更改了接口之后快速的更新于接口文檔中?帶著這些問題,引入swagger。
特性:
- swagger可以生成互動性的API控制臺
- 調用者和開發者嘗試API
- 形成一種合作契約,讓團隊更加敏捷的開發
- 對代碼有一定的入侵型
2. 集成
2.1 POM配置
pom中增加swagger的依賴
<!--Swagger Restful UI 集成依賴-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.4.0</version>
</dependency>
2.2 開啟swagger
在入口程序的啟動類(Application.java)上增加@EnableSwagger2的注解
@EnableSwagger2
@SpringBootApplication
public class Application {
public static void main(String[] args) {
//啟動入口
SpringApplication.run(Application.class, args);
}
}
2.3 配置swagger
@Configuration
public class AppConfig {
/**
* 創建swagger ui的摘要
* @return
*/
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
// 掃描的class的包路徑
.apis(RequestHandlerSelectors.basePackage("pers.mateng.demo.springboot"))
// 只掃描類上有API注解的class
// .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
// 只掃描方法上有ApiOperation注解的方法
// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
/**
* swagger ui的標題信息
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("標題")
.description("副標題")
.version("1.0")
.build();
}
}
2.4 聲明 API
修改UserController,注意類注解(@Api)和方法注解(@ApiOperation)
@RestController
@RequestMapping(path="user")
@Api(tags="用戶管理")
public class UserController {
@Autowired
private UserDao userDao;
@ApiOperation(value="查詢用戶", notes="測試無請求參數的swagger-ui")
@RequestMapping(method=RequestMethod.GET)
public List<User> findAll() {
return userDao.findAll();
}
@ApiOperation(value="增加用戶-測試1", notes="測試application/x-www-form-urlencoded形式提交參數")
@RequestMapping(method=RequestMethod.POST)
public User add(@ModelAttribute User user) {
return userDao.save(user);
}
@ApiOperation(value="修改用戶-測試1", notes="測試application/json形式提交參數")
@RequestMapping(path="/{id}", method=RequestMethod.PUT)
public User update1(@ApiParam(value="用戶id") @PathVariable Long id, @RequestBody User user) {
User temp = userDao.findOne(id);
if(temp != null) {
temp.setName(user.getName());
temp.setAge(user.getAge());
return userDao.save(temp);
}
return null;
}
@ApiOperation(value="根據id查詢用戶", notes="測試path參數提交")
@GetMapping(path="/{id}")
public User findById(@ApiParam(value="用戶id") @PathVariable Long id) {
return userDao.findOne(id);
}
@ApiOperation(value="根據id刪除用戶", notes="測試path參數提交")
@DeleteMapping(path="/{id}")
public Boolean del(@ApiParam(value="用戶id") @PathVariable Long id) {
userDao.delete(id);
return Boolean.TRUE;
}
}
3. 驗證
啟動工程,使用eclipse的run as重新啟動Application的main函數
使用瀏覽器訪問http://localhost:8888/swagger-ui.html。即可查看UserControlerl中暴漏的接口
填寫參數后,點擊 “try it out” 即可發送請求
4. 進階詳解
4.1 @ModelAttribute 的參數說明
在swagger-ui上查看“增加用戶-測試1”接口,發現該接口的描述并不完善,問題如下:
- 所有的請求參數都沒有中文描述
- 增加用戶時參數“id”是不需要的
那么接口調用方是無法更好的理解接口的使用,解決辦法如下
方法一
- 使用 @ApiIgnore,讓 swagger 忽略該實體類的參數
- 使用 @ApiImplicitParams 重新聲明參數的類型、說明、是否必須、參數位置
詳細代碼如下:
@ApiOperation(value="增加用戶-測試2")
@RequestMapping(path="add2", method=RequestMethod.POST)
@ApiImplicitParams({
@ApiImplicitParam(value="用戶名", name="name", required=true, dataType="String", paramType="form"),
@ApiImplicitParam(value="年齡", name="age", required=false, dataType="integer", paramType="form")
})
public User add2(@ApiIgnore @ModelAttribute User user) {
return userDao.save(user);
}
方法二
- 升級 swagger的版本到2.7.0
- 使用 @ApiModelProperty(hidden=true) 隱藏參數
- 使用 @ApiModelProperty(value = "xxx") 描述參數的說明
- 使用 @ApiModelProperty(required=false) 標識參數是否必須輸入
修改實體類User,==注意每個屬性的注解==
@Entity
@Table(name="TB_USER")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="U_ID")
@ApiModelProperty(hidden=true)
private Long id;
@Column(name="U_NAME", nullable = false, length=32, unique=true)
@ApiModelProperty(value = "用戶名稱", required=true)
private String name;
@Column(name="U_AGE", length=4)
@ApiModelProperty(value = "年齡", required=false)
private Integer age;
get/set...
}
4.2 @RequestBody 的參數說明
在 swagger-ui 上查看“修改用戶-測試1”接口,發現該接口的描述并不完善,問題如下:
- 所有的請求參數都沒有中文描述
- 為了追求 RESTful 風格,導致id聲明了兩次,在 Path 和 Resquestbody 中各聲明了一次
所以接口調用方是無法更好的理解接口的使用,解決辦法如下
方法一
不使用@Resquestbody 直接使用@ModelAttribute + @ApiImplicitParams的方法,==也就是4.1章節中的方法一==
代碼如下:
@ApiOperation(value="修改用戶-測試2", notes="測試application/x-www-form-urlencoded形式提交參數")
@RequestMapping(path="update2", method=RequestMethod.PUT)
@ApiImplicitParams({
@ApiImplicitParam(value="用戶id", name="id", required=true, dataType="Integer", paramType="form"),
@ApiImplicitParam(value="用戶名", name="name", required=true, dataType="String", paramType="form"),
@ApiImplicitParam(value="年齡", name="age", required=false, dataType="integer", paramType="form")
})
public User update2(@ApiIgnore @ModelAttribute User user) {
User temp = userDao.findOne(user.getId());
if(temp != null) {
temp.setName(user.getName());
temp.setAge(user.getAge());
return userDao.save(temp);
}
return null;
}
方法二
==也就是4.1章節中的方法二==
- 使用 @ApiModelProperty(hidden=true) 隱藏參數
- 使用 @ApiModelProperty(value = "xxx") 描述參數的說明
- 使用 @ApiModelProperty(required=false) 標識參數是否必須輸入
在實體類 User上增加注解,代碼如下:
@Entity
@Table(name="TB_USER")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="U_ID")
@ApiModelProperty(hidden=true)
private Long id;
@Column(name="U_NAME", nullable = false, length=32, unique=true)
@ApiModelProperty(value = "用戶名稱", required=true)
private String name;
@Column(name="U_AGE", length=4)
@ApiModelProperty(value = "年齡", required=false)
private Integer age;
get/set……
}
4.3 @PathVariable/@RequestParam 的參數說明
在這兩個注解的前面增加swagger的注解@ApiParam(value="xxx")
@DeleteMapping(path="/{id}")
public Boolean del(@ApiParam(value="用戶id") @PathVariable Long id) {
userDao.delete(id);
return Boolean.TRUE;
}
@GetMapping(path="/name")
public String findByName(@ApiParam(value="用戶名") @RequestParam String name) {
return name;
}
4.4 總結
在4.1章節和4.2章節中,處理參數的說明都使用了兩種方法,概括的講,方法一是在方法體的注解上想辦法解決,方法二是在參數的屬性上想辦法解決。
方法一的優缺點分析:
- 缺點:寫的代碼多。
- 優點:適應性好,例如:有多個api接口都需要使用同一個javabean作為入參,但是每個接口實際暴露的參數不一樣。就可以復用同一個javabean,而在各自的方法上處理。
- 優點:對javabean沒有入侵性。
- 適合formdata/x-www-form-urlencoded表單提交。
方法二的優缺點:
- 缺點:復用性差,例如:有多個api接口都需要使用同一個javabean作為入參,但是每個接口實際暴露的參數不一樣。不能復用同一個javabean。
- 缺點:如果一個javabean即作為入參,又作為出參。
- 優點:代碼寫的少。
- 適合application/json提交參數。