一、問題描述
隨著互聯(lián)網(wǎng)技術(shù)的發(fā)展,現(xiàn)在的網(wǎng)站架構(gòu)基本都由原來的后端渲染,變成了:前端渲染、先后端分離的形態(tài),而且前端技術(shù)和后端技術(shù)在各自的道路上越走越遠(yuǎn)。 前端和后端的唯一聯(lián)系,變成了API接口;API文檔變成了前后端開發(fā)人員聯(lián)系的紐帶,變得越來越重要,swagger就是一款讓你更好的書寫API文檔的框架,而且swagger可以完全模擬http請(qǐng)求,入?yún)⒊鰠⒑蛯?shí)際情況差別幾乎為零。
沒有API文檔工具之前,大家都是手寫API文檔的(維護(hù)起來相當(dāng)困難),在什么地方書寫的都有,有在confluence上寫的,有在對(duì)應(yīng)的項(xiàng)目目錄下readme.md上寫的,每個(gè)公司都有每個(gè)公司的玩法,無所謂好壞。但是能稱之為“框架”的,估計(jì)也只有swagger了
二、使用步驟
- 創(chuàng)建springboot項(xiàng)目配置pom.xml
<dependency>
<!--添加lombok就可以不用再寫set,get方法-->
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
- 配置啟動(dòng)類
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 創(chuàng)建Swagger的配置類
package com.example.config;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Autowired
Environment environment;
//配置Docket以配置Swagger具體參數(shù)
//在不同生產(chǎn)模式下的操作,
// @Bean
// public Docket docket(){
// Profiles profiles=Profiles.of("dev","test");
// boolean isEnable = environment.acceptsProfiles(profiles);
// return new Docket(DocumentationType.SWAGGER_2)
// .ignoredParameterTypes(Integer.class,Long.class, HttpSession.class)
// .enable(isEnable);
// }
// @Bean
// public Docket docketUser(){
// Parameter token= new ParameterBuilder().name("token")
// .description("用戶登錄令牌")
// .parameterType("header")
// .modelRef(new ModelRef("String"))
// .required(true)
// .build();
// List<Parameter> parameters=new ArrayList<>();
// parameters.add(token);
// return new Docket(DocumentationType.SWAGGER_2)
// .globalOperationParameters(parameters);
// }
//基于包
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
// return new Docket(DocumentationType.SWAGGER_2)
// .select()
// .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
// //paths可以進(jìn)行篩選想要的方法
// .paths(PathSelectors.ant("/hello/**"))
// .build();
}
//基于方法
// @Bean
// public Docket docket(){
// return new Docket(DocumentationType.SWAGGER_2)
// .select()
// .apis(RequestHandlerSelectors.withMethodAnnotation(GetMapping.class)).build();
// }
private ApiInfo apiInfo(){
Contact contact=new Contact("小謝","aaa.com","1787798327@qq.com");
return new ApiInfo("Swagger學(xué)習(xí)接口文檔",
"這是學(xué)習(xí)swagger時(shí)生成的文檔信息",
"v1.0",
"http://xietongxue.top:8090",
contact,
"",
"",
new ArrayList<>()
);
}
}
- 創(chuàng)建User
package com.example.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("用戶實(shí)體")
public class User {
@ApiModelProperty(value = "用戶id",example = "0")
private Integer id;
@ApiModelProperty("用戶名")
private String username;
@ApiModelProperty(value = "用戶年齡",example = "1")
private String age;
}
- 創(chuàng)建Controller
package com.example.controller;
import com.example.model.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
@Api(tags = "用戶相關(guān)的請(qǐng)求")
@RestController
@RequestMapping("/user")
public class UserController {
@ApiOperation("獲取用戶信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "username",value = "用戶名",
dataType = "string",paramType = "header",defaultValue = "zhangsan",example = "lisi"),
@ApiImplicitParam(name = "password",value = "用戶密碼")
})
@GetMapping
public String getUser(String username,String password){
return "user";
}
@ApiOperation("添加用戶")
@PostMapping
public User postUser(User user){
return user;
}
@ApiOperation("刪除用戶")
@DeleteMapping
public User delUser(@RequestBody User user){
return user;
}
// @GetMapping
// public String getUser(){
// return "張三";
// }
//
// @PostMapping
// public String addUser(String username){
// return username;
// }
//
// @DeleteMapping
// public User delUser(){
// User zs = new User("張三", "15");
// return zs;
// }
//
// @PutMapping
// public String putUser(@RequestBody User user){
// return "user";
// }
}
- 啟動(dòng)測試http://localhost:8080/swagger-ui.html
在這里插入圖片描述
部分代碼精講
除了通過包路徑配置掃描接口外,還可以通過配置其他方式掃描接口,這里注釋一下所有的配置方式:
any() // 掃描所有,項(xiàng)目中的所有接口都會(huì)被掃描到
none() // 不掃描接口
withMethodAnnotation(final Class<? extends Annotation> annotation)// 通過方法上的注解掃描,如withMethodAnnotation(GetMapping.class)只掃描get請(qǐng)求
withClassAnnotation(final Class<? extends Annotation> annotation) // 通過類上的注解掃描,如.withClassAnnotation(Controller.class)只掃描有controller注解的類中的接口
basePackage(final String basePackage) // 根據(jù)包路徑掃描接口
1、配置接口掃描過濾
上述方式可以通過具體的類、方法等掃描接口,還可以配置如何通過請(qǐng)求路徑配置:
eturn new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.swaggerexample.controller"))
// 配置如何通過 path過濾 即這里只掃描 請(qǐng)求以 /user開頭的接口
.paths(PathSelectors.ant("/user/**"))
.build();
這里的可選值還有:
any() // 任何請(qǐng)求都掃描
none() // 任何請(qǐng)求都不掃描
regex(final String pathRegex) // 通過正則表達(dá)式控制,返回true掃描,false不掃描
ant(final String antPattern) // 通過ant()表達(dá)式控制,返回true掃描,false不掃描
2、配置要忽略的請(qǐng)求參數(shù)
可以通過ignoredParameterTypes()方法去配置要忽略的參數(shù):
// 配置docket以配置Swagger具體參數(shù)
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
// 配置要忽略的參數(shù)
.ignoredParameterTypes(HttpServletRequest.class)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.swaggerexample.controller")).build();
}
3、配置是否啟動(dòng)Swagger
通過enable()方法配置是否啟用swagger,如果是false,swagger將不能在瀏覽器中訪問了:
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.ignoredParameterTypes(HttpServletRequest.class)
.enable(false) // 配置是否啟用Swagger,如果是false,在瀏覽器將無法訪問
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.swaggerexample.controller")).build();
}
**4、如何動(dòng)態(tài)配置當(dāng)項(xiàng)目處于test、dev環(huán)境時(shí)顯示swagger,處于prod時(shí)不顯示?
**
@Bean
public Docket docket(Environment environment) {
// 設(shè)置要顯示swagger的環(huán)境
Profiles of = Profiles.of("dev", "test");
// 判斷當(dāng)前是處于該環(huán)境,通過 enable() 接收此參數(shù)判斷是否要顯示
boolean b = environment.acceptsProfiles(of);
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.ignoredParameterTypes(HttpServletRequest.class)
.enable(b) // 配置是否啟用Swagger,如果是false,在瀏覽器將無法訪問
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.swaggerexample.controller")).build();
}
5、配置API分組
如果沒有配置分組,默認(rèn)是default。通過groupName()方法即可配置分組:
//配置分組
@Bean
public Docket docketUser(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("用戶")
.select().paths(PathSelectors.ant("/user")).build();
}
@Bean
public Docket docketHello(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("你好")
.select().paths(PathSelectors.ant("/hello")).build();
}
如下圖所示,我們配置了groupName("user")那么當(dāng)前接口分組信息為user。

6、實(shí)體配置
比如當(dāng)前項(xiàng)目中有這么一個(gè)實(shí)體:
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("用戶實(shí)體")
public class User {
@ApiModelProperty(value = "用戶id",example = "0")
private Integer id;
@ApiModelProperty("用戶名")
private String username;
@ApiModelProperty(value = "用戶年齡",example = "1")
private String age;
}
只要這個(gè)實(shí)體在請(qǐng)求接口的返回值上(即使是泛型),都能映射到實(shí)體項(xiàng)中:
注:并不是因?yàn)锧ApiModel這個(gè)注解讓實(shí)體顯示在這里了,而是只要出現(xiàn)在接口方法的返回值上的實(shí)體都會(huì)顯示在這里,而@ApiModel和@ApiModelProperty這兩個(gè)注解只是為實(shí)體添加注釋的。
@ApiModel為類添加注釋
@ApiModelProperty為類屬性添加注釋
常用的注解
swagger通過注解表明該接口文檔會(huì)生成文檔,包括接口名,請(qǐng)求方法,參數(shù),返回信息的等等。
@Api修飾整個(gè)類,描述controller的作用
@ApiOperation:描述一個(gè)類的一個(gè)方法,或者說一個(gè)接口
@ApiParam:單個(gè)參數(shù)描述
@ApiModel:當(dāng)接收參數(shù)為對(duì)象時(shí)
@ApiProperty:用對(duì)象接收參數(shù)時(shí),描述對(duì)象的一個(gè)字段
@ApiRespose:HTTP響應(yīng)其中1個(gè)描述
@ApiResponses:HTTP響應(yīng)整體描述
@ApiIgnore:使用該注解忽略這個(gè)API
@ApiError:發(fā)生錯(cuò)誤返回的信息
@ApiImplicitParam:一個(gè)參數(shù)請(qǐng)求
@ApiImplicitParams:多個(gè)請(qǐng)求
詳細(xì)解釋:
@Api:用在請(qǐng)求類上,表示對(duì)類的說明
tags=“說明該類的作用,可以在UI界面上看到的注解”
value=“該參數(shù)沒什么意義,在UI界面上也看到,所以不需要配置”
@ApiOperation:用在請(qǐng)求的方法上,說明方法的用途,作用
value=“說明方法的用途,作用”
notes=“方法的備注說明”
@ApiImplicitParams:用在請(qǐng)求的方法上,表示一組參數(shù)的說明
@ApiImplicitParam:用在@ApiImplicitParams注解中,指定一個(gè)請(qǐng)求參數(shù)的各個(gè)方面
name:參數(shù)名
value:參數(shù)的漢字說明
required:參數(shù)放在哪個(gè)地方
header:請(qǐng)求參數(shù)的獲取 @RequestHeader
query:請(qǐng)求參數(shù)的獲取 @RequestParam
path:(用于Restful接口)
body(不常用)
form(不常用)
dataTye:當(dāng)參數(shù)為對(duì)象類型時(shí)指定參數(shù)類型
@ApiResponses:用在請(qǐng)求的方法上,表示一組響應(yīng)
@ApiResponse:用在@ApiResponses中,一般用于表達(dá)一個(gè)錯(cuò)誤的響應(yīng)信息(實(shí)際上任何相應(yīng)信息都可以)
code:數(shù)字,例如400
message:信息,例如“請(qǐng)求參數(shù)沒填寫正確”
response:拋出的異常類
@ApiModel:用于響應(yīng)類上,表示一個(gè)返回響應(yīng)數(shù)據(jù)的信息(這種一般用在post創(chuàng)建的時(shí)候,使用@RequestBody這樣的場景,請(qǐng)求參數(shù)無法使用@ApiImplicitParams注解進(jìn)行描述的時(shí)候)
@ApiModelProperty:用在屬性上,描述響應(yīng)類的屬性