赞
踩
目录
1. @ApiModel与@ApiModelProperty 实体描述
4. @ApiImplicitParams与@ApiImplicitParam 参数描述
尤其在当前前后端分离的大趋势下,编写和维护开发接口的文档是每个程序员必要的职责。Swagger 首先是一个规范、完整和统一的接口文档维护规范/标准。在这个标准下,Swagger官方提供了很多基于该标准的自动化接口维护工具,用于生成、描述、调用和可视化接口文档的Web 服务。该工具主要包括以下三个部分:
在SpringBoot中,由于Swagger的大流行,Spring 基于Swagger 的标准/规范,开发了一套适用于Spring生态的接口工具框架 Springfox-swagger ,可以将基于SpringMVC和Spring Boot项目的项目代码,按照Swagger规范自动生成JSON格式的描述文件并进行展示。Swagger发展到今天,已经有2.x和3.x两种主流的大版本,同样Springfox-swagger也有两种相应的版本,两种版本略有不同,我们这里主要讲Swagger3的整合与使用。
springfox-boot-starter 该starter包含了一些swagger必要的自动配置类和启动器,其主要包括:
- springfox-swagger:swagger核心,生成接口文档的Json格式数据
- springfox-swagger-ui:swagger可视化,将Json数据可视化展示
- <dependency>
- <groupId>io.springfox</groupId>
- <artifactId>springfox-boot-starter</artifactId>
- <version>3.0.0</version>
- </dependency>
spring boot 2.6.x或更高版本集成Swagger时,直接运行会出现异常信息报错(空指针),主要原因是:Spring Boot 2.6及 更高版本使用的默认路径匹配规则是PathPatternMatcher,而Springfox使用的路径匹配是基于AntPathMatcher的。所以这里需要更改一下SpringBoot配置。
- spring:
- mvc:
- pathmatch:
- matching-strategy: ant_path_matcher
-
配置类中各部分配置的含义都已经通过注释说明了,这里主要介绍RequestHandlerSelectors和PathSelectors的接口扫描与展示过滤规则,其中:
- RequestHandlerSelectors:
- any():扫描项目所有包下的所有接口
- none():不扫描接口
- withMethodAnnotation:通过方法上的指定注解扫描接口
- withClassAnnotation:通过类上的指定注解扫描接口
- basePackage:根据包路径扫描接口
- PathSelectors:
- any() :任何接口路径Url都扫描展示
- none():任何接口路径Url都不扫描展示
- regex:通过正则表达式控制接口路径Url扫描展示
- ant:通过 ant 路径匹配控制接口路径Url扫描展示
- @Configuration //声明配置类
- @EnableOpenApi //开启swagger支持
- public class SwaggerConfig {
-
- /**
- * Docket类是Swagger的配置类,要自定义修改Swagger的默认配置信息,我们需要覆盖该对象
- * @return
- */
- @Bean
- public Docket docket(){
- //1.以OAS_30标准构建Docket配置类
- return new Docket(DocumentationType.OAS_30)
- //2.配置Swagger接口文档基本信息apiInfo
- .apiInfo(apiInfo())
- //3.select方法开启配置扫描接口的Builder
- .select()
- //4.指定要扫描/维护接口文档的包(否则就全部扫描)
- .apis(RequestHandlerSelectors.basePackage("com.example.bootswagger.controller"))
- //5.路径过滤:该Docket-UI展示时,只展示指定路径下的接口文档(any表示都展示)
- .paths(PathSelectors.any())
- .build();
- }
-
- /**
- * 配置 Swagger 接口文档的基本信息
- * @return
- */
- private ApiInfo apiInfo(){
- return new ApiInfoBuilder()
- //1.接口文档标题
- .title("SpringBoot整合Swagger")
- //2.接口文档描述内容
- .description("这里是SpringBoot整合Swagger的详细信息......,包括...")
- //3.项目文档迭代版本
- .version("9.0")
- //4.主要联系人信息(姓名name,个人主页url,邮箱email)
- .contact(new Contact("阿安","www.baidu.com","1436218372@qq.com"))
- //5.相关许可证信息
- .license("The CSDN License")
- //6.相关许可证链接
- .licenseUrl("www.baidu.com")
- //7.返回构建的ApiInfo对象
- .build();
- }
- }
配置完成后启动SpringBoot项目,访问 http://localhost:8080/swagger-ui/index.html 或 http://localhost:8080/swagger-ui/ 即可看到生成的接口文档。
在实际开发中,可能是是由很多人来共同开发一组接口功能,每个人负责不同的部分。那么对于每个人/每个小组负责的文档部分也应该进行分组,使得开发过程更加清晰。在Swagger实现中,一个Docket配置类对应一组文档配置,既然要进行分组,那么分几组我们就要分别配置几个相应的Docket对象,然后通过groupName()方法配置分组信息(名称)。
- @Configuration //声明配置类
- @EnableOpenApi //开启swagger支持
- public class SwaggerConfig {
-
- /**
- * 配置分组文档 docketA :该部分文档由王五负责,主要涉及UserController相应接口的开发,对应url为 /user/**
- * @return
- */
- @Bean
- public Docket docketA(){
- //1.以OAS_30文档标准构建Docket配置类
- return new Docket(DocumentationType.OAS_30)
- //2.配置Swagger接口文档基本信息apiInfoA
- .apiInfo(apiInfoA())
- //3.配置文档分组-名称
- .groupName("docketA")
- //4.select方法开启配置扫描接口的Builder
- .select()
- //5.指定要扫描/维护接口文档的包:bootswagger.controller
- .apis(RequestHandlerSelectors.basePackage("com.example.bootswagger.controller"))
- //6.指定路径过滤规则:docketA只展示 /user/** 路径下的接口描述(配合包扫描)
- .paths(PathSelectors.ant("/user/**"))
- .build();
- }
-
- /**
- * 配置分组文档 docketB :该部分文档由李四负责,主要涉及AdminController相应接口的开发,对应url为 /admin/**
- * @return
- */
- @Bean
- public Docket docketB(){
- //1.以OAS_30文档标准构建Docket配置类
- return new Docket(DocumentationType.OAS_30)
- //2.配置Swagger接口文档基本信息apiInfoB
- .apiInfo(apiInfoB())
- //3.配置文档分组-名称
- .groupName("docketB")
- //4.select方法开启配置扫描接口的Builder
- .select()
- //5.指定要扫描/维护接口文档的包:bootswagger.controller
- .apis(RequestHandlerSelectors.basePackage("com.example.bootswagger.controller"))
- //6.指定路径过滤规则:docketA只展示 /user/** 路径下的接口描述(配合包扫描)
- .paths(PathSelectors.ant("/admin/**"))
- .build();
- }
-
- /**
- * 配置 文档A 的基本信息
- * @return
- */
- private ApiInfo apiInfoA(){
- return new ApiInfoBuilder()
- //1.接口文档标题
- .title("文档A:SpringBoot整合Swagger")
- //2.接口文档描述内容
- .description("这里是SpringBoot整合Swagger的详细信息......,包括...")
- //3.项目文档迭代版本
- .version("9.0")
- //4.主要联系人信息(姓名name,个人主页url,邮箱email)
- .contact(new Contact("王五","www.baidu.com","1436218372@qq.com"))
- //7.返回构建的ApiInfo对象
- .build();
- }
-
- /**
- * 配置 文档B 的基本信息
- * @return
- */
- private ApiInfo apiInfoB(){
- return new ApiInfoBuilder()
- //1.接口文档标题
- .title("文档B:SpringBoot整合Swagger")
- //2.接口文档描述内容
- .description("这里是SpringBoot整合Swagger的详细信息......,包括...")
- //3.项目文档迭代版本
- .version("2.0")
- //4.主要联系人信息(姓名name,个人主页url,邮箱email)
- .contact(new Contact("李四","www.baidu.com","1436218372@qq.com"))
- //7.返回构建的ApiInfo对象
- .build();
- }
- }
- @ApiModel(value="实体类名称",description="实体类描述"):标注在实体类上,用于对实体类进行描述说明
- @ApiModelProperty(value="简要描述",hidden=false,dataType="数据类型"):标注于实体类属性或方法上,用于对实体类的属性或方法进行描述说明。其中hidden表示是否隐藏该属性(默认为false)
- @ApiModel(description = "此实体类封装了返回值结果,包括状态码与返回值消息...")
- public class ResultVo {
-
- @ApiModelProperty(value = "状态码",hidden = false,dataType = "Integer")
- private Integer code;
-
- @ApiModelProperty(value = "响应消息",hidden = false,dataType = "String")
- private String message;
-
- public Integer getCode() {
- return code;
- }
-
- public void setCode(Integer code) {
- this.code = code;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- @Override
- public String toString() {
- return "ResultVo{" +
- "code=" + code +
- ", message='" + message + '\'' +
- '}';
- }
- }
注意:接口方法所涉及的实体类(出现在接口方法的返回值、参数上等方式)都会自动被扫描并插入到接口文档中。所以并不是因为@ApiModel这个注解让实体类显示,而@ApiModel和@ApiModelProperty这两个注解只是为显示的实体添加注释说明的。
- @Api(tags = "接口模块类描述说明"):该注解标注在接口模块类上,用于对接口模块类进行描述说明
- @RestController
- @RequestMapping("/user")
- @Api(tags = "用户请求处理Controller")
- public class UserController {
-
- }
- @ApiOperation(value="接口方法简要说明",notes="接口方法详细描述",response=Class<T>):该注解标注在接口模块类的接口方法上,用于对接口方法进行描述说明。其中notes字段可以插入HTML标签,response字段表示该方法的返回值类型。
- @RestController
- @RequestMapping("/user")
- @Api(tags = "用户请求处理Controller")
- public class UserController {
-
- @ApiOperation(value = "用户登陆方法",notes = "<span style='color:red;'>描述:</span> 用来执行用户登录方法的接口",response = ResultVo.class)
- @RequestMapping(value = "/login",method = RequestMethod.GET)
- public ResultVo loginUser(){
- ResultVo resultVo = new ResultVo();
- resultVo.setCode(1);
- resultVo.setMessage("Login SUCCESS");
- return resultVo;
- }
-
- @ApiOperation(value = "用户注册方法",notes = "<span style='color:red;'>描述:</span> 用来执行用户注册方法的接口",response = ResultVo.class)
- @RequestMapping(value = "/register",method = RequestMethod.GET)
- public ResultVo registerUser(){
- ResultVo resultVo = new ResultVo();
- resultVo.setCode(2);
- resultVo.setMessage("Register SUCCESS");
- return resultVo;
- }
- }
- @ApiImplicitParams(list=[ ]):该注解作用在接口方法上,是ApiImplicitParam的列表
- @ApiImplicitParam(name="参数名称",value = "参数说明",defaultValue = "参数默认值",dataType = "数据类型"):该注解作用于ApiImplicitParams列表内,用于对方法上的参数进行描述说明。
- @RestController
- @RequestMapping("/user")
- @Api(tags = "用户请求处理Controller")
- public class UserController {
-
- @ApiOperation(value = "用户登陆方法",notes = "<span style='color:red;'>描述:</span> 用来执行用户登录方法的接口",response = ResultVo.class)
- @RequestMapping(value = "/login",method = RequestMethod.GET)
- @ApiImplicitParams({
- @ApiImplicitParam(name="username",value = "用户名",defaultValue = "admin",dataType = "String"),
- @ApiImplicitParam(name="userInfo",value = "用户信息",defaultValue = "nothing",dataType = "String")
- })
- public ResultVo loginUser(String userName,String userInfo){
- System.out.println(userName);
- System.out.println(userInfo);
- ResultVo resultVo = new ResultVo();
- resultVo.setCode(1);
- resultVo.setMessage("Login SUCCESS");
- return resultVo;
- }
-
- }
注意:参数使用@RequestBody时,@ApiImplicitParam的type就不要使用body了,二者相互冲突,可以使用 @ApiParam 处理。而且不使用@RequestBody时,@ApiImplicitParam将参数统一附加到地址url;使用@RequestBody后,不再附加。
Swagger原生官方依赖不提供文档导出功能,只能网页在线查看。所以要实现接口文档导出,我们可以通过以下两种方式(注意url拦截器放行):
- 整合第三方Swagger-UI界面提供的文档导出功能(主要)
- bootstrap-UI
- Layui-UI
- mg-UI
- 整合第三方导出插件,实现文档导出功能
注意访问地址为:http://localhost:8080/doc.html
- <!-- 引入swagger-bootstrap-ui包 访问地址 /doc.html-->
- <dependency>
- <groupId>com.github.xiaoymin</groupId>
- <artifactId>swagger-bootstrap-ui</artifactId>
- <version>1.9.6</version>
- </dependency>
knife4j是bootstrap-UI的升级版。相比bootstrap-UI来说,knife4j功能更加完善和强大,并且其starter中已经封装了springfox,我们无需再次引入。官网文档地址:https://doc.xiaominfo.com/knife4j/
(1)如果开发者继续使用OpenAPI2的规范结构,底层框架依赖springfox2.10.5版本,那么可以考虑Knife4j
的2.x版本
- <dependency>
- <groupId>com.github.xiaoymin</groupId>
- <artifactId>knife4j-spring-boot-starter</artifactId>
- <version>2.0.9</version>
- </dependency>
(2)如果开发者使用OpenAPI3的结构,底层框架依赖springfox3.0.0,可以考虑Knife4j
的3.x版本
- <dependency>
- <groupId>com.github.xiaoymin</groupId>
- <artifactId>knife4j-spring-boot-starter</artifactId>
- <version>3.0.3</version>
- </dependency>
(3)除了引入starter不同,其他配置均与之前swagger配置相同。配置完成后,启动项目访问http://localhost:8080/doc.html 即可
在Shiro或SpringSecurity权限管理框架中,使用Swagger时访问文档主页会被拦截,因此我们需要配置放行相关swagger资源的访问请求。下面以Shiro整合为例:
- /**
- * 定义拦截器链,所有请求都经过自定义的jwt过滤器
- * @return
- */
- @Bean
- public ShiroFilterChainDefinition shiroFilterChainDefinition(){
- DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
- Map<String,String> filterRuleMap = new LinkedHashMap<>();
- //放行swagger资源
- filterRuleMap.put("/swagger-ui/**","anon");
- filterRuleMap.put("/swagger-resources/**","anon");
- filterRuleMap.put("/v3/**","anon");
- filterRuleMap.put("/webjars/**","anon");
- //jwt统一拦截
- filterRuleMap.put("/**","jwt");
- definition.addPathDefinitions(filterRuleMap);
- return definition;
- }
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。