Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。
常用注解推荐查看如下链接,这边就不再论述
https://my.oschina.net/Rayn/blog/3064162
这边整合的内容有如下
1、pom.xml引入
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
ps:排除2.9.2版本的swagger-models和swagger-annotations,而引入1.5.21版本,是因为使用2.9.2版本时,当字段为数值型映射文档字段属性会出异常
2、创建Swagger的配置类
@Configuration
public class SwaggerConfig {
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.version("1.0")
.title("API接口文档 ")
.description("API接口文档")
.build();
}
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2).useDefaultResponseMessages(false)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.github.lybgeek.swagger"))
.paths(PathSelectors.regex("/api.*")).build();
}
}
3、在启动类上加上@EnableSwagger2注解
@SpringBootApplication
@EnableSwagger2
public class SwaggerSourceApplication
{
public static void main( String[] args )
{
SpringApplication.run(SwaggerSourceApplication.class,args);
}
}
4、在实体bean上加上@ApiModel注解,实体的字段上加上@ApiModelProperty注解
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel
public class BookDTO {
@ApiModelProperty(value = "编号", name = "id", example = "1")
private Long id;
@ApiModelProperty(value = "书名", name = "name", example = "swagger2入门")
@NotNull(message = "书名不能为空")
private String bookName;
@ApiModelProperty(value = "作者", name = "author", example = "张三")
@NotNull(message = "作者不能为空")
private String author;
@ApiModelProperty(value = "描述", name = "description", example = "swagger2入门实战")
private String description;
@ApiModelProperty(value = "价格", name = "price", example = "10")
@NotNull(message = "价格不能为空")
private BigDecimal price;
@ApiModelProperty(value = "库存", name = "stock", example = "20")
@NotNull(message = "库存不能为空")
private Integer stock;
}
5、contoller层做形如下配置
@RestController
@RequestMapping(value={"/api/{version}/book","/book"})
@Slf4j
@Api(value = "书目管理", tags = {"书目管理"})
@ApiResponses({@ApiResponse(code = 200, message = "成功")})
public class BookController {
@Autowired
private BookService bookService;
@PostMapping(value="/add")
@ApiOperation(value = "添加书籍", notes = "添加书籍")
public Result<BookDTO> addBook(@Valid BookDTO bookDTO, BindingResult bindingResult){
Result<BookDTO> result = new Result<>();
if (bindingResult.hasErrors()){
return ResultUtil.INSTANCE.getFailResult(bindingResult, result);
}
try {
BookDTO book = bookService.addBook(bookDTO);
result.setData(book);
} catch (Exception e) {
log.error("addBook error:"+e.getMessage(),e);
result.setStatus(Result.fail);
result.setMessage(e.getMessage());
}
return result;
}
@PostMapping(value="/update")
@ApiOperation(value = "更新书籍", notes = "更新书籍")
public Result<BookDTO> upadteBook(BookDTO bookDTO){
Result<BookDTO> result = new Result<>();
if(bookDTO.getId() == null){
result.setStatus(Result.fail);
result.setMessage("id不能为空");
return result;
}
BookDTO book = bookService.editBook(bookDTO);
result.setData(book);
return result;
}
@PostMapping(value="/del/{id}")
@ApiOperation(value = "删除书籍", notes = "根据书籍编号删除书籍")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "书籍编号", dataType = "Long", required = true)
})
public Result<Boolean> delBook(@PathVariable("id")Long id){
Result<Boolean> result = new Result<>();
Boolean delFlag = bookService.delBookById(id);
result.setData(delFlag);
return result;
}
@PostMapping(value="/list")
@ApiOperation(value = "查找书籍列表", notes = "根据查询条件查询书籍")
public Result<List<BookDTO>> listUsers(BookDTO bookDTO){
Result<List<BookDTO>> result = new Result<>();
List<BookDTO> books = bookService.listBooks(bookDTO);
result.setData(books);
return result;
}
@PostMapping(value="/page")
@ApiOperation(value = "书籍分页", notes = "根据查询条件查询书籍")
@ApiImplicitParams({
@ApiImplicitParam(name = "pageNo", value = "页码", dataType = "Integer", required = true),
@ApiImplicitParam(name = "pageSize", value = "分页大小", dataType = "Integer", required = true)
})
public Result<PageResult<BookDTO>> pageUsers(BookDTO bookDTO,Integer pageNo,Integer pageSize){
PageQuery<BookDTO> pageQuery = new PageQuery<>();
pageQuery.setPageNo(pageNo);
pageQuery.setPageSize(pageSize);
pageQuery.setQueryParams(bookDTO);
Result<PageResult<BookDTO>> result = new Result<>();
PageResult<BookDTO> books = bookService.pageBook(pageQuery);
result.setData(books);
return result;
}
@PostMapping(value="/get/{id}")
@ApiOperation(value = "查找书籍", notes = "根据书籍编号查找书籍")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "书籍编号", dataType = "Long", required = true)
})
public Result<BookDTO> getBookById(@PathVariable("id") Long id){
Result<BookDTO> result = new Result<>();
BookDTO book = bookService.getBookById(id);
result.setData(book);
return result;
}
}
6、如果代码有配置拦截器,可以看具体需求看是否要拦截swagger相关页面,下面代码为不拦截swagger相关页面配置
@Configuration
public class IntercepterConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
@Bean
public AuthIntercepors authIntercepors() {
return new AuthIntercepors();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authIntercepors()).addPathPatterns("/**")
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**","/swagger-ui.html","/doc.html","/docs.html");
}
}
7、通过访问项目地址/swagger-ui.html,进入在线接口文档页面
swagger 分组只需在swagger配置加入groupName属性就行了,配置如下
@Configuration
public class SwaggerConfig {
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.version("1.0")
.title("API接口文档 ")
.description("API接口文档")
.build();
}
@Bean
public Docket createRestApiWithApiVersion(){
return new Docket(DocumentationType.SWAGGER_2).useDefaultResponseMessages(false)
.apiInfo(apiInfo())
.groupName(ApiVersionUtil.DEFAULT_API_VERSION)
.select()
.apis(RequestHandlerSelectors.basePackage("com.github.lybgeek.swagger"))
// .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.regex("/api.*")).build()
}
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2).useDefaultResponseMessages(false)
.apiInfo(apiInfo())
.groupName("default")
.select()
.apis(RequestHandlerSelectors.basePackage("com.github.lybgeek.swagger"))
.paths(PathSelectors.regex("(?!/api).+")).build();
}
}
1、配置局部token
主要是在swagger配置中加入globalOperationParameters属性就行,其配置如下
@Configuration
public class SwaggerConfig {
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.version("1.0")
.title("API接口文档 ")
.description("API接口文档")
.build();
}
@Bean
public Docket createRestApiWithApiVersion(){
List<Parameter> pars = new ArrayList<>();
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar.name(Constant.ACCESS_TOKEN).description(Constant.ACCESS_TOKEN).modelRef(new ModelRef("string")).parameterType("header").required(true).build();
pars.add(tokenPar.build());
return new Docket(DocumentationType.SWAGGER_2).useDefaultResponseMessages(false)
.apiInfo(apiInfo())
.groupName(ApiVersionUtil.DEFAULT_API_VERSION)
.select()
.apis(RequestHandlerSelectors.basePackage("com.github.lybgeek.swagger"))
// .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.regex("/api.*")).build()
.genericModelSubstitutes(ResponseEntity.class)
//每个接口单独传token
.globalOperationParameters(pars);
}
2、配置全局token
主要是在swagger配置中加入securitySchemes属性以及securityContexts属性,其配置如下
@Configuration
public class SwaggerConfig {
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.version("1.0")
.title("API接口文档 ")
.description("API接口文档")
.build();
}
@Bean
public Docket createRestApi(){
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
tokenPar.name(Constant.ACCESS_TOKEN).description(Constant.ACCESS_TOKEN).modelRef(new ModelRef("string")).parameterType("header").required(true).build();
pars.add(tokenPar.build());
return new Docket(DocumentationType.SWAGGER_2).useDefaultResponseMessages(false)
.apiInfo(apiInfo())
.groupName("default")
.select()
.apis(RequestHandlerSelectors.basePackage("com.github.lybgeek.swagger"))
// .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
// .paths(PathSelectors.regex("/api.*")).build()
.paths(PathSelectors.regex("(?!/api).+")).build()
.genericModelSubstitutes(ResponseEntity.class)
// .globalOperationParameters(pars);
//设置全局token
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Collections.singletonList(SecurityReference.builder()
.reference(Constant.ACCESS_TOKEN)
.scopes(authorizationScopes).build());
}
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContexts=new ArrayList<>();
securityContexts.add(
SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("(?!/api).+"))
.build());
return securityContexts;
}
private List<ApiKey> securitySchemes() {
return newArrayList(
new ApiKey(Constant.ACCESS_TOKEN, Constant.ACCESS_TOKEN, "header")
)
}
1、接口版本号控制实现
因为这个接口版本号控制的实现,与本文的论述的关联不大,因此就不展开描述了。感兴趣的朋友,可以查看如下链接
https://www.jianshu.com/p/fd4a61c47b86
这篇文章讲述比较详细,但是里面有个实现细节有bug,如果大家是参考这篇文章进行实现就会发现。其bug的解决方案可参考如下链接
https://my.oschina.net/pwh19920920/blog/2413927
2、swagger与接口版本号集成
主要依然是在swagger配置中实现,其设置和局部token的设置方式一样,只是token是设置在header,版本号设置在path,其代码如下
@Configuration
public class SwaggerConfig {
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.version("1.0")
.title("API接口文档 ")
.description("API接口文档")
.build();
}
@Bean
public Docket createRestApiWithApiVersion(){
List<Parameter> pars = new ArrayList<>();
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar.name(Constant.ACCESS_TOKEN).description(Constant.ACCESS_TOKEN).modelRef(new ModelRef("string")).parameterType("header").required(true).build();
ParameterBuilder versionPar = new ParameterBuilder();
versionPar.name("version").description("version").modelRef(new ModelRef("string")).parameterType("path")
.defaultValue(ApiVersionUtil.DEFAULT_API_VERSION).required(false).build();
pars.add(tokenPar.build());
pars.add(versionPar.build());
return new Docket(DocumentationType.SWAGGER_2).useDefaultResponseMessages(false)
.apiInfo(apiInfo())
.groupName(ApiVersionUtil.DEFAULT_API_VERSION)
.select()
.apis(RequestHandlerSelectors.basePackage("com.github.lybgeek.swagger"))
// .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.regex("/api.*")).build()
.genericModelSubstitutes(ResponseEntity.class)
//每个接口单独传token
.globalOperationParameters(pars);
}
1、pom.xml配置
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.3</version>
</dependency>
2、在swagger的配置类上,加上@EnableSwaggerBootstrapUI注解
@Configuration
@EnableSwaggerBootstrapUI
public class SwaggerConfig {
3、如果有配置拦截器,要放行doc.html
4、访问项目地址/doc.html
本文介绍的内容大体都是平常使用swagger会经常碰到的,至于自定义接口文档排序等优先级不是那么高的就不再介绍。更多相关swagger的介绍,大家感兴趣可以查看
https://github.com/swagger-api/swagger-ui
或者访问官网
http://swagger.io
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-swagger