Swagger2在SpringBoot環境下的應用
1. 集成Swagger
1.1 添加依賴
<!--swagger2 start-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<!--引入swagger-ui包-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
1.2 配置類
package com.inn.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfiguration extends WebMvcConfigurerAdapter {
//生產關閉swagger
@Value("${swagger.enable}")
private boolean enableSwagger;
// /**
// * 訪問swagger ui 出現404時可以把注釋去掉試試
// * 解決資源系統資源目錄與swagger ui資源目錄沖突問題
// * 這個地方要重新注入一下資源文件,不然不會注入資源的,也沒有注入requestHandlerMappping,相當於xml配置的swagger資源配置
// * <mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html"/>
// * <mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/>
// * @param registry
// */
// @Override
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
// registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
// registry.addResourceHandler("swagger-ui.html")
// .addResourceLocations("classpath:/META-INF/resources/");
// registry.addResourceHandler("/webjars/**")
// .addResourceLocations("classpath:/META-INF/resources/webjars/");
// super.addResourceHandlers(registry);
// }
// /**
// * 支持分組 groupName
// */
// @Bean(value = "solrRestApi")
// public Docket createSolrRestApi() {
// return new Docket(DocumentationType.SWAGGER_2)
// .apiInfo(apiInfo()).groupName("Solr Demo模塊")
// .enable(enableSwagger)
// .select()
// .apis(RequestHandlerSelectors.basePackage("com.inn.demo.modules.solr.web"))
// .paths(PathSelectors.any())
// .build();
// }
@Bean(value = "userRestApi")
public Docket createUserRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//.groupName("用戶管理")
.enable(enableSwagger)
.globalOperationParameters(createCommonParams())//公共參數
.select()
.apis(RequestHandlerSelectors.basePackage("com.inn.demo.modules.user.web"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Demo APIs")
.description("應用實例")
//.termsOfServiceUrl("http://www.demo.com/";)
//.contact(new Contact("開發者1", "", "xxx@163.com"))
.version("1.0")
.build();
}
/**
* 創建公共參數
* @return
*/
private List<Parameter> createCommonParams() {
//添加head參數start
List<Parameter> pars = new ArrayList<Parameter>();
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar.name("x-access-token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
pars.add(tokenPar.build());
return pars;
//添加head參數end
}
}
1.3 注解使用
作用范圍
|
API
|
使用位置
|
對象屬性
|
@ApiModelProperty
|
用在出入參數對象的字段上
|
協議集描述
|
@Api
|
用於controller類上
|
協議描述
|
@ApiOperation
|
用在controller的方法上
|
Response集
|
@ApiResponses
|
用在controller的方法上
|
Response
|
@ApiResponse
|
用在 @ApiResponses里邊
|
非對象參數集
|
@ApiImplicitParams
|
用在controller的方法上
|
非對象參數描述
|
@ApiImplicitParam
|
用在@ApiImplicitParams的方法里邊
|
描述返回對象的意義
|
@ApiModel
|
用在返回對象類上
|
ApiImplicitParam的相關屬性
|
||
屬性
|
取值
|
作用
|
paramType
|
path
query
body
header
form
|
參數放在哪個地方:
必須要有這個屬性
header:header中提交:@RequestHeader獲取
query :key=value提交:@RequestParam獲取
path :地址中提交:@PathVariable獲取
body :json流提交 :@RequestBody獲取(限POST)
form :表單提交:@RequestParam獲取(限POST)
|
dataType
|
Long
String
|
參數的數據類型 只作為標志說明,並沒有實際驗證
|
name
|
|
接收參數名
|
value
|
|
接收參數的意義描述
|
required
|
|
參數是否必填
|
|
TRUE
|
必填
|
|
FALSE
|
非必填
|
defaultValue
|
|
默認值
|
ApiImplicitParam 與 ApiParam 的區別
ApiImplicitParam:
- 對Servlets或者非 JAX-RS的環境,只能使用 ApiImplicitParam。
- 在使用上,ApiImplicitParam比ApiParam具有更少的代碼侵入性,只要寫在方法上就可以了,但是需要提供具體的屬性才能配合swagger ui解析使用。
- ApiParam只需要較少的屬性,與swagger ui配合更好。
代碼實例:
@RestController
@RequestMapping(value = "/user")
@Api(value = "/user", description = "人員基本信息 ")
public class UserController {
static Map<String, User> users = Collections.synchronizedMap(new HashMap<String, User>());
@ApiOperation(value = "獲取用戶列表", notes = "")
@RequestMapping(value = {"/list"}, method = RequestMethod.GET)
public List<User> getUserList() {
List<User> r = new ArrayList<User>(users.values());
return r;
}
@ApiOperation(value = "創建用戶", notes = "根據User對象創建用戶")
@ApiImplicitParam(name = "user", value = "用戶詳細實體user", required = true, dataType = "User")
@RequestMapping(value = "add", method = RequestMethod.POST)
public String postUser(@RequestBody User user) {
users.put(user.getId(), user);
return "success";
}
@ApiOperation(value = "獲取用戶詳細信息", notes = "根據url的id來獲取用戶詳細信息")
@ApiParam(name = "id", value = "用戶ID", required = true)
@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public User getUser(@PathVariable(value = "id") String id) {
return users.get(id);
}
@ApiOperation(value = "更新用戶詳細信息", notes = "根據url的id來指定更新對象,並根據傳過來的user信息來更新用戶詳細信息")
@RequestMapping(value = "/update/{id}", method = RequestMethod.PUT)
public String putUser(@PathVariable @ApiParam(name = "id", value = "用戶ID", required = true) String id,
@RequestBody @ApiParam(name = "user", value = "用戶詳細實體user", required = true) User user) {
User u = users.get(id);
u.setName(user.getName());
u.setAge(user.getAge());
users.put(id, u);
return "success";
}
@ApiOperation(value = "更新用戶名稱和年齡", notes = "更新用戶名稱和年齡")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "用戶ID", required = true, dataType = "String",paramType = "path"),
@ApiImplicitParam(name = "name", value = "用戶名", required = true, dataType = "String",paramType = "query"),
@ApiImplicitParam(name = "age", value = "年齡", required = true, dataType = "Integer",paramType = "query"),
@ApiImplicitParam(name = "user", value = "用戶信息", required = true, dataType = "User",paramType = "body"),
@ApiImplicitParam(name = "headerName", value = "Header信息", required = true, dataType = "String",paramType = "header")
})
@RequestMapping(value = "/update/info/{id}", method = RequestMethod.POST)
public String updateUserNameAndAge(@PathVariable(value = "id") String id,
@RequestParam(value = "name") String name,
@RequestParam(value = "age") Integer age,
@RequestHeader(value = "headerName") String headerName,
@RequestBody User user) {
User u = users.get(id);
u.setName(name);
u.setAge(age);
users.put(id, u);
return "success";
}
@ApiOperation(value = "刪除用戶", notes = "根據url的id來指定刪除對象")
@ApiParam(name = "id", value = "用戶ID", required = true)
@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
public String deleteUser(@PathVariable String id) {
users.remove(id);
return "success";
}
@ApiOperation(value="刪除用戶-傳遞數組", notes="刪除對象,傳遞數組")
@RequestMapping(value="/users/deleteByIds", method = RequestMethod.DELETE)
public void deleteUsers(@ApiParam("用戶ID數組") @RequestParam Integer[] ids) {
for (int id:ids){
users.remove(id);
}
}
}
User實體類:
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties({"handler", "hibernateLazyInitializer"})
@ApiModel(value = "User")
public class User {
@ApiModelProperty(value = "ID")
private String id;
@ApiModelProperty(value = "姓名", required = true)
private String name;
@ApiModelProperty(value = "年齡")
private Integer age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
1.4 訪問控制台
按以下步驟配置,項目啟動后訪問:
1.5 可選配置
在application.properties中加入以下配置,用於設置測試請求的host,默認在swagger ui上做請求測試時都是以/users/1為路徑發送請求。
如果需要改變請求的根路徑,就需要配置這個參數:
該Host也是swagger-ui發送測試請求的Host, 通常我們會將將接口文檔部署在
測試服務器,這樣就需要設置Host,
否則請求都是通過localhost發送,
請求不到測試服務器的接口。
springfox.documentation.swagger.v2.host =
yourapp.abc.com
配置獲取api docs json數據的請求路徑 ,默認為/v2/api-docs:
springfox.documentation.swagger.v2.path = /api
2. 生成靜態API文檔pdf
2.1 Maven 配置
======屬性配置=======
<snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
<asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory>
<generated.asciidoc.directory>${project.build.directory}/asciidoc</generated.asciidoc.directory>
<asciidoctor.html.output.directory>${project.build.directory}/asciidoc/html</asciidoctor.html.output.directory>
<asciidoctor.pdf.output.directory>${project.build.directory}/asciidoc/pdf</asciidoctor.pdf.output.directory>
=====依賴配置============
<!--離線文檔-->
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<version>1.1.2.RELEASE</version>
<scope>test</scope>
</dependency>
<!--springfox-staticdocs 生成靜態文檔-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-staticdocs</artifactId>
<version>2.6.1</version>
</dependency>
<!--swagger2 end-->
============插件配置==========
<!--通過Asciidoctor使得asciidoc生成其他的文檔格式,例如:PDF 或者HTML5-->
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.3</version>
<!--生成PDF-->
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-pdf</artifactId>
<version>1.5.0-alpha.14</version>
</dependency>
<!-- Comment this section to use the default jruby artifact provided by the plugin -->
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
<version>1.7.21</version>
</dependency>
</dependencies>
<!--文檔生成配置-->
<configuration>
<sourceDirectory>${asciidoctor.input.directory}</sourceDirectory>
<sourceDocumentName>index.adoc</sourceDocumentName>
<attributes>
<doctype>book</doctype>
<toc>left</toc>
<toclevels>3</toclevels>
<numbered></numbered>
<hardbreaks></hardbreaks>
<sectlinks></sectlinks>
<sectanchors></sectanchors>
<generated>${generated.asciidoc.directory}</generated>
</attributes>
</configuration>
<!--因為每次執行只能處理一個后端,所以對於每個想要的輸出類型,都是獨立分開執行-->
<executions>
<!--html5-->
<execution>
<id>output-html</id>
<phase>test</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html5</backend>
<outputDirectory>${asciidoctor.html.output.directory}</outputDirectory>
</configuration>
</execution>
<!--pdf-->
<execution>
<id>output-pdf</id>
<phase>test</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>pdf</backend>
<outputDirectory>${asciidoctor.pdf.output.directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
2.2 創建index.adoc文件
路徑:項目名/docs/asciidoc/index.adoc
內容:
- include::{generated}/overview.adoc[]
- include::{generated}/definitions.adoc[]
- include::{generated}/paths.adoc[]
2.3 創建生成pdf、html的測試類
package com.inn.demo;
import io.github.robwin.markup.builder.MarkupLanguage;
import io.github.robwin.swagger2markup.GroupBy;
import io.github.robwin.swagger2markup.Swagger2MarkupConverter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import springfox.documentation.staticdocs.SwaggerResultHandler;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@AutoConfigureMockMvc
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
@RunWith(SpringRunner.class)
@SpringBootTest
public class Swagger2MarkupTest {
private String snippetDir = "target/generated-snippets";
private String outputDir = "target/asciidoc";
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
/**
* 生成api html、pdf
* @throws Exception
*/
@Test
public void Test() throws Exception {
// 得到swagger.json,寫入outputDir目錄中
mockMvc.perform(get("/v2/api-docs").accept(MediaType.APPLICATION_JSON))
.andDo(SwaggerResultHandler.outputDirectory(outputDir).build())
.andExpect(status().isOk())
.andReturn();
// 讀取上一步生成的swagger.json轉成asciiDoc,寫入到outputDir
// 這個outputDir必須和插件里面<generated></generated>標簽配置一致
Swagger2MarkupConverter.from(outputDir + "/swagger.json")
.withPathsGroupedBy(GroupBy.TAGS)// 按tag排序
.withMarkupLanguage(MarkupLanguage.ASCIIDOC)// 格式
.withExamples(snippetDir)
.build()
.intoFolder(outputDir);// 輸出
}
}
運行測試類即可生成pdf、html
- 生成的PDF和HTML文件:target/asciidoc/html and target/asciidoc/pdf
3. Swagger-UI 漢化
3.1 添加自定義首頁和譯文
在resourece目錄下創建\META-INF\resourece目錄,然后創建一個名稱為"swagger-ui.html" 的HTML文件

html內容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="icon" type="image/png" href="webjars/springfox-swagger-ui/images/favicon-32x32.png" sizes="32x32"/>
<link rel="icon" type="image/png" href="webjars/springfox-swagger-ui/images/favicon-16x16.png" sizes="16x16"/>
<link href='webjars/springfox-swagger-ui/css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='webjars/springfox-swagger-ui/css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='webjars/springfox-swagger-ui/css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='webjars/springfox-swagger-ui/css/reset.css' media='print' rel='stylesheet' type='text/css'/>
<link href='webjars/springfox-swagger-ui/css/print.css' media='print' rel='stylesheet' type='text/css'/>
<script src='webjars/springfox-swagger-ui/lib/object-assign-pollyfill.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/jquery-1.8.0.min.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/jquery.slideto.min.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/jquery.wiggle.min.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/handlebars-4.0.5.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/lodash.min.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/backbone-min.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/swagger-ui.min.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/highlight.9.1.0.pack_extended.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/jsoneditor.min.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/marked.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lib/swagger-oauth.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/springfox.js' type='text/javascript'></script> <!--國際化操作:選擇中文版 -->
<script src='webjars/springfox-swagger-ui/lang/translator.js' type='text/javascript'></script>
<script src='webjars/springfox-swagger-ui/lang/zh-cn.js' type='text/javascript'></script>
</head>
<body class="swagger-section">
<div id='header'>
<div class="swagger-ui-wrap">
<a id="logo" href="javascript:void(0)">
<img class="logo__img" alt="swagger" height="30" width="30" src="webjars/springfox-swagger-ui/images/logo_small.png" />
<span class="logo__title">在線API</span>
</a>
<form id='api_selector'>
<div class='input'>
<select id="select_baseUrl" name="select_baseUrl"></select>
</div>
<div class='input'>
<input placeholder="http://example.com/api"; id="input_baseUrl" name="baseUrl" type="text"/>
</div>
<div id='auth_container'></div>
<div class='input'><a id="explore" class="header__btn" href="#" data-sw-translate>Explore</a></div>
</form>
</div>
</div>
<div id="message-bar" class="swagger-ui-wrap" data-sw-translate></div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
</body>
</html>
大功告成 我們訪問
http://localhost:8080/swagger-ui.html 看看顯示效果:

3.2 更詳細的漢化
如果想進一步調整譯文,可以在META-INF\resources\webjars\springfox-swagger-ui\lang 目錄下添加zh-cn.js文件.

然后在譯文(zh-cn.js )內容,如下
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"警告:已過時",
"Implementation Notes":"實現備注",
"Response Class":"響應類",
"Status":"狀態",
"Parameters":"參數",
"Parameter":"參數",
"Value":"值",
"Description":"描述",
"Parameter Type":"參數類型",
"Data Type":"數據類型",
"Response Messages":"響應消息",
"HTTP Status Code":"HTTP狀態碼",
"Reason":"原因",
"Response Model":"響應模型",
"Request URL":"請求URL",
"Response Body":"響應體",
"Response Code":"響應碼",
"Response Headers":"響應頭",
"Hide Response":"隱藏響應",
"Headers":"頭",
"Try it out!":"試一下!",
"Show/Hide":"顯示/隱藏",
"List Operations":"顯示操作",
"Expand Operations":"展開操作",
"Raw":"原始",
"can't parse JSON. Raw result":"無法解析JSON. 原始結果",
"Example Value":"示例",
"Click to set as parameter value":"點擊設置參數",
"Model Schema":"模型架構",
"Model":"模型",
"apply":"應用",
"Username":"用戶名",
"Password":"密碼",
"Terms of service":"服務條款",
"Created by":"創建者",
"See more at":"查看更多:",
"Contact the developer":"聯系開發者",
"api version":"api版本",
"Response Content Type":"響應Content Type",
"Parameter content type:":"參數類型:",
"fetching resource":"正在獲取資源",
"fetching resource list":"正在獲取資源列表",
"Explore":"瀏覽",
"Show Swagger Petstore Example Apis":"顯示 Swagger Petstore 示例 Apis",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"無法從服務器讀取。可能沒有正確設置access-control-origin。",
"Please specify the protocol for":"請指定協議:",
"Can't read swagger JSON from":"無法讀取swagger JSON於",
"Finished Loading Resource Information. Rendering Swagger UI":"已加載資源信息。正在渲染Swagger UI",
"Unable to read api":"無法讀取api",
"from path":"從路徑",
"server returned":"服務器返回"
});
大功告成!