很多时候,后端开发需要把接口信息暴露给前台人员查看,一般来说可以使用Swagger展示接口Api。
这边使用Knife4j框架配置类,配置生成在线文档, 但是报错了:
“Cannot invoke org.springframework.web.servlet.mvc.condition.PatternsRequestCondition. getPatterns() " because “this.condition” is null”
在applicaiton.yml添加
#解决Cannot invoke "PatternsRequestCondition.getPatterns()"
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
Knife4j是一款在线API文档框架,可以基于当前项目的Controller控制器类中的配置生成文档,并自带调试功能。
在项目中使用Knife4j需要5个步骤:
pom.xml
中添加依赖:
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>knife4j-spring-boot-starterartifactId>
<version>2.0.9version>
dependency>
application.properties
/ application.yml
)中开启增强模式knife4j.enable
属性,取值为true
#Knife4j配置
knife4j:
# 开启增强模式 ,Spring 将使用bean来满足注入点的依赖关系
enable: true
#解决Cannot invoke "PatternsRequestCondition.getPatterns()"
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
config
包中,创建Knife4jConfiguration
配置类com.luoyang.small.controller
,必须是你项目中控制器类所在的包,代码如下:package com.luoyang.small.config;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.EnableSwagger2WebMvc;
/**
* Knife4j配置类
*
* @author luoyang
* @Date 2023/12/14
*/
@Slf4j
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {
/**
* 【重要】指定Controller包路径
*/
private String basePackage = "com.luoyang.small.controller";
/**
* 分组名称
*/
private String groupName = "product";
/**
* 主机名
*/
private String host = "http://java.luoyang.com";
/**
* 标题
*/
private String title = "后端项目Test在线API文档--商品管理";
/**
* 简介
*/
private String description = "测测测测测测测测测测测--商品管理";
/**
* 服务条款URL
*/
private String termsOfServiceUrl = "http://www.apache.org/licenses/LICENSE-2.0";
/**
* 联系人
*/
private String contactName = "Luoyang";
/**
* 联系网址
*/
private String contactUrl = "https://www.baidu.com";
/**
* 联系邮箱
*/
private String contactEmail = "[email protected]";
/**
* 版本号
*/
private String version = "1.0.0";
@Autowired
private OpenApiExtensionResolver openApiExtensionResolver;
public Knife4jConfiguration() {
log.debug("创建配置类对象:Knife4jConfiguration");
}
@Bean
public Docket docket() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.host(host)
.apiInfo(apiInfo())
.groupName(groupName)
.select()
.apis(RequestHandlerSelectors.basePackage(basePackage))
.paths(PathSelectors.any())
.build()
.extensions(openApiExtensionResolver.buildExtensions(groupName));
return docket;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(title)
.description(description)
.termsOfServiceUrl(termsOfServiceUrl)
.contact(new Contact(contactName, contactUrl, contactEmail))
.version(version)
.build();
}
}
4.启用项目,通过 doc.html 即可访问在线API文档,
即:http://localhost:8080/doc.html ,效果如下:
5.在线查看Controller控制器类中的配置生成文档
为了更好的显示API文档,应该通过相关注解进行配置:
1.@Api
:添加在控制器类上,通过此注解的tags
属性,可配置管理模块的名称,在配置管理模块名称时,可以在各名称前面添加数字或字母进行序号的排列,使得各管理模块的显示顺序是自定义的顺序
2.@ApiOperation
:添加在控制器类中处理请求的方法上,通过此注解的value
属性,可配置业务的名称
3.@ApiOperationSupport
:添加在控制器类中处理请求的方法上,通过此注解的order
属性(int
类型),可配置业务的排序序号,各业务将按照此序号升序排列
4.@ApiImplicitParam
:添加在控制器类中处理请求的方法上,用于对未封装的请求参数进行配置,必须通过此注解的name
属性,指定配置哪个参数,其它属性的配置可参考@ApiModelProperty
中的属性,需要注意的是,一旦通过此注解进行配置,在API文档上显示的数据类型默认是string
,对于非字符串类型的属性,应该显式的配置dataType
属性
具体代码
package com.luoyang.small.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.luoyang.small.ex.CustomServiceException;
import com.luoyang.small.pojo.dto.AlbumAddNewDTO;
import com.luoyang.small.pojo.entity.Album;
import com.luoyang.small.service.IAlbumService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 相册web控制器
*
* @author luoyang
* @Date 2023/12/13
*/
@Slf4j
@RequestMapping("/album")
@RestController
//Api在线文档注解
@Api(tags = "1.相册管理")
public class AlbumController {
/**
* 不建议声明为具体的实现类,那样不利于代码“解耦”!
*/
@Autowired
private IAlbumService albumService;
//在线文档注解
@ApiOperation("添加相册") //接口名注解
//@ApiImplicitParam(name = "albumAddNewDTO", value = "相册对象", required = true) //参数名注解
@ApiOperationSupport(order = 2)//接口展示排序
//直接网络请求添加
//http://localhost:8080/album/add?name=TestAlbum001&description=TestDescription001&sort=88
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String addNewAlbum(AlbumAddNewDTO albumAddNewDTO) {
try {
albumService.addNew(albumAddNewDTO);
return "添加相册成功Ya!";
} catch (CustomServiceException e) {
String message = e.getMessage();
log.error("addNewAlbum Exception {}", message);
return message;
}
}
//在线文档注解
@ApiOperation("根据相册对象删除相册")//接口名注解
@ApiImplicitParam(name = "albumName", value = "相册对象", required = true,
example = "小米9相册", dataType = "String")//参数名注解
@ApiOperationSupport(order = 1)//接口展示排序
//直接网络请求删除
//http://localhost:8080/album/delete?name=TestAlbum001
@RequestMapping(value = "/delete", method = RequestMethod.GET)
public String deleteAlbum(String albumName) {
log.debug("开始处理【根据相册名删除】的请求,参数:{}", albumName);
if (albumName == null || albumName.isEmpty()) {
return "删除相册的名称为空";
}
try {
albumService.deleteAlbum(albumName);
return albumName + "相册,删除成功Ya!";
} catch (Exception e) {
String message = e.getMessage();
log.error("deleteAlbum Exception {}", message);
return message;
}
}
//在线文档注解
@ApiOperation("根据相册对象更新相册")//接口名注解
@ApiOperationSupport(order = 4)//接口展示排序
//直接web请求地址更新,如下
//http://localhost:8080/album/update?name=TestAlbum001&description=TestDescription001&sort=88
@RequestMapping(value = "update", method = RequestMethod.GET)
public String updateAlbum(AlbumAddNewDTO albumAddNewDTO) {
if (albumAddNewDTO == null) {
return "更新对象为空";
}
String name = albumAddNewDTO.getName();
if (name == null || name.isEmpty()) {
return "更新相册的名称为空";
}
try {
albumService.updateAlbum(albumAddNewDTO);
return name + "相册,更新成功Ya!";
} catch (Exception e) {
String message = e.getMessage();
log.error("updateAlbum Exception {}", message);
return message;
}
}
//在线文档注解
@ApiOperationSupport(order = 3)//接口展示排序
@ApiOperation("查询所有相册")//接口名注解
//直接网络请求更新
//http://localhost:8080/album/selectAll
@RequestMapping(value = {"selectAll", "selectAllOtherName"}, method = RequestMethod.GET)
public List<Album> selectAllAlbum() {
List<Album> albumList = null;
try {
albumList = albumService.selectAllAlbum();
} catch (Exception e) {
String message = e.getMessage();
log.error("selectAllAlbum Exception {}", message);
}
return albumList;
}
}
@ApiModelProperty
:添加在POJO类型的属性上,通过此注解的value
属性,可配置属性的名称,通过此注解的required
属性,可配置是否必须提交此参数(但不具备检查功能),通过此注解的example
属性,可配置示例值(需要注意数据类型的问题,例如数值型的属性不要配置字母或符号作为示例值),通过此注解的dataType
属性,可配置数据类型,例如配置为dataType = "long"
,但此属性通常不需要配置此属性package com.luoyang.small.pojo.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* service操作相册数据实体类
*
* @author luoyang
* @Date 2023/12/12
*/
@Data
public class AlbumAddNewDTO implements Serializable {
@ApiModelProperty(value = "相册名称", required = true, example = "小米手机的相册")
private String name;
@ApiModelProperty(value = "描述", example = "简单相册")
private String description;
@ApiModelProperty(value = "排序权重", example = "100")
private Integer sort;
}