用于快速生成接口文档,并在线测试,接口文档也实时更新。官方链接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容器中
@Configuration
public class SwaggerCfg {
@Bean
public 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方法
@Configuration
public class SwaggerCfg {
@Bean
public 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环境还是生产环境。
@Bean
public Docket docket(Environment environment){
//获取配置文件激活的环境是否有dev,test
Boolean 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实例即可。
@Configuration
public class SwaggerCfg {
@Bean
public Docket userDocket(Environment environment){
//获取配置文件激活的环境是否有dev,test
Boolean 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();
}
@Bean
public Docket docket(Environment environment){
//获取配置文件激活的环境是否有dev,test
Boolean 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 {
@Autowired
private 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里面的参数也生成了,我们可以对这些参数进行忽略
@Bean
public Docket docket(Environment environment){
//获取配置文件激活的环境是否有dev,test
Boolean 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方法
@Bean
public Docket userDocket(Environment environment){
//获取配置文件激活的环境是否有dev,test
Boolean 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 {
@Autowired
private 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 {
@Autowired
private 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 {
@Autowired
private 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 {
@Autowired
private 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;
@Configuration
public class SwaggerCfg {
@Autowired
private Environment environment;
@Bean
public Docket group1() {
return groupDocket("/(正则表达式)",
"分组1", "描述");
}
@Bean
public Docket group2() {
return groupDocket("/(正则表达式)",
"分组2", "描述");
}
@Bean
public 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();
}
}
总结:非常优秀的接口调试工具。