SpringBoot集成knife4j实现Swagger接口文档
前言:如果你是后台开发,提供restful接口给前端,建议你使用Swagger3提供restful的接口文档自动生成和在线接口调试。knife4j是对Swagger进一步封装,其优化了API文档的UI界面,是本人最推荐的方式。一、Swagger简介1.1、SwaggerSwagger是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。Swagger拥有接口文
前言:如果你是后台开发,提供restful接口给前端,建议你使用Swagger3提供restful的接口文档自动生成和在线接口调试。knife4j是对Swagger进一步封装,其优化了API文档的UI界面,是本人最推荐的方式。
一、Swagger简介
1.1、Swagger
Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。Swagger拥有接口文档自动生成和在线调试接口的两大功能。Swagger拥有众多不同语言和平台的开源实现与工具,他有很多实现方式,非常方便,并且支持语言特别多。
(1) 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) springfox-swagger
在Spring中集成Swagger会使用到springfox-swagger
,它对Spring和Swagger的使用进行了整合
springfox是Java对swagger的一个具体实现。springfox的前身是swagger-springmvc,用于springmvc与swagger的整合。它内部会自动解析Spring容器中Controller暴露出的接口,并且也提供了一个界面用于展示或调用这些API。
Springfox其实是一个通过扫描代码提取代码中的信息,生成API文档的工具
。在Swagger的教程中,都会提到@Api
、@ApiModel
、@ApiOperation
这些注解,这些注解其实不是Springfox的,而是Swagger
的。springfox-swagger2
这个包依赖了swagger-core
这个包,而这些注解正是在这里面。但是,swagger-core
这个包是只支持JAX-RS2
的,并不支持常用的Spring MVC
。这就是springfox-swagger
的作用了,它将上面那些用于JAX-RS2
的注解适配到了Spring MVC
上。
Spring项目引入依赖:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
SpingBoot项目引入依赖:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
(3)Swagger 3 的使用
Swagger2(基于openApi2)已经在17年停止维护了,取而代之的是 Swagger3(基于openApi3),而国内 Swagger3使用的文档较少,百度搜出来的都是过时的Swagger2(17年停止维护并更名为swagger3)的使用。
-
Open API:OpenApi是业界真正的 api 文档标准,其是由 Swagger 来维护的,并被linux列为api标准,从而成为行业标准。
-
Swagger组织:swagger 是一个 api 文档维护组织,后来成为了 Open API 标准的主要定义者,现在最新的版本为17年发布的 Swagger3(Open Api3)。
-
swagger2的包名为 io.swagger,而swagger3的包名为 io.swagger.core.v3。
Swagger 3 相关特性:
-
支持 Spring 5,Webflux(仅请求映射支持,尚不支持功能端点)、Spring Integration
-
补充官方在 spring boot 的自动装配 springfox-boot-starter 以后可以直接依赖一个 dependency
-
与2.0更好的规范兼容性
-
支持OpenApi 3.0.3
-
轻依赖 spring-plugin,swagger-core
-
现有的swagger2批注将继续有效并丰富开放式API 3.0规范
1.2、springfox-swagger-ui
如果使用springfox-swagger-ui
,启动项目后的api文档访问路径:http://localhost:8080/swagger-ui.html
1.3、swagger-bootstrap-ui
swagger-bootstrap-ui是springfox-swagger的增强UI实现,api文档结构更加清晰,在线调试也很方便
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>${swagger.bootstrap.ui.version}</version>
</dependency>
访问的url为:http:// http://localhost:8080/doc.html
1.4、swagger-bootstrap-ui的升级版Knife4j
Knife4j在更名之前,原来的名称是叫swagger-bootstrap-ui,这是两种不一样风格的ui显示,将原来的蓝色变成炫酷的黑色模式,比传统的
springfox-swagger-ui和
swagger-bootstrap-ui更好看
,Knife4j是本人最推荐的方式。
-
Knifej是使用knife4j-spring-boot-starter的风格来编写的,可以将配置项写在配置文件中,这些配置项提供了许多增强功能,可以更好的整合springboot、springcloud;
-
Knifej执行更新,为了更平滑的演进,而swagger-bootstrap-ui已停更;
1.5、SpringDoc(可选)
SpringDoc也是 Spring 社区维护的一个项目(非官方),帮助使用者将 swagger3 集成到 Spring 中。也是用来在 Spring 中帮助开发者生成文档,并可以轻松的在SpringBoot中使用。SpringDoc基于swagger,并做了更多的对Spring系列各框架的兼容,用法上与Swagger3基本相同,并多了一些自己的配置,相较于Swagger3来说更好用,支持也更好一点。
从 spring-fox 迁移到 springdoc,需要依赖变更:pom.xml 里去掉 springfox 或者 swagger 的依赖,并添加springdoc-openapi-ui
。
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.3.1</version>
</dependency>
SpringDoc使用 swagger3 注解代替 swagger2 的:
这一步是可选的,因为改动太大,故 springfox对旧版的 swagger做了兼容处理。但不知道未来会不会不兼容,这里列出如何用 swagger 3 的注解代替 swagger 2 的,注意修改 swagger 3 注解的包路径为io.swagger.v3.oas.annotations。
Swagger2 的注解命名以易用性切入,全是 Api 开头,在培养出使用者依赖注解的习惯后,Swagger 3将注解名称规范化和工程化:
如果感兴趣,可以参考:SpringBoot结合SpringDo
二、Knife4j代替springfox-boot-starter实现Swagger3
Swagger用来自动生成API接口文档,还可以在线调试;而knife4j是对Swagger进一步封装,其优化了API文档的UI界面。
Knife4j
的前身是swagger-bootstrap-ui,
取名knife4j是希望她能像一把匕首一样小巧轻量并且功能强悍,希望把她做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于UI前端。
2.1、导入Knife4j依赖
-
SpringFox是对Swagger的SpringMVC的支持融合,Knife4是对Swagger进一步封装,其优化了api文档的界面
-
Knife4j在更名之前,原来的名称是叫swagger-bootstrap-ui。Knife4j底层依赖springfox,因此无需再单独引入springfox的具体版本
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
2.2、创建Knife4jConfig配置类
import com.hs.notice.entity.EmailNotice;
import com.hs.notice.entity.SmsNotice;
import com.hs.notice.entity.WeChatNotice;
import com.fasterxml.classmate.TypeResolver;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
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.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;
/**
* 作用: 自动生成API文档和在线接口调试工具
*/
@Configuration
//该注解是Springfox-swagger框架提供的使用Swagger注解,该注解必须加
@EnableSwagger2
//knife4j提供的增强扫描注解,Ui提供了例如动态参数、参数过滤、接口排序等增强功能
@EnableKnife4j
public class Knife4jConfig {
/**
* 创建一个Docket的对象,相当于是swagger的一个实例 : 配置开发和测试环境下开启Swagger,生产发布时关闭
*
* RequestHandlerSelectors,配置要扫描接口的方式
* basePackage:指定扫描的包路径
* any:扫描全部
* none:全部不扫描
* withClassAnnotation:扫描类上的注解,如RestController
* withMethodAnnotation:扫描方法上的注解,如GetMapping
*
* @return
*/
@Autowired
TypeResolver typeResolver;
@Bean
public Docket createRestApi(Environment environment)
{
//设置显示的swagger环境信息,判断是否处在自己设定的环境当中,为了安全生产环境不开放Swagger
Profiles profiles=Profiles.of("dev","test");
boolean flag=environment.acceptsProfiles(profiles);
//创建一个Docket的对象,相当于是swagger的一个实例
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.groupName("1.x版本")
.apiInfo(apiInfo())
//只有当springboot配置文件为dev或test环境时,才开启swaggerAPI文档功能
.enable(flag)
.select()
// 这里指定Controller扫描包路径:设置要扫描的接口类,一般是Controller类
.apis(RequestHandlerSelectors.basePackage("com.hs.notice.controller")) //这里采用包扫描的方式来确定要显示的接口
// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) //这里采用包含注解的方式来确定要显示的接口
// 配置过滤哪些,设置对应的路径才获取
.paths(PathSelectors.any())
.build()
//防止Controller中参数中没有实体类或者返回值不是实体类导致Swagger Models页面扫描不到的情况
.additionalModels(typeResolver.resolve(EmailNotice.class))
.additionalModels(typeResolver.resolve(SmsNotice.class))
.additionalModels(typeResolver.resolve(WeChatNotice.class));
}
///配置相关的api信息
private ApiInfo apiInfo()
{
return new ApiInfoBuilder()
.description("API调试文档")
//作者信息
.contact(new Contact("何哥", "http://ip地址:8086/doc.html", "110@qq.com"))
.version("v1.0")
.title("消息通知服务API文档")
//服务Url
.termsOfServiceUrl("")
.build();
}
}
如上代码所示,通过@Configuration注解,让Spring来加载该类配置。
- @ EnableSwagger2支持Swagger 2的SpringFox支持。
-
DocumentationType.SWAGGER_2告诉Docketbean我们正在使用Swagger规范的版本2。
-
apiInfo()用来创建该Api的基本信息(这些基本信息会展现在文档页面中)。
-
select()创建一个构建器,用于定义哪些控制器及其生成的文档中应包含哪些方法。
-
apis()定义要包含的类(控制器和模型类)。这里我们包括所有这些,但您可以通过基础包,类注释等来限制它们。SpringFox会将其检测为文档生成源。Controller和Model类。您可以在Docket配置中轻松配置它。我们可以使用.apis(RequestHandlerSelectors.any(来包含所有类;当然我们也可以缩小到我们的基础包。
-
paths()允许您根据路径映射定义应包含哪个控制器的方法。我们现在包括所有这些,但您可以使用正则表达式等限制它。上面的代码.paths(PathSelectors.any())是代表匹配所有URL。
2.3、创建User实体类
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "用户实体")
public class User {
@ApiModelProperty(value = "id")
private Integer id;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "性别,0男,1女")
private Integer sex;
}
2.4、创建UserController接口
package com.example.demo.controller;
import com.example.demo.User;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
@RestController
@Api(tags = "用户接口")//描述UserController的信息
public class UserController {
@ApiOperation(value = "查询用户",notes = "根据id查询用户")
@ApiImplicitParam(paramType = "path",name="id",value = "用户id",required = true)
@GetMapping("/user/query/{id}")
public String getUserById(@PathVariable Integer id) {
return "/user/"+id;
}
@ApiResponses({
@ApiResponse(code=200,message="删除成功"),
@ApiResponse(code=500,message="删除失败")})
@ApiOperation(value = "删除用户",notes = "根据id删除用户")
@DeleteMapping("/user/delete/{id}")
public Integer deleteUserById(@PathVariable Integer id) {
return id;
}
@ApiOperation(value = "添加用户",notes = "添加一个用户,传入用户名和性别")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "query",name="username",value = "用户名",required = true,defaultValue = "张三"),
@ApiImplicitParam(paramType = "query",name="sex",value = "性别",required = true,defaultValue = "女")
})
@PostMapping("/user")
public String addUser(@RequestParam String username,@RequestParam String sex){
return username+","+sex;
}
@ApiOperation(value="修改用户",notes = "根据传入的用户信息修改用户")
@PutMapping("/user")
public String updateUser(@RequestBody User user){
return user.toString();
}
@GetMapping("/ignore")
@ApiIgnore
public void ignoreMethod(){}
}
2.5、启动项目,访问Swagger文档
启动项目,在浏览器输入http://localhost:8080/doc.html就可以看到接口的信息,展开接口,就能看到所有的接口详细信息。
展开后可以对各个请求进行测试。选择接口后点击调试,输入相关的参数点击发送按钮即可。
页面简单清爽 ,可以导出接口文档非常方便,赶紧来试试吧
三、Swagger常用注解
@Api:用在请求的类上,表示对类的说明
tags="说明该类的作用,可以在UI界面上看到的注解"
value="该参数没什么意义,在UI界面上也看到,所以不需要配置"
@ApiOperation:用在请求的方法上,说明方法的用途、作用
value="说明方法的用途、作用"
notes="方法的备注说明"
@ApiImplicitParams:用在请求的方法上,表示一组参数说明
@ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传
paramType:参数放在哪个地方
· header --> 请求参数的获取:@RequestHeader
· query --> 请求参数的获取:@RequestParam
· path(用于restful接口)--> 请求参数的获取:@PathVariable
· body(不常用)
· form(不常用)
dataType:参数类型,默认String,其它值dataType="Integer"
defaultValue:参数的默认值
@ApiResponses:用在请求的方法上,表示一组响应
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
code:数字,例如400
message:信息,例如"请求参数没填好"
response:抛出异常的类
@ApiModel:用于响应类上,表示一个返回响应数据的信息
(这种一般用在post创建的时候,使用@RequestBody这样的场景,
请求参数无法使用@ApiImplicitParam注解进行描述的时候)
@ApiModelProperty:用在属性上,描述响应类的属性
3.1、Model类使用
@Data
@ApiModel(value="BizComponent对象", description="组件")
public class BizComponent implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty(value = "分类")
private Long categoryId;
@ApiModelProperty(value = "组件名称")
private String name;
@ApiModelProperty(value = "组件描述")
private String description;
@ApiModelProperty(value = "日期字段")
private LocalDateTime componentTime;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty(value = "修改时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime modifiedTime;
}
3.2、Control类和接口方法使用
@RestController
@RequestMapping("/api/category")
@Api(value = "/category", tags = "组件分类")
public class BizCategoryController {
private IBizCategoryService bizCategoryService;
@GetMapping("/list")
@ApiOperation(value = "列表", notes = "分页列表")
public R<PageModel<BizCategory>> list(PageQuery pageQuery,
@RequestParam @ApiParam("组件分类名称") String name) {
IPage<BizCategory> page = bizCategoryService.page(pageQuery.loadPage(),
new LambdaQueryWrapper<BizCategory>().like(BizCategory::getName, name));
return R.success(page);
}
@GetMapping("/{categoryId}")
@ApiOperation(value = "详情", notes = "组件分类详情")
@ApiResponses({
@ApiResponse(code=200,message="请求成功"),
@ApiResponse(code=100,message="请求失败")})
public R<BizCategory> detail(@PathVariable @ApiParam("分类Id") Long categoryId) {
BizCategory category = bizCategoryService.getById(categoryId);
return R.success(category);
}
@PostMapping("/save")
@ApiOperation(value = "保存", notes = "新增或修改")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "form", name = "categoryId", value = "组件id(修改时为必填)"),
@ApiImplicitParam(paramType = "form", name = "name", value = "组件分类名称", required = true)
})
public R<BizCategory> save(Long categoryId, String name) {
BizCategory category = new BizCategory();
category.setId(categoryId);
category.setName(name);
bizCategoryService.saveOrUpdate(category);
return R.success(category);
}
@DeleteMapping("/{categoryId}")
@ApiOperation(value = "删除", notes = "删除")
public R delete(@PathVariable @ApiParam("分类Id") Long categoryId) {
bizCategoryService.delete(categoryId);
return R.success();
}
}
四、企业项目中比较实用的用法
4.1、忽略不想生成文档的接口
某些Controller 不需要生成API文档的接口,可以通过@ApiIgnore忽略掉
4.2、开发环境开启Swagger ,生产环境关闭
虽然说swagger是个好东西,但是使用中切不可以忽略的一个安全问题。dev环境中你可以开放swagger给前端或者测试,但如果你的swagger ui不小心放到了生产,那是一件多么可怕的事情,真可以来个一锅端,切记切记。
@Value("${swagger.switch}")
private boolean swaggerSwitch;
@Bean
public Docket api() {
Docket docket = new Docket(DocumentationType.SWAGGER_2);
if (swaggerSwitch) {
docket.enable(true);
} else {
docket.enable(false);
}
docket.apiInfo(apiInfo()).select().paths(PathSelectors.any()).build();
return docket;
}
4.3、Swagger UI中 model实体类不显示解决方案
方式一:只要在接口中,返回值中存在实体类,就会被扫描到swagger中
@PostMapping("/account")
public Account user(){
return new Account();
}
方式二:在controller 使用 @RequestBody 注解
Swagger的model里面之所以没有你需要的model,是因为你的model没有被swagger发现,我们利用Spring的注解让这个类被发现就行
@ApiOperation(value = "添加用户", notes = "添加新用户")
@PostMapping("/add")
public Map addUser( @RequestBody Account account){
return userService.createUser(account);
}
方式三:在Swagger的配置Bean中,手动的添加你想呈现的类,如下最后三行,可以写很多个typeResolver.resolve(XXX.class)作为参数传入
import com.fasterxml.classmate.TypeResolver;
@Autowired
TypeResolver typeResolver;
@Bean
public Docket createRestApi(Environment environment)
{
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.groupName("1.x版本")
.apiInfo(apiInfo())
.enable(true)
.select()
.apis(RequestHandlerSelectors.basePackage("com.hs.notice.controller"))
.paths(PathSelectors.any())
.build()
//防止Controller中参数中没有实体类或者返回值不是实体类导致Swagger Models页面扫描不到的情况
.additionalModels(typeResolver.resolve(EmailNotice.class))
.additionalModels(typeResolver.resolve(SmsNotice.class))
.additionalModels(typeResolver.resolve(WeChatNotice.class));
}
4.4、Knife4j文档请求异常
报错信息如下:
java.lang.NullPointerException: null
at springfox.documentation.swagger2.mappers.RequestParameterMapper.bodyParameter(RequestParameterMapper.java:264) ~[springfox-swagger2-3.0.0.jar:3.0.0]
错误原因:
极有可能就是,给参数变量重命名了,导致Controller入参和API写的参数对应不上
比如下面代码中的Api提示参数的name = "errorDeviceState"
,但实际参数写的却是 errorDeviceStateEnum
@ApiOperation("查看单个完整巡检报告")
@GetMapping
@ApiImplicitParams({
@ApiImplicitParam(name = "inspectId", value = "巡检任务ID", dataTypeClass = String.class),
@ApiImplicitParam(name = "errorDeviceState", value = "设备巡检状态(1异常,2离线)", dataTypeClass = ErrorDeviceStateEnum.class)
})
public WebResult<ReportVO> queryDetail(@RequestParam String inspectId, @RequestParam ErrorDeviceStateEnum errorDeviceStateEnum) {
// code ...
}
4.5、Swagger文档中的调试界面请求参数丢失
问题描述:请求参数本来应该是x-www-form-urlencoded方式的,却变成了raw方式,丢失content参数
解决方案:丢失参数content前面加上个@RequestParam注解就可以了
sendMessage(String openid,@RequestParam @Length(max=1024) String content,String appId,String t_sign,String requestId)
4.6、本地swagger使用localhost/doc.html不能访问
localhost/doc.html换为127.0.0.1/doc.html
参考链接:
更多推荐
所有评论(0)