學習Spring Boot:(六) 整合Swagger2
前言
Swagger是用來描述和文件化RESTful API的一個專案。Swagger Spec是一套規範,定義了該如何去描述一個RESTful API。類似的專案還有RAML、API Blueprint。 根據Swagger Spec來描述RESTful API的檔案稱之為Swagger specification file,它使用JSON來表述,也支援作為JSON支援的YAML。
Swagger specification file可以用來給swagger-ui生成一個Web的可互動的文件頁面,以可以用swagger2markup生成靜態文件,也可用使用swagger-codegen生成客戶端程式碼。總之有了有個描述API的JSON文件之後,可以做各種擴充套件。
Swagger specification file可以手動編寫,swagger-editor為了手動編寫的工具提供了預覽的功能。但是實際寫起來也是非常麻煩的,同時還得保持程式碼和文件的兩邊同步。於是針對各種語言的各種框架都有一些開源的實現來輔助自動生成這個`Swagger specification file。
swagger-core是一個Java的實現,現在支援JAX-RS。swagger-annotation定義了一套註解給使用者用來描述API。
spring-fox也是一個Java的實現,它支援Spring MVC, 它也支援swagger-annotation定義的部分註解。
使用
新增依賴
在pom檔案新增:
<swagger.version>2.7.0</swagger.version>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
配置docket
@Configuration
@EnableSwagger2
public class SwaggerConfig {
/**
* SpringBoot預設已經將classpath:/META-INF/resources/和classpath:/META-INF/resources/webjars/對映
* 所以該方法不需要重寫,如果在SpringMVC中,可能需要重寫定義(我沒有嘗試)
* 重寫該方法需要 extends WebMvcConfigurerAdapter
*/
// @Override
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
// registry.addResourceHandler("swagger-ui.html")
// .addResourceLocations("classpath:/META-INF/resources/");
//
// registry.addResourceHandler("/webjars/**")
// .addResourceLocations("classpath:/META-INF/resources/webjars/");
// }
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.wuwii"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Spring Boot中使用Swagger2構建RESTful APIs")
.description("rest api 文件構建利器")
.termsOfServiceUrl("https://blog.wuwii.com/")
.contact("KronChan")
.version("1.0")
.build();
}
}
builder說明
根據網上一位前輩的文章:
@Bean
public Docket petApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select() //1
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.pathMapping("/") //2
.directModelSubstitute(LocalDate.class, //3
String.class)
.genericModelSubstitutes(ResponseEntity.class) //4
.alternateTypeRules( //5
newRule(typeResolver.resolve(DeferredResult.class,
typeResolver.resolve(ResponseEntity.class, WildcardType.class)),
typeResolver.resolve(WildcardType.class)))
.useDefaultResponseMessages(false) //6
.globalResponseMessage(RequestMethod.GET, //7
newArrayList(new ResponseMessageBuilder()
.code(500)
.message("500 message")
.responseModel(new ModelRef("Error"))
.build()))
.securitySchemes(newArrayList(apiKey())) //8
.securityContexts(newArrayList(securityContext())) //9
;
}
方法說明:
1. 定義了需要生成API文件的endpoint,api()
方法可以通過RequestHandlerSelectors的各種選擇器來選擇,比如說選擇所有註解了@RsestController的類中的所有API e.g. .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
。path()
方法可以通過PathSelectors的來匹配路徑,提供了regex匹配或者ant匹配
2. 定義了API的根路徑
3. 輸出模型定義時的替換,比如遇到所有LocalDate的欄位時,輸出成String
4. 遇到對應泛型型別的外圍類,直接解析成泛型型別,比如說ResponseEntity<T>
,應該直接輸出成型別T
5. 提供了自定義性更強的針對泛型的處理,示例中的程式碼的意思是將型別DeferredResult直接解析成型別T
6. 是否使用預設的ResponseMessage, 框架預設定義了一些針對各個HTTP方法時各種不同響應值對應的message
7. 全域性的定義ResponseMessage,示例程式碼定義GET方法的500錯誤的訊息以及錯誤模型。注意這裡GET方法的所有ResponseMessage都會被這裡的定義覆蓋
8. 定義API支援的SecurityScheme,指的是認證方式,支援OAuth
、APIkey
。 P.S. 要讓swagger-ui的oauth正常工作,需要定義個SecurityConfiguration的Bean
9. 定義具體上下文路徑對應的認證方式
10. 還有一些介面可以定義API的名稱等一些基本資訊,定義API支援的資料格式等等。
介面上新增文件
@RestController
@Api(description = "這是一個控制器的描述 ")
public class PetController {
/**
* logger
*/
private static final Logger LOGGER = LoggerFactory.getLogger(PetController.class);
private String no;
private String kind;
private String name;
@ApiOperation(value="測試介面", notes="測試介面描述")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "使用者ID", required = true, dataType = "Long", paramType = "path"),
@ApiImplicitParam(name = "pet", value = "寵物", required = true, dataType = "PetController")
})
@ApiResponses({
@ApiResponse(code = 200, message = "請求完成"),
@ApiResponse(code = 400, message = "請求引數錯誤")
})
@RequestMapping(path = "/index/{id}", method = RequestMethod.PUT)
public PetController index1(@PathVariable("id") String id, @RequestBody PetController pet) {
return pet;
}
//…… get / set
常用的註解說明
檢視API文件
啟動Spring Boot程式,訪問:http://host:port/swagger-ui.html
。就能看到RESTful API的頁面。開啟我們的測試介面的API ,可以檢視這個介面的描述,以及引數等資訊:
點選上圖中右側的Model Schema(黃色區域:它指明瞭這個requestBody的資料結構),此時pet中就有了pet物件的模板,修改上測試資料,點選下方Try it out!
按鈕,即可完成了一次請求呼叫!
呼叫完後,我們可以檢視介面的返回資訊:
參考文章
- Spring Boot中使用Swagger2構建強大的RESTful API文件檔
- spring-boot-swagger2 使用手冊
- 使用springfox生成springmvc專案的swagger的文件
例外補充點
驗證碼
我使用的是 com.github.axet.kaptcha
的驗證碼
雖然按照別人的方法使用 HttpServletResponse
輸出流,這種是暴露 Servlet
的介面。但是發現了一個問題了,在 swagger 的獲取驗證碼接上測試的時候不能得到驗證碼圖片,但是在 img
標籤中是沒問題,發現 swagger 還是把我的返回結果作為 json
處理。所以我還是想到使用下載中二進位制流的方法,將 BufferedImage
轉換成二進位制流陣列,總算是解決。
上最後解決的辦法:
/**
* 獲取驗證碼
*/
@GetMapping(value = "/captcha.jpg", produces = MediaType.IMAGE_JPEG_VALUE)
public ResponseEntity<byte[]> captcha()throws IOException {
//生成文字驗證碼
String text = producer.createText();
//生成圖片驗證碼
BufferedImage image = producer.createImage(text);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", out);
// 文字驗證碼儲存到 shiro session
ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);
HttpHeaders headers = new HttpHeaders();
headers.setCacheControl("no-store, no-cache");
return ResponseEntity
.status(HttpStatus.OK)
.headers(headers)
.body(out.toByteArray());
我是採用 ImageIO
工具類的將 BufferedImage
轉換成 輸出流,從輸出流中獲取二進位制流陣列。
ImageIO.write(BufferedImage image,String format,OutputStream out)
再補充一個 將二進位制流陣列 byte[]
轉換成 BufferedImage
// 將二進位制流陣列轉換成輸入流
ByteArrayInputStream in = new ByteArrayInputStream(byte[] byets);
// 讀取輸入流
BufferedImage image = ImageIO.read(InputStream in);
在 swagger
上是這樣的了:
配置不同環境中是否啟動
在不同環境種配置是否啟用規則:
swagger:
enable: true # or false
在 swagger 配置類中加入
/**
* 啟用
*/
@Value("${swagger.enable}")
private boolean enable;
…… set / get
配置 Docket 中
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// 加入 enable
.enable(enable)
.select()
.apis(RequestHandlerSelectors.basePackage("com.wuwii"))
.paths(PathSelectors.any())
.build();
}
SpringMVC 中配置 Swagger2
Swagger 的配置檔案:
@Configuration
@EnableSwagger2
@EnableWebMvc
@ComponentScan("com.devframe.controller")
public class SwaggerConfig extends WebMvcConfigurerAdapter {
/**
* 靜態檔案過濾
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.devframe"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("RESTful APIs")
.description("rest api 文件構建利器")
.termsOfServiceUrl("https://blog.wuwii.com/")
.version("1.0")
.build();
}
}
額外需要在 web.xml
配置:
<!-- Springmvc前端控制器掃描路徑增加“/v2/api-docs”,用於掃描Swagger的 /v2/api-docs,否則 /v2/api-docs無法生效。-->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/v2/api-docs</url-pattern>
</servlet-mapping>
單元測試中會出現的錯誤
發現加入 Swagger
後,以前的單元測試再執行的時候,會丟擲一個異常,參考 How to run integration tests with spring and springfox?
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'documentationPluginsBootstrapper' defined in URL [jar:file:/C:/Users/test/.m2/repository/io/springfox/springfox-spring-web/2.0.0-SNAPSHOT/springfox-spring-web-2.0.0-SNAPSHOT.jar!/springfox/documentation/spring/web/plugins/DocumentationPluginsBootstrapper.class]: Unsatisfied dependency expressed through constructor argument with index 1 of type [java.util.List]: : No qualifying bean of type [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] found for dependency [collection of org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] found for dependency [collection of org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
解決,單元測試上加入 @EnableWebMvc
相關文章
- Spring boot學習(三) Spring boot整合mybatisSpring BootMyBatis
- Spring boot學習(四)Spring boot整合DruidSpring BootUI
- Spring boot學習(五)Spring boot整合Mybatis Generator以及PageHelperSpring BootMyBatis
- Spring Boot2 系列教程(十七)SpringBoot 整合 Swagger2Spring BootSwagger
- Spring Boot 整合 Swagger2,構建強大的 API 文件Spring BootSwaggerAPI
- 手把手教你Spring Boot整合Mybatis Plus和Swagger2Spring BootMyBatisSwagger
- Spring Boot(六)整合 MyBatis 操作 MySQL 8Spring BootMyBatisMySql
- Spring boot學習(六)Spring boot實現AOP記錄操作日誌Spring Boot
- Spring Boot中整合機器學習簡介Spring Boot機器學習
- 個人學習系列 - Spring Boot 整合 UReport2Spring Boot
- Spring-boot整合AOP及AOP相關學習Springboot
- spring-boot-route(六)整合JApiDocs生成介面文件SpringbootAPI
- spring boot學習Spring Boot
- Spring Boot 學習Spring Boot
- Spring Boot學習(一)——Spring Boot介紹Spring Boot
- Spring Boot整合Spring SecuritySpring Boot
- Spring Boot整合Spring BatchSpring BootBAT
- Spring Boot整合Spring AopSpring Boot
- Spring Boot系列十九 Spring boot整合 swaggerSpring BootSwagger
- Spring Boot 2.0(八):Spring Boot 整合 MemcachedSpring Boot
- Spring boot學習(一)開啟Spring boot之旅Spring Boot
- Spring boot學習(二) Spring boot基礎配置Spring Boot
- Spring Boot學習筆記:Spring Boot核心配置Spring Boot筆記
- 小代學Spring Boot之整合MyBatisSpring BootMyBatis
- spring boot整合jooqSpring Boot
- Spring Boot整合SocketSpring Boot
- Spring Boot整合rabbitmqSpring BootMQ
- Spring Boot整合RedisSpring BootRedis
- Spring Boot 整合redisSpring BootRedis
- Spring Boot 整合 rabbitmqSpring BootMQ
- Spring Boot 整合 elasticsearchSpring BootElasticsearch
- Spring Boot 整合 dockerSpring BootDocker
- Spring Boot 整合 elkSpring Boot
- Spring Boot 整合 ApolloSpring Boot
- spring boot整合HadoopSpring BootHadoop
- Spring Boot 整合 MyBatisSpring BootMyBatis
- Spring Boot整合SwaggerSpring BootSwagger
- spring boot整合shiroSpring Boot