Spring boot集成Swagger2,并配置多个扫描路径,添加swagger-ui-layer
Spring boot集成Swagger,并配置多个扫描路径
1:认识Swagger
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。
作用:
1. 接口的文档在线自动生成。
2. 功能测试。
Swagger是一组开源项目,其中主要要项目如下:
Swagger-tools:提供各种与Swagger进行集成和交互的工具。例如模式检验、Swagger 1.2文档转换成Swagger 2.0文档等功能。
Swagger-core: 用于Java/Scala的的Swagger实现。与JAX-RS(Jersey、Resteasy、CXF...)、Servlets和Play框架进行集成。
Swagger-js: 用于JavaScript的Swagger实现。
Swagger-node-express: Swagger模块,用于node.js的Express web应用框架。
Swagger-ui:一个无依赖的HTML、JS和CSS集合,可以为Swagger兼容API动态生成优雅文档。
Swagger-codegen:一个模板驱动引擎,通过分析用户Swagger资源声明以各种语言生成客户端代码。
2:spring boot 集成 swagger
2.1 引入POM
- <!-- swagger2 -->
- <dependency>
- <groupId>io.springfox</groupId>
- <artifactId>springfox-swagger2</artifactId>
- <version>2.9.2</version>
- </dependency>
- <dependency>
- <groupId>io.springfox</groupId>
- <artifactId>springfox-swagger-ui</artifactId>
- <version>2.9.2</version>
- </dependency>
- <dependency>
- <groupId>com.github.caspar-chen</groupId>
- <artifactId>swagger-ui-layer</artifactId>
- <version>1.1.3</version>
- </dependency>
2.2 配置swagger
在Application.java同级或子包中创建SwaggerConfig.java
- package com.example.demo.swagger;
- import org.springframework.context.annotation.Bean;
- 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;
- @Configuration
- @EnableSwagger2
- public class SwaggerConfig {
- /**
- * 创建API应用
- * apiInfo() 增加API相关信息
- * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
- * 本例采用指定扫描的包路径来定义指定要建立API的目录。
- *
- * @return
- */
- @Bean
- public Docket createRestApi() {
- return new Docket(DocumentationType.SWAGGER_2)
- .apiInfo(apiInfo())
- .select()
- .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
- .paths(PathSelectors.any())
- .build();
- }
- /**
- * 创建该API的基本信息(这些基本信息会展现在文档页面中)
- * 访问地址:http://项目实际地址/swagger-ui.html
- *
- * @return
- */
- private ApiInfo apiInfo() {
- return new ApiInfoBuilder()
- .title("测试 APIs")
- .description("测试api接口文档")
- .termsOfServiceUrl("http://www.baidu.com")
- .version("1.0")
- .build();
- }
- }
2.3 添加文档内容
在完成了上述配置后,其实已经可以生产文档内容,我们访问http://localhost:8080/swagger-ui.html。如图

但是这样的文档主要针对请求本身,描述的主要来源是函数的命名,对用户并不友好,我们通常需要自己增加一些说明来丰富文档内容。
Swagger使用的注解及其说明:
@Api:用在类上,说明该类的作用。
@ApiOperation:注解来给API增加方法说明。
@ApiImplicitParams : 用在方法上包含一组参数说明。
@ApiImplicitParam:用来注解来给方法入参增加说明。
@ApiResponses:用于表示一组响应
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
l code:数字,例如400
l message:信息,例如"请求参数没填好"
l response:抛出异常的类
@ApiModel:描述一个Model的信息(一般用在请求参数无法使用@ApiImplicitParam注解进行描述的时候)
l @ApiModelProperty:描述一个model的属性
例如:
- package com.example.demo.controller;
- import com.example.demo.entity.User;
- import com.example.demo.service.UserService;
- import io.swagger.annotations.Api;
- import io.swagger.annotations.ApiOperation;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- @RestController
- @RequestMapping("/user")
- @Api(tags="用户系统-用户管理")
- public class UserController {
- @Autowired
- private UserService userService;
- @GetMapping("updateMoblie")
- @ApiOperation(value="更新手机号", notes = "更新手机号接口")
- public String updateMoblie(Long userId){
- userService.updateMobile(userId);
- return "success";
- }
- }
结果如图

以上我们完成了spring boot与swagger的集成,但是使用springfox中的 RequestHandlerSelectors.basePackage("com.xxx") 只能支持单个包路径的扫描匹配,如果我们业务中分了多个包,swagger怎么能扫描到呢?
3: swagger 多包扫描配置
要解决这个问题,我们可以参考一下RequestHandlerSelectors.basePackage的源码
- public class RequestHandlerSelectors {
- private RequestHandlerSelectors() {
- throw new UnsupportedOperationException();
- }
- /**
- * Any RequestHandler satisfies this condition
- *
- * @return predicate that is always true
- */
- public static Predicate<RequestHandler> any() {
- return Predicates.alwaysTrue();
- }
- /**
- * No RequestHandler satisfies this condition
- *
- * @return predicate that is always false
- */
- public static Predicate<RequestHandler> none() {
- return Predicates.alwaysFalse();
- }
- /**
- * Predicate that matches RequestHandler with handlers methods annotated with given annotation
- *
- * @param annotation - annotation to check
- * @return this
- */
- public static Predicate<RequestHandler> withMethodAnnotation(final Class<? extends Annotation> annotation) {
- return new Predicate<RequestHandler>() {
- @Override
- public boolean apply(RequestHandler input) {
- return input.isAnnotatedWith(annotation);
- }
- };
- }
- /**
- * Predicate that matches RequestHandler with given annotation on the declaring class of the handler method
- *
- * @param annotation - annotation to check
- * @return this
- */
- public static Predicate<RequestHandler> withClassAnnotation(final Class<? extends Annotation> annotation) {
- return new Predicate<RequestHandler>() {
- @Override
- public boolean apply(RequestHandler input) {
- return declaringClass(input).transform(annotationPresent(annotation)).or(false);
- }
- };
- }
- private static Function<Class<?>, Boolean> annotationPresent(final Class<? extends Annotation> annotation) {
- return new Function<Class<?>, Boolean>() {
- @Override
- public Boolean apply(Class<?> input) {
- return input.isAnnotationPresent(annotation);
- }
- };
- }
- private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
- return new Function<Class<?>, Boolean>() {
- @Override
- public Boolean apply(Class<?> input) {
- return ClassUtils.getPackageName(input).startsWith(basePackage);
- }
- };
- }
- /**
- * Predicate 匹配RequestHandler,并为处理程序方法的类提供基本包名.
- * predicate 包括与所提供的basePackage匹配的所有请求处理程序
- *
- * @param basePackage - base package of the classes
- * @return this
- */
- public static Predicate<RequestHandler> basePackage(final String basePackage) {
- return new Predicate<RequestHandler>() {
- @Override
- public boolean apply(RequestHandler input) {
- return declaringClass(input).transform(handlerPackage(basePackage)).or(true);
- }
- };
- }
- private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
- return Optional.fromNullable(input.declaringClass());
- }
- }
我们看到 swagger 是通过Predicate 的apply 方法的返回值来判断是非匹配的 我们可以通过改造basePackage方法来实现多包扫描,改造 SwaggerConfig 如下
- package com.hzcominfo.sinopec.pos;
- import com.google.common.base.Function;
- import com.google.common.base.Optional;
- import com.google.common.base.Predicate;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import springfox.documentation.RequestHandler;
- import springfox.documentation.builders.ApiInfoBuilder;
- import springfox.documentation.builders.PathSelectors;
- import springfox.documentation.service.ApiInfo;
- import springfox.documentation.service.Contact;
- import springfox.documentation.spi.DocumentationType;
- import springfox.documentation.spring.web.plugins.Docket;
- import springfox.documentation.swagger2.annotations.EnableSwagger2;
- @Configuration
- @EnableSwagger2
- public class Swagger2 {
- // 定义分隔符
- private static final String splitor = ";";
- /**
- * 创建API应用
- * api() 增加API相关信息
- * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
- * 本例采用指定扫描的包路径来定义指定要建立API的目录。
- *
- * @return
- */
- @Bean
- public Docket api() {
- return new Docket(DocumentationType.SWAGGER_2)
- .apiInfo(apiInfo())
- .select()
- .apis(basePackage("com.hzcominfo.sinopec.pos.web.controller.mobilev1"
- + splitor
- + "com.hzcominfo.sinopec.pos.web.controller.mobilev2.api"))
- .paths(PathSelectors.any())
- .build();
- }
- //构建 api文档的详细信息函数,注意这里的注解引用的是哪个
- private ApiInfo apiInfo() {
- return new ApiInfoBuilder()
- //页面标题
- .title("XXX项目接口")
- //创建人
- .contact(new Contact("userName", "", "linzp@hzcominfo.com"))
- //版本号
- .version("1.0.0-SNAPSHOT")
- //描述
- .description("")
- .build();
- }
- public static Predicate<RequestHandler> basePackage(final String basePackage) {
- return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
- }
- private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
- return input -> {
- // 循环判断匹配
- for (String strPackage : basePackage.split(splitor)) {
- boolean isMatch = input.getPackage().getName().startsWith(strPackage);
- if (isMatch) {
- return true;
- }
- }
- return false;
- };
- }
- private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
- return Optional.fromNullable(input.declaringClass());
- }
- /**
- * swagger2原始ui
- * http://localhost:8080/swagger-ui.html
- *
- * swagger-ui-layer访问ui
- * http://localhost:8080/docs.html
- */
- }
swagger2:
swagger-ui-layer:
Spring boot集成Swagger2,并配置多个扫描路径,添加swagger-ui-layer的更多相关文章
- Spring Boot 集成 Swagger2 与配置 OAuth2.0 授权
Spring Boot 集成 Swagger2 很简单,由于接口采用了OAuth2.0 & JWT 协议做了安全验证,使用过程中也遇到了很多小的问题,多次尝试下述配置可以正常使用. Maven ...
- SpringBoot集成Swagger2并配置多个包路径扫描
1. 简介 随着现在主流的前后端分离模式开发越来越成熟,接口文档的编写和规范是一件非常重要的事.简单的项目来说,对应的controller在一个包路径下,因此在Swagger配置参数时只需要配置一 ...
- Spring boot集成swagger2
一.Swagger2是什么? Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件. Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格 ...
- 解决Spring Boot集成Shiro,配置类使用Autowired无法注入Bean问题
如题,最近使用spring boot集成shiro,在shiroFilter要使用数据库动态给URL赋权限的时候,发现 @Autowired 注入的bean都是null,无法注入mapper.搜了半天 ...
- Spring Boot 集成Swagger2生成RESTful API文档
Swagger2可以在写代码的同时生成对应的RESTful API文档,方便开发人员参考,另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API. 使用Spring Boot可 ...
- Spring Boot 集成 Swagger2 教程
上篇讲过 Spring Boot RESTful api ,这篇简单介绍下 SwaggerUI 在 Spring Boot 中的应用. Swagger 是一个规范和完整的框架,用于生成.描述.调用和可 ...
- spring boot 集成swagger2
1 在pom.xml中加入Swagger2的依赖 <dependency> <groupId>io.springfox</groupId> <artifac ...
- Spring Boot之Swagger2集成
一.Swagger2简单介绍 Swagger2,它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档.它既可以减少我们创建文档的工作量,同时 ...
- spring boot集成redis基础入门
redis 支持持久化数据,不仅支持key-value类型的数据,还拥有list,set,zset,hash等数据结构的存储. 可以进行master-slave模式的数据备份 更多redis相关文档请 ...
随机推荐
- 【转载,备忘】SQL Server 更改跟踪(Chang Tracking)监控表数据
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 主要区别与对比(Compare) 实现监控表数据步骤(Process) 参考文献(Refere ...
- Java课堂笔记1
1. Java严格区分大小写 2. 一个源文件public主类名必须和文件名完全一致 3. 命名规则严格要求,字母.数字.下划线.美元符号$.下划线_组成,其中不能以数字开头,也不能使用Java的 ...
- centos7查看防火墙状态、关闭防火墙
查看防火墙状态: firewall-cmd --state 关闭防火墙: systemctl stop firewalld.service 禁止firewall开机启动: systemctl disa ...
- vue中ref在input中详解
当我们在项目中遇见文本输入框的时候,获取时刻输入框中的值 1.v-model <template> <input type="text" v-model=&quo ...
- t100 常用公用變數
g_enterprise 目前的企業代碼,將限制使用者所能閱讀的資料內容g_prog 目前執行的作業編號,用於變換畫面顯示資料與產生系統資訊,不可變更g_code 目前執行的程式代碼(4gl)名稱,不 ...
- 记一次redis主从同步失败
zabbix告警突然从某个时间点开始提示CPU使用高,网卡流量也一直居高不下. 首先查看redis日志,发现告警时间点redis主节点被重启了,发生了主备切换,并且在日志中发现这么一段 [3081] ...
- go 学习笔记 ----资源自动回收
在释放局部资源时, 可以用defer管理 Go语言版本基于defer的Mutex用法 func safeRead(Mutex *mu) []byte { mu.Lock() defer mu.Unlo ...
- FORM表单 onclick()与onsubmit()
FORM表单中onclick().submit()与onsubmit()的问题 最近遇到一次处理form数据的过滤,采用了button的onclick事件来检查,发现return false后表单仍然 ...
- Python基础知识(三)
Python基础知识(三) 一丶整型 #二进制转成十进制的方法 # 128 64 32 16 8 4 2 1 1 1 1 1 1 1 例如数字5 : 101 #十进制转成二进制的方法 递归除取余数,从 ...
- if __name__ == '__main__' 该如何理解
Python 中的 if __name__ == '__main__' 该如何理解 程序入口 对于很多编程语言来说,程序都必须要有一个入口,比如 C,C++,以及完全面向对象的编程语言 Java,C# ...