問題:前後端分離時代的到來
-
前端需要測試後端資料
-
後端提供介面,實時更新介面的改動
一、Swagger簡介
-
號稱世界上最流行的api框架
-
Restful api文件線上自動生成工具-->api文件與api定義同步更新
-
直接執行,可以線上測試api介面
-
支援多種語言(java、php)
在專案中使用swagger需要springfox jar包
- swagger2
- swagger ui
二、springboot整合swagger
-
新建springboot專案
-
匯入jar包
<!--swaggerjar包--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency>
-
編寫一個helloworld
package com.kj.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class SwaggerController { @RequestMapping("/hello") public String hello(){ return "hello"; } }
-
配置swagger
import org.springframework.context.annotation.Configuration; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 //開啟swagger public class SwaggerConfig { }
啟動類加上
@EnableSwagger2
註解(遇到Unable to infer base url.
bug時加入,可以解決)package com.kj; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import springfox.documentation.swagger2.annotations.EnableSwagger2; @SpringBootApplication @EnableSwagger2 public class SwaggerDemoApplication { public static void main(String[] args) { SpringApplication.run(SwaggerDemoApplication.class, args); } }
-
啟動執行
訪問localhost/swagger-ui.html。沒有配置port的是這個地址localhost:8080/swagger-ui.html
swagger-ui.html所在檔案
三、配置swagger
1、配置ApiInfo
swagger需要一個docket例項
可以看到docket的建構函式,需要一個DocumentationType
public Docket(DocumentationType documentationType) {
this.apiInfo = ApiInfo.DEFAULT;
this.groupName = "default";
this.enabled = true;
this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
this.applyDefaultResponseMessages = true;
this.host = "";
this.pathMapping = Optional.absent();
this.apiSelector = ApiSelector.DEFAULT;
this.enableUrlTemplating = false;
this.vendorExtensions = Lists.newArrayList();
this.documentationType = documentationType;
}
而DocumentationType有三個預設的值
public class DocumentationType extends SimplePluginMetadata {
public static final DocumentationType SWAGGER_12 = new DocumentationType("swagger", "1.2");
public static final DocumentationType SWAGGER_2 = new DocumentationType("swagger", "2.0");
public static final DocumentationType SPRING_WEB = new DocumentationType("spring-web", "1.0");
......
}
所以我們可以這樣向容器中建立一個docket
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2);
}
此時改配置資訊,呼叫docket的函式即可。
比如修改swagger的api資訊,我們需要更改ApiInfo
相關原始碼
public Docket(DocumentationType documentationType) {
this.apiInfo = ApiInfo.DEFAULT; //api描述
this.groupName = "default";
this.enabled = true;
this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
this.applyDefaultResponseMessages = true;
this.host = "";
this.pathMapping = Optional.absent();
this.apiSelector = ApiSelector.DEFAULT;
this.enableUrlTemplating = false;
this.vendorExtensions = Lists.newArrayList();
this.documentationType = documentationType;
}
//預設的apiInfo
static {
DEFAULT = new ApiInfo("Api Documentation",
"Api Documentation",
"1.0", "urn:tos",
DEFAULT_CONTACT,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
//作者資訊
public static final Contact DEFAULT_CONTACT = new Contact("", "", "");
這時候為我們自己的docket注入我們們自己的apiInfo
即可
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo());
}
private static ApiInfo getApiInfo(){
return new ApiInfo("KJ Api檔案",
"swagger測試",
"1.0",
"https://blog.csdn.net/KJ_Study",
new Contact("KJ", "https://blog.csdn.net/KJ_Study", "qi1638629056@163.com"),
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
結果如下(其實這個基本沒任何效率上的作用)
2、配置掃描介面
有一個方法Docket.select()
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
.select()
.build();
}
只能build兩個方法apis與paths
配置掃描目標
有掃描全部any
,一個都不掃描none
,基於包掃描basePackage
,通過方法註解掃描(掃描有這個註解的方法,可以自己加入GetMapper.class的引數),通過類註解掃描
用的多的還是basePackage
我們指定一個掃描包
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.kj.controller")) //RequestHandlerSelectors配置掃描介面的方式
.build();
}
結果
3、過濾路徑
掃描帶有/kj/ url的api,我們只有一個/hello請求,所以不會有任何api
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.kj.controller"))
.paths(PathSelectors.ant("/kj/**"))
.build();
}
4、配置是否啟用swagger
將docket的enabled屬性改為false即可
//docket的部分原始碼
public Docket(DocumentationType documentationType) {
this.apiInfo = ApiInfo.DEFAULT;
this.groupName = "default";
this.enabled = true; //是否使用swagger
this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
this.applyDefaultResponseMessages = true;
this.host = "";
this.pathMapping = Optional.absent();
this.apiSelector = ApiSelector.DEFAULT;
this.enableUrlTemplating = false;
this.vendorExtensions = Lists.newArrayList();
this.documentationType = documentationType;
}
public Docket enable(boolean externallyConfiguredFlag) {
this.enabled = externallyConfiguredFlag;
return this;
}
所以我們enable一下
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.kj.controller")) //RequestHandlerSelectors配置掃描介面的方式
.build()
.enable(false);
}
實際使用:我們通過外部的環境來判斷是否呼叫swagger
@Bean
public Docket docket(Environment environment){
//設定顯示要呼叫swagger的環境,可以有多個值
Profiles profiles = Profiles.of("dev");
//判斷當前的環境與指定的是否一樣
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.kj.controller")) //RequestHandlerSelectors配置掃描介面的方式
.build()
.enable(flag);
}
我們有多個配置檔案,一個用於開發,一個用於部署
5、配置api文件的分組
主要的是groupName
public Docket(DocumentationType documentationType) {
this.apiInfo = ApiInfo.DEFAULT;
this.groupName = "default";
this.enabled = true;
this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
this.applyDefaultResponseMessages = true;
this.host = "";
this.pathMapping = Optional.absent();
this.apiSelector = ApiSelector.DEFAULT;
this.enableUrlTemplating = false;
this.vendorExtensions = Lists.newArrayList();
this.documentationType = documentationType;
}
@Bean
public Docket docket(Environment environment){
Profiles profiles = Profiles.of("dev");
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.kj.controller"))
.build()
.enable(flag)
.groupName("KJ");
}
我們可以看到一個docket一個分組。要想要多個我們再建立幾個docket即可。
注意組名不能相同,如果相同spring會報bug並結束程式
@Bean
public Docket docket1() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
.groupName("A");
}
@Bean
public Docket docket2() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
.groupName("B");
}
@Bean
public Docket docket3() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
.groupName("C");
}
不同後端開發人員選擇自己的組,就可以只看到自己的api
6、實體類配置
只要返回值中存在,就會被swagger掃描
編寫一個pojo
package com.kj.pojo;
public class User {
private String username;
private String password;
}
編寫一個方法
@RestController
public class SwaggerController {
@RequestMapping("/hello")
public String hello(){
return "hello";
}
@PostMapping("/user")
public User user(){
return new User();
}
}
我們也可以在實體類加上注註釋(在顯示時,只顯示註解配置的內容),顯不顯示與這個註解無關
package com.kj.pojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel("實體類")
public class User {
@ApiModelProperty("使用者名稱")
public String username;
@ApiModelProperty("密碼")
private String password;
}
可以看到私有方法是看不到的
同樣我們也可以給方法加註釋,或者給引數加註釋
@RestController
public class SwaggerController {
@ApiOperation("哈嘍方法")
@RequestMapping("/hello")
public String hello(){
return "hello";
}
@PostMapping("/user")
public User user(){
return new User();
}
@GetMapping("/hello2")
public String hello2(@ApiParam("使用者名稱") String name){
return "hello";
}
}
四、傳送請求
下面就可以看到結果了