用于快速生成接口文档,并在线测试,接口文档也实时更新。官方链接https://swagger.io/,
集成
官方starter
<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency><dependency><groupId>io.swagger</groupId><artifactId>swagger-models</artifactId><version>1.6.2</version></dependency>
访问如下地址
http://localhost:8080/swagger-ui/index.html
配置
需要将Swagger的Docket实例加到Spring容器中
@Configurationpublic class SwaggerCfg {@Beanpublic Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开"));}private ApiInfo apiInfo(String title, String desc) {Contact contact = new Contact("作者:李付发","http://www.baidu.com","1966591729@qq.com");return new ApiInfoBuilder().title(title).version("1.0.0").description(desc).contact(contact).build();}}

配置要扫描的接口
关键角色:Docket的select方法
@Configurationpublic class SwaggerCfg {@Beanpublic Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开")).select()//RequestHandlerSelectors配置要扫描接口的方式,basePackage指定要扫描的包//.apis(RequestHandlerSelectors.basePackage("com.lff.dr"))//withMethodAnnotation扫描方法上的注解.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))//过滤匹配.paths(PathSelectors.regex("/(xxx.)")).build();}private ApiInfo apiInfo(String title, String desc) {Contact contact = new Contact("作者:李付发","http://www.baidu.com","1966591729@qq.com");return new ApiInfoBuilder().title(title).version("1.0.0").description(desc).contact(contact).build();}}
开启和关闭Swagger功能
项目上线后我们应该关闭Swagger功能,防止通过Swagger来发起请求。Docket有个.enable方法用来设置是否开启。
new Docket(DocumentationType.SWAGGER_2).enable(false) //false表示开启,true表示关闭

思考:怎么根据项目的环境,也就是生产环境还是测试环境自动开启或关闭Swagger?
有一种比较好的方式是直接获取Spring配置文件中的如下内容
spring:profiles:active: dev
看一下active的值是dev环境还是生产环境。
@Beanpublic Docket docket(Environment environment){//获取配置文件激活的环境是否有dev,testBoolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));return new Docket(DocumentationType.SWAGGER_2).enable(enable).apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开")).select()//RequestHandlerSelectors配置要扫描接口的方式,basePackage指定要扫描的包//.apis(RequestHandlerSelectors.basePackage("com.lff.dr"))//withMethodAnnotation扫描方法上的注解.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).build();}
配置API文档分组
Docket有个groupName(“”)方法用于设置分组。
new Docket(DocumentationType.SWAGGER_2).groupName("数据字典分组")

思考:如何设置多个分组?
只需创建多个Docket Bean实例即可。
@Configurationpublic class SwaggerCfg {@Beanpublic Docket userDocket(Environment environment){//获取配置文件激活的环境是否有dev,testBoolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));return new Docket(DocumentationType.SWAGGER_2).groupName("用户组").enable(enable).apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开")).select().apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).build();}@Beanpublic Docket docket(Environment environment){//获取配置文件激活的环境是否有dev,testBoolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));return new Docket(DocumentationType.SWAGGER_2).groupName("数据字典分组").enable(enable).apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开")).select()//RequestHandlerSelectors配置要扫描接口的方式,basePackage指定要扫描的包//.apis(RequestHandlerSelectors.basePackage("com.lff.dr"))//withMethodAnnotation扫描方法上的注解.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).build();}private ApiInfo apiInfo(String title, String desc) {Contact contact = new Contact("作者:李付发","http://www.baidu.com","1966591729@qq.com");return new ApiInfoBuilder().title(title).version("1.0.0").description(desc).contact(contact).build();}}

忽略请求参数
Docket有个ignoredParameterTypes 方法用于设置忽略请求参数
比如我们的接口是这样写的
@RestController@RequestMapping("/dictTypes")public class DictTypeController {@Autowiredprivate DictTypeService service;@GetMapping("/list")@ApiOperation(value = "返回所有的数据字典类型",notes = "")public Map<String,Object> listAll(DictTypeQuery query, HttpSession session){Map<String,Object> map = new HashMap<>();map.put("code",0);map.put("data",service.list());return map;}}

会发现把HttpSession里面的参数也生成了,我们可以对这些参数进行忽略
@Beanpublic Docket docket(Environment environment){//获取配置文件激活的环境是否有dev,testBoolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));return new Docket(DocumentationType.SWAGGER_2).groupName("数据字典分组").enable(enable).ignoredParameterTypes(HttpSession.class,HttpServletRequest.class,HttpServletResponse.class).apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开")).select()//RequestHandlerSelectors配置要扫描接口的方式,basePackage指定要扫描的包//.apis(RequestHandlerSelectors.basePackage("com.lff.dr"))//withMethodAnnotation扫描方法上的注解.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).build();}
配置全局参数
我们有时需要配置全局参数,比如很多请求都需要传token参数,要求用户只有登录成功后才能访问资源(token一般是登录成功后返回给客户端的,客户端保存token)。
这时可以使用Docket的globalRequestParameters方法
@Beanpublic Docket userDocket(Environment environment){//获取配置文件激活的环境是否有dev,testBoolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));RequestParameter tokenParam = new RequestParameterBuilder().name("Token") //参数的名称.description("用户登录令牌").in(ParameterType.HEADER) //token放在请求头里面发送.build();return new Docket(DocumentationType.SWAGGER_2).groupName("用户组").enable(enable).globalRequestParameters(List.of(tokenParam)).ignoredParameterTypes(HttpSession.class,HttpServletRequest.class,HttpServletResponse.class).apiInfo(apiInfo("用户组模块","用户组描述")).select().apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).build();}

这样就很方便的模拟有token的请求了
常用注解
@APi
@Api(tags = "模块名") //用在Controller上
�实例
@RestController@RequestMapping("/dictTypes")@Api(tags = "数据字典类型")public class DictTypeController {@Autowiredprivate DictTypeService service;@GetMapping("/list")@ApiOperation(value = "返回所有的数据字典类型",notes = "")public Map<String,Object> listAll(DictTypeQuery query){Map<String,Object> map = new HashMap<>();map.put("code",0);map.put("data",service.list());return map;}}
@ApiOperation
@ApiOperation(value = "用途",notes = "备注")
实例
@RestController@RequestMapping("/dictTypes")@Api(tags = "数据字典类型")public class DictTypeController {@Autowiredprivate DictTypeService service;@GetMapping("/list")@ApiOperation(value = "返回所有的数据字典类型",notes = "可以传分页大小,第几页等")public Map<String,Object> listAll(DictTypeQuery query){Map<String,Object> map = new HashMap<>();map.put("code",0);map.put("data",service.list());return map;}}

@ApiModel、@ApiModelProperty
@ApiModel(value = "实体名称",description = "描述") //@ApiModel用在实体上@ApiModelProperty(value = "属性名描述",required = false,hidden = false) //@ApiModelProperty用在实体的属性上,required是否必传,hidden在Swagger是否显示
实例
@ApiModel(value = "DictTypeQuery",description = "数据字典类型查询参数")public class DictTypeQuery {@ApiModelProperty(value = "搜索关键字",required = false)private String keyWord;@ApiModelProperty(value = "客户端传递的页码",required = true)private Long page;@ApiModelProperty(value = "每页多少条数据")private Long size;@ApiModelProperty(hidden = true)private List<?> data;//查询的总页数@ApiModelProperty(hidden = true)private Long total;//总页数@ApiModelProperty(hidden = true)private Long pages;}
@ApiParam
@ApiParam(value = "请求参数描述",required = false,hidden = false)
实例
@RestController@RequestMapping("/dictTypes")@Api(tags = "数据字典类型")public class DictTypeController {@Autowiredprivate DictTypeService service;@GetMapping("/list")@ApiOperation(value = "返回所有的数据字典类型",notes = "可以传分页大小,第几页等")public Map<String,Object> listAll(DictTypeQuery query,@ApiParam("用户token") String token){Map<String,Object> map = new HashMap<>();map.put("code",0);map.put("data",service.list());return map;}}

如果结果返回的是实体模型数据,结果也有注释。
@RestController@RequestMapping("/dictTypes")@Api(tags = "数据字典类型")public class DictTypeController {@Autowiredprivate DictTypeService service;@GetMapping("/list")@ApiOperation(value = "返回测试数据",notes = "哈哈")public DictTypeQuery listAll(DictTypeQuery query){return new DictTypeQuery();}}

一个比较完整的示例
import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.env.Environment;import org.springframework.core.env.Profiles;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.builders.RequestParameterBuilder;import springfox.documentation.service.ApiInfo;import springfox.documentation.service.Contact;import springfox.documentation.service.ParameterType;import springfox.documentation.service.RequestParameter;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.util.List;@Configurationpublic class SwaggerCfg {@Autowiredprivate Environment environment;@Beanpublic Docket group1() {return groupDocket("/(正则表达式)","分组1", "描述");}@Beanpublic Docket group2() {return groupDocket("/(正则表达式)","分组2", "描述");}@Beanpublic Docket group3() {return groupDocket("/(正则表达式)","分组3", "描述");}public Docket basicDocket() {//根据环境是否启用Swagger功能boolean enable = environment.acceptsProfiles(Profiles.of("dev", "test"));//设置全局参数RequestParameter tokenParam = new RequestParameterBuilder().name("Token").description("用户登录令牌").in(ParameterType.HEADER).build();return new Docket(DocumentationType.SWAGGER_2)//设置全局参数.globalRequestParameters(List.of(tokenParam)).enable(enable).ignoredParameterTypes(HttpSession.class,HttpServletRequest.class,HttpServletResponse.class);}public Docket groupDocket(String regex, String title, String desc) {return basicDocket().groupName(title).apiInfo(apiInfo(title, desc)).select()//根据是否有ApiOperation的方法,生成Swagger文档.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.regex(regex)).build();}private ApiInfo apiInfo(String title, String desc) {Contact contact = new Contact("作者:李付发","http://www.baidu.com","1966591729@qq.com");return new ApiInfoBuilder().title(title).version("1.0.0").description(desc).contact(contact).build();}}
总结:非常优秀的接口调试工具。
