原SpringBoot2.7.18升级至3.3.0之后,Knife4j进行同步升级(Spring Boot 3 只支持OpenAPI3规范),从原3.0.3(knife4j-spring-boot-starter)版本升级至4.5.0(knife4j-openapi3-jakarta-spring-boot-starter),以下是升级过程与注意事项等
版本信息
- JDK 21
- Maven 3.9.6
- SpringBoot 3.3.0
- Knife4j 4.5.0(截止2024-06-18最新仍为4.5.0)
一、pom.xml
引入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.0</version><!-- 2.7.18↑--><relativePath/>
</parent><dependencies>...<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.5.0</version></dependency>...
</dependencies>
二、yml中配置
# Knife4j配置
# springdoc-openapi配置
springdoc:# get请求多参数时不需要添加额外的@ParameterObject和@Parameter注解default-flat-param-object: true# 启用swaggerUIswagger-ui:#自定义swagger前端请求路径,输入http:127.0.0.1:8080/swagger-ui.html会自动重定向到swagger页面path: /swagger-ui.htmlenabled: true
# tags-sorter: alpha # 标签的排序方式 alpha:按照子母顺序排序(@ApiSupport注解排序不生效,因此需要设置)
# operations-sorter: alpha # 接口的排序方式 alpha:按照子母顺序排序(@ApiOperationSupport注解排序生效,因此这里不作设置)operations-sorter: order # 设置规则为order,该规则会使用Knife4j的增强排序扩展规则`x-order`# 启用文档,默认开启api-docs:path: /v3/api-docs #swagger后端请求地址enabled: true
# knife4j相关配置 可以不用改
knife4j:enable: true #开启knife4j,无需添加@EnableKnife4j注解setting:language: ZH_CN # 中文:ZH_CN 英文:ENenable-swagger-models: trueenable-dynamic-parameter: falsefooter-custom-content: "<strong>Copyright ?? 2024 Keyidea. All Rights Reversed</strong>"enable-footer-custom: trueenable-footer: trueenable-document-manage: truedocuments: #文档补充说明- name: MarkDown语法说明locations: classpath:static/markdown/grammar/*group: 01-系统接口 # 此处分组必须使用在Knife4jConfig已存在的分组名group,当存在displayName时,使用displayName名称- name: 补充文档locations: classpath:static/markdown/others/*group: 01-系统接口 # 此处分组必须使用在Knife4jConfig已存在的分组名group,当存在displayName时,使用displayName名称
说明:使用knife4j.documents
配置补充文档时,需要注意,文档格式必须为markdown格式,另外,文件存放位置如下
Knife4j补充文档存放位置
实际呈现如下
补充文档
三、Knife4jConfig
配置
StatusCode类见附录A
package cn.keyidea.common.config;import cn.keyidea.common.constant.StatusCode;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Map;/*** Knife4jConfig* 注意:分组名称暂时只能使用英文或数字,在4.0.0~4.5.0的Knife4j版本中使用中文分组会出现页面访问异常* <p>* 解决:(2024-06-18)保持原有分组名group不变,新增displayName中文名称;* 特别注意:设置displayName后,knife4j.documents.name配置文档时,需使用displayName名称* <p>** @author qyd* @date 2024-04-13*/
@Configuration
public class Knife4jConfig {private final static Logger logger = LoggerFactory.getLogger(Knife4jConfig.class);private static final String SERVICE_URL = "http://127.0.0.1:7004/tj4/doc.html";private static final String API_INFO_TITLE = "软件接口文档";private static final String API_INFO_VERSION = "V1.0";private static final String API_INFO_DESCRIPTION = "Api接口列表";private static final String API_INFO_LICENSE = "2024年度内部文档,违拷必究.";// 2024集同接口@Beanpublic GroupedOpenApi api4() {return GroupedOpenApi.builder().group("04-2024-api").displayName("04-2024集同接口").packagesToScan("cn.keyidea.second")// 自定义全局响应码.addOpenApiCustomizer((this::setCustomStatusCode)).build();}// 2023集同接口@Beanpublic GroupedOpenApi api3() {return GroupedOpenApi.builder().group("03-2023-api").displayName("03-2023集同接口").packagesToScan("cn.keyidea.control")// 自定义全局响应码.addOpenApiCustomizer((this::setCustomStatusCode)).build();}// 业务接口@Beanpublic GroupedOpenApi api2() {return GroupedOpenApi.builder().group("02-business-api").displayName("02-业务接口").packagesToScan("cn.keyidea.business")// .pathsToMatch("/v1/**").addOpenApiMethodFilter(method -> method.isAnnotationPresent(io.swagger.v3.oas.annotations.Operation.class))// 自定义全局响应码.addOpenApiCustomizer((this::setCustomStatusCode)).build();}// 系统接口@Beanpublic GroupedOpenApi api1() {// 创建了一个api接口的分组return GroupedOpenApi.builder()// 分组名称,使用英文,中文访问异常(使用displayName设置中文名,避免直接使用group设置中文时访问异常).group("01-sys-api").displayName("01-系统接口") // 使用displayName设置中文接口分组名时,group仍不可或缺.packagesToScan("cn.keyidea.sys")// 自定义全局响应码.addOpenApiCustomizer((this::setCustomStatusCode)).build();}@Beanpublic OpenAPI openAPI() {return new OpenAPI().info(new Info().title(API_INFO_TITLE).description(API_INFO_DESCRIPTION).version(API_INFO_VERSION).contact(new Contact().name("Keyidea").email("support@keyidea.cn")).license(new License().name(API_INFO_LICENSE).url(SERVICE_URL)));}/*** 设置自定义错误码** @param openApi openApi对象*/private void setCustomStatusCode(OpenAPI openApi) {if (openApi.getPaths() != null) {Paths paths = openApi.getPaths();for (Map.Entry<String, PathItem> entry : paths.entrySet()) {String key = entry.getKey();PathItem value = entry.getValue();// put方式自定义全局响应码Operation put = value.getPut();// get方式自定义全局响应码Operation get = value.getGet();// delete方式自定义全局响应码Operation delete = value.getDelete();// post方式自定义全局响应码Operation post = value.getPost();if (put != null) {put.setResponses(handleResponses(put.getResponses()));}if (get != null) {get.setResponses(handleResponses(get.getResponses()));}if (delete != null) {delete.setResponses(handleResponses(delete.getResponses()));}if (post != null) {post.setResponses(handleResponses(post.getResponses()));}}}}/*** 处理不同请求方式中的自定义响应码* - 响应码中使用原有的响应体Content(否则会造成BaseRes中通用的data无法解析各自的对象)* - 使用原生的ApiResponses作为返回体(否则会造成前端响应示例和响应内容中丢失注释)** @param responses 响应体集合* @return 返回处理后的响应体集合*/private ApiResponses handleResponses(ApiResponses responses) {// 设置默认ContentContent content = new Content();// 以下代码注释,因为无论如何都会从原生responses中获取到一个Content// MediaType mediaType = new MediaType();// Schema schema = new Schema();// schema.set$ref("#/components/schemas/BaseRes");// mediaType.setSchema(schema);// content.addMediaType("*/*", mediaType);// 从原来的responses中获取原生Contentfor (Map.Entry<String, ApiResponse> entry : responses.entrySet()) {String key = entry.getKey();ApiResponse apiResponse = entry.getValue();if (apiResponse != null) {content = apiResponse.getContent();break;}}// 获取全部全局响应自定义列表Map<Integer, String> map = StatusCode.toMap();// 设置全局响应码for (Map.Entry<Integer, String> entry : map.entrySet()) {ApiResponse api = new ApiResponse();api.setContent(content);api.description(entry.getValue());responses.addApiResponse(entry.getKey() + "", api);}return responses;}
}
四、ShiroConfig中放行Swagger相关路径
如果SpringBoot未集成Shiro,那么此处无需关注。
...
// Shiro放行swagger2(Knife4j)
// filterMap.put("/doc.html", "anon");
// filterMap.put("/swagger-resources/**", "anon");
// filterMap.put("/v2/**", "anon");
// filterMap.put("/webjars/**", "anon");// Shiro放行swagger3(Knife4j)
filterMap.put("/doc.html", "anon");
filterMap.put("/swagger-resources/**", "anon");
filterMap.put("/v3/**", "anon");
filterMap.put("/webjars/**", "anon");
filterMap.put("/swagger-ui/**", "anon");
...
五、注解更新
swagger 3 注释的包是io.swagger.v3.oas.annotations
1.原生注解更新
# Controller注解更新
@Api → @Tag
@ApiSort → @ApiSupport# 类接口注解更新
@ApiIgnore→@Parameter(hidden = true)或@Operation(hidden = true)或@Hidden
@ApiImplicitParam → @Parameter
@ApiImplicitParams → @Parameters
@ApiOperation(value = "foo", notes = "bar") → @Operation(summary = "foo", description = "bar")
@ApiResponse(code = 404, message = "foo") → @ApiResponse(responseCode = "404", description = "foo")# 实体类注解更新
@ApiModel → @Schema
@ApiModelProperty(hidden = true) → @Schema(accessMode = READ_ONLY)
@ApiModelProperty → @Schema
@ApiParam → @Parameter
2.全局替换示例
## 全局替换原有注解@Api(tags
->
@Tag(name@ApiSort(
->
@ApiSupport(order = , dataType = "Integer", dataTypeClass = Integer.class
->
, in = ParameterIn.DEFAULT, dataType = "String", dataTypeClass = String.class
->
, in = ParameterIn.DEFAULT, paramType = "path", in = ParameterIn.DEFAULT
, paramType = "path", dataType = "Integer", dataTypeClass = Integer.class
->
, in = ParameterIn.PATH, dataType = "Date", dataTypeClass = Date.class
->@ApiOperation(value
->
@Operation(summary@ApiImplicitParams
->
@Parameters@ApiModel(value | @ApiModelProperty(value
->
@Schema(name | @Schema(descriptionrequired = true | required = false (限定为entity或vo等实体类包进行更换)
->
requiredMode = Schema.RequiredMode.REQUIRED
requiredMode = Schema.RequiredMode.NOT_REQUIRED## javax注解更改(jakarta)import javax.xxx;
->
import jakarta.xxx;
六、典型应用
1.文件上传(与自定义错误码)
在
Knife4jConfig
类中已经完美解决了全局自定义错误码,因此在单个接口中已不建议再写,除非有特殊要求。
以下接口类中自定义错误码仅为示例。
···
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
···
import org.springframework.web.multipart.MultipartFile;
···/*** 系统公共类** @author qyd* @date 2022-10-17*/
@ApiSupport(order = 1)
@Tag(name = "1-系统公共类", description = "系统公共类")
@RestController
// @RequestMapping(name = "/sys/common/", produces = MediaType.APPLICATION_JSON_VALUE)
@RequestMapping("/sys/common/")
public class CommonController {private final static Logger logger = LoggerFactory.getLogger(CommonController.class);@Autowiredprivate SysFileLogService sysFileService;@SysLogAnnotation(module = "公共类", serviceDesc = "公共类-文件上传", serviceType = ConstantsExpand.ServiceType.UPLOAD)@ApiOperationSupport(author = "qyd", order = 1)@Operation(summary = "文件上传", description = "")@Parameters({@Parameter(name = "file", description = "单文件上传", required = true, schema = @Schema(type = "file", format = "binary"), in = ParameterIn.DEFAULT),@Parameter(name = "fileType", description = "文件类型", required = true, example = "txt", in = ParameterIn.DEFAULT),@Parameter(name = "type", description = "是否使用文件原始名称:1-使用,其他-不使用(使用随机UUID)", required = false, example = "1", in = ParameterIn.DEFAULT)})@ApiResponses({@ApiResponse(responseCode = "1000", description = "响应成功"),@ApiResponse(responseCode = "1001", description = "非法字段"),})@PostMapping("uploadFile")public BaseRes uploadFile(@RequestPart(value = "file", required = true) MultipartFile file,@RequestParam(value = "fileType", required = true) String fileType,@RequestParam(value = "type", required = false) Integer type) {return sysFileService.uploadFile(file, fileType, type);}
}
2.实体类(分页参数基类PageObject
)
package cn.keyidea.common.bean;import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;import java.io.Serializable;/*** 分页基类 分页参数对象** @author qyd* @date 2024-06-05*/
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Schema(name = "PageObject", description = "分页对象")
public class PageObject implements Serializable {// 前端实际使用天基三期(React)写法当前页使用的是page@NotNull(message = "当前页不能为NULL")@Schema(description = "当前页,默认1", name = "page", example = "1", type = "integer", requiredMode = Schema.RequiredMode.REQUIRED)private Integer page;@NotNull(message = "分页数不能为NULL")@Schema(description = "分页数,默认15", name = "pageSize", example = "15", type = "integer", requiredMode = Schema.RequiredMode.REQUIRED)private Integer pageSize;@Schema(description = "排序字段", name = "orderBy", example = "", requiredMode = Schema.RequiredMode.NOT_REQUIRED)private String orderBy;@Schema(description = "排序方式:false-asc,true-desc", name = "desc", type = "boolean", example = "false", requiredMode = Schema.RequiredMode.NOT_REQUIRED)private Boolean desc;}
3.接口类-分页查询/新增/更新/删除/导入示例
已TLE数据的增删查改为例进行说明。
package cn.keyidea.business.controller;import cn.keyidea.business.entity.Tle;
import cn.keyidea.business.service.TleService;
import cn.keyidea.common.annotation.SysLogAnnotation;
import cn.keyidea.common.bean.BaseRes;
import cn.keyidea.common.constant.ConstantsExpand;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;/*** <p>* 卫星TLE信息表* </p>** @author qyd* @since 2022-10-12*/
@ApiSupport(order = 2)
@Tag(name = "2-卫星TLE管理", description = "卫星两行根数管理")
@RestController
@RequestMapping("/v1/tle")
public class TleController {private final static Logger logger = LoggerFactory.getLogger(TleController.class);@Autowiredprivate TleService tleService;@SysLogAnnotation(module = "TLE管理", serviceDesc = "TLE管理-分页查询", serviceType = ConstantsExpand.ServiceType.QUERY)@ApiOperationSupport(author = "qyd", order = 1)@Operation(summary = "分页查询")@Parameters({@Parameter(name = "sceneId", description = "场景ID", required = false, example = "1", in = ParameterIn.DEFAULT),@Parameter(name = "tleCode", description = "节点标识,支撑模糊查询", required = false, example = "0101", in = ParameterIn.DEFAULT),@Parameter(name = "type", description = "卫星类型:0-低轨卫星,1-中轨卫星,2-高轨卫星,3-天基用户", required = false, example = "0", in = ParameterIn.DEFAULT),@Parameter(name = "current", description = "当前页", required = true, example = "1", in = ParameterIn.DEFAULT),@Parameter(name = "pageSize", description = "分页数", required = true, example = "15", in = ParameterIn.DEFAULT)})@GetMapping("listPage")public BaseRes<BaseRes.DataList<Tle>> listPage(@RequestParam(value = "sceneId", required = false) Integer sceneId,@RequestParam(value = "tleCode", required = false) String tleCode,@RequestParam(value = "type", required = false) Integer type,@RequestParam(value = "current", required = true, defaultValue = "1") Integer pageNumber,@RequestParam(value = "pageSize", required = true, defaultValue = "15") Integer pageSize) {Page<Tle> page = new Page<>(pageNumber, pageSize);return tleService.listPage(page, sceneId, tleCode, type);}@SysLogAnnotation(module = "TLE管理", serviceDesc = "TLE管理-TLE详情", serviceType = ConstantsExpand.ServiceType.QUERY)@ApiOperationSupport(author = "qyd", order = 2)@Operation(summary = "TLE详情")@Parameter(name = "id", description = "主键ID", required = true, example = "1", in = ParameterIn.PATH)@GetMapping("getById/{id}")public BaseRes getById(@PathVariable(value = "id", required = true) Integer id) {return tleService.getOneById(id);}@SysLogAnnotation(module = "TLE管理", serviceDesc = "TLE管理-TLE新增", serviceType = ConstantsExpand.ServiceType.ADD)@ApiOperationSupport(author = "qyd", order = 3, includeParameters = {"tle.tleCode","tle.line1","tle.line2","tle.sceneId","tle.remark"})@Operation(summary = "TLE新增", description = "")@PostMapping("add")public BaseRes add(@Valid @RequestBody Tle tle) {return tleService.add(tle);}@SysLogAnnotation(module = "TLE管理", serviceDesc = "TLE管理-TLE更新", serviceType = ConstantsExpand.ServiceType.UPDATE)@ApiOperationSupport(author = "qyd", order = 4, includeParameters = {"tle.id","tle.tleCode","tle.line1","tle.line2","tle.sceneId","tle.remark"})@Operation(summary = "TLE更新")@PutMapping("update")public BaseRes update(@Valid @RequestBody Tle tle) {return tleService.update(tle);}@SysLogAnnotation(module = "TLE管理", serviceDesc = "TLE管理-TLE更新", serviceType = ConstantsExpand.ServiceType.DELETE)@ApiOperationSupport(author = "qyd", order = 5)@Operation(summary = "TLE删除", description = "")@Parameter(name = "id", description = "主键ID", required = true, example = "1", in = ParameterIn.PATH)@DeleteMapping("delete/{id}")public BaseRes delete(@PathVariable(value = "id", required = true) Integer id) {return tleService.delete(id);}@SysLogAnnotation(module = "TLE管理", serviceDesc = "TLE管理-TLE导入", serviceType = ConstantsExpand.ServiceType.IMPORT)@ApiOperationSupport(author = "qyd", order = 6)@Operation(summary = "TLE导入", description = "TLE导入数据格式请参看模板:<a href='template/txt/tle.txt'>TLE文本导入模板</a>")@Parameters({@Parameter(name = "file", description = "单文件上传", required = true, schema = @Schema(type = "file", format = "binary"), in = ParameterIn.DEFAULT),@Parameter(name = "sceneId", description = "场景ID", required = true, example = "1", in = ParameterIn.DEFAULT)})@PostMapping(value = "importTle")public BaseRes importTle(@RequestPart(value = "file", required = true) MultipartFile file,@RequestParam(value = "sceneId", required = true) Integer sceneId) {return tleService.importTle(file, sceneId);}}
七、FAQ
1.关于Controller排序说明
a) 使用tags-sorter排序问题说明
使用tags-sorter的alpha排序,是为字母排序,会造成在@Tag的name中使用00-xx/01-xx/02-xx/.../10-xxx
进行说明时,排序为00-xx/10-xx/01-xx/.../09-xxx
,为了对排序进行强一致,所以废弃使用tags-sorter的alpha排序,使用注解@ApiSupport
进行排序定义。
b) 解决使用@ApiSupport
不生效问题
- 移除yml中对tags-sorter的alpha排序(注释掉);
- 在控制器上给
@ApiSupport
注解,按照order值进行自定义排序,你想让哪个在前,order值就小一些,我一般是从1开始; - 在注解
@Tag
中的description要给描述,不能是空字符串,否则@ApiSupport
不生效; - 弃用tags-sorter的alpha排序更改使用
@ApiSupport
排序后,需重启程序,此时浏览器最好清除缓存后重新访问Knife4j。
2.关于接口分组无法使用中文问题解决
a) 问题回溯
在Knife4jConfig
配置类中使用group进行中文分组时,会造成doc.html访问异常,推测是底层编码问题所致。
b) 解决方法
Knife4jConfig
配置类中,配置GroupedOpenApi时,group使用英文,displayName使用中文(doc.html最终显示displayName名称);- 当
Knife4jConfig
配置类中使用displayName名称时,在yml中配置补充文档时,设置knife4j.documents.name
时使用displayName名称,而不是group名称,切记!
3.关于响应内容中不出现注释内容说明
当响应内容中不出现注释时,点击右上角显示说明
,触发一次关闭或勾选,即可出现注释内容。(群友推测可能是当响应结果过多时显示BUG问题,必须关闭勾选触发一次显示说明的事件)
4.关于Controller层中GET请求且接收参数为对象时的配置注意事项
参考以下两篇文章
- Knife4j v4.0版本针对参数解析ParameterObject的问题说明
- SpringBoot接收参数场景
集成Knife4j后,针对GET请求且接收参数为对象时,需要在yml中配置
springdoc.default-flat-param-object=true
;且在接受参数时使用注解@ModelAttribute
。
5.关于过滤参数注解@ApiOperationSupport
使用
从Knife4j4.0.0开始,@ApiOperationSupport
注解中的ignoreParameters
和includeParameters
属性不再提供支持。如果需要进行精确显示提供的参数,官方建议是新建VO类。
Knife4j4.5.0注解关于注解@ApiOperationSupport属性说明
官方说明: 3.11 过滤请求参数 | Knife4j
八、待解决问题
1.设置includeParameters
无效[影响指数:5/5]【见7.5章节】
POST请求中使用includeParameters
给部分对象参数时无效,界面会显示全部对象字段。
includeParameters设置部分参数仍显示全部全部
2.设置多响应码时界面显示响应状态为tab[影响指数:4/5]
接口上设置多响应码时在前端响应状态中会显示多个tab,导致导出文档时,对同一个接口会出现多次响应状态描述
设置多响应码时出现响应码Tab
附录
附录A:状态码枚举定义类(StatusCode.java)
package cn.keyidea.common.constant;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 状态码枚举定义** @author qyd* @date 2022-10-13*/
public enum StatusCode
{SUCCESS(1000, "请求成功"),INVALID_PARAM(1001, "非法字段"),SYSTEM_BUSY(1002, "系统忙"),INVALID_MASTER_KEY(1003, "无接口访问权限"),FAILURE(1004, "请求失败"),UNAUTHORIZED(1005, "未授权"),INVALID_TOKEN(2001, "TOKEN失效"),CONNECT_TIMED_OUT(3001, "请求超时"),HTTP_REQ_ERROR(3002, "HTTP请求出错");/*** 错误码*/private final int code;/*** 错误描述信息*/private final String msg;StatusCode(int code, String msg){this.code = code;this.msg = msg;}public String getMsg(){return this.msg;}public String getCode(){return this.code + "";}public int getCodeValue(){return this.code;}/*** 转为Map集合数据** @return 枚举对象Map集合*/public static Map<Integer, String> toMap(){Map<Integer, String> map = new HashMap<>(32);for (StatusCode value : StatusCode.values()){map.put(value.getCodeValue(), value.getMsg());}return map;}/*** 转为List集合数据** @return 枚举对象List集合*/public static List<Map<String, String>> toList(){List<Map<String, String>> list = new ArrayList<>(32);Map<String, String> map = null;for (StatusCode item : StatusCode.values()){map = new HashMap<>();map.put("code", item.getCode());map.put("msg", item.getMsg());list.add(map);}map = null;return list;}
}
附录B:通用响应封装类(BaseRes.java)
package cn.keyidea.common.bean;import cn.keyidea.common.constant.StatusCode;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;import java.io.Serializable;/*** 通用响应封装,范式返回(Swagger要求)** @author qyd*/
@Data
public class BaseRes<T> implements Serializable {/*** 错误码*/@Schema(name = "code", description = "错误码,当code为1000时返回正常,其余返回异常", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")public Integer code;/*** 错误提示信息*/@Schema(name = "msg", description = "错误提示信息,当code为非1000时返回提示信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "请求成功")public String msg;/*** 附加返回数据*/@Schema(name = "data", description = "附加返回数据,当code为1000时返回数据")public T data;public static class DataList<T> {/*** 记录总数*/@Schema(name = "total", description = "记录总数")public Integer total;/*** 数据列表*/@Schema(name = "list", description = "数据列表")public T list;public DataList(Integer total, T list) {this.total = total;this.list = list;}}/*** 给ObjectMapper用的,代码中不要调用*/public BaseRes() {}/*** 自定义返回码和提示消息** @param code 错误码* @param msg 提示文字*/public BaseRes(int code, String msg) {this.code = code;this.msg = msg;}public BaseRes(int code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;}/*** 返回成功,但是没有附加数据** @return BaseRes对象*/public static BaseRes success() {return new BaseRes(StatusCode.SUCCESS.getCodeValue(), "请求成功");}/*** 返回成功,带附加数据** @param data 附加数据* @return BaseRes对象*/public static BaseRes successData(Object data) {BaseRes value = new BaseRes(StatusCode.SUCCESS.getCodeValue(), "请求成功");value.data = data;return value;}/*** 返回参数无效响应** @return BaseRes对象*/public static BaseRes invalidParam() {return new BaseRes(StatusCode.INVALID_PARAM.getCodeValue(), "参数无效");}/*** 返回参数无效响应,自定义错误提示** @param msg 提示文字* @return BaseRes对象*/public static BaseRes invalidParam(String msg) {return new BaseRes(StatusCode.INVALID_PARAM.getCodeValue(), msg);}/*** 返回系统忙无效响应** @return BaseRes对象*/public static BaseRes systemBusy() {return new BaseRes(StatusCode.SYSTEM_BUSY.getCodeValue(), "系统忙");}/*** 返回master key无效响应** @return BaseRes对象*/public static BaseRes invalidMasterkey() {return new BaseRes(StatusCode.INVALID_MASTER_KEY.getCodeValue(), "没有接口访问权限");}/*** 返回失败,附带说明** @return BaseRes对象*/public static BaseRes fail(String msg) {return new BaseRes(StatusCode.FAILURE.getCodeValue(), msg);}/*** 返回错误信息时,仍然返回数据** @param data 数据集* @param msg 错误信息* @return BaseRes对象*/public static BaseRes failData(Object data, String msg) {return new BaseRes(StatusCode.FAILURE.getCodeValue(), msg, data);}/*** 登录失效的错误** @return BaseRes对象*/public static BaseRes invalidToken() {return new BaseRes(StatusCode.INVALID_TOKEN.getCodeValue(), "请先登录");}/*** 检查响应处理是否成功** @return 成功返回true,否则false*/@JsonIgnorepublic boolean isSuccess() {return (this.code.equals(StatusCode.SUCCESS.getCodeValue()));}/*** 返回分页列表数据** @param total 记录总数* @param list 列表数据* @return rsp*/public static BaseRes list(long total, Object list) {DataList data = new DataList((int) total, list);return BaseRes.successData(data);}
}
参考
以下参考截止[2024-06-20],CSDN等网站链接均能查看全部文章。
官方
- 3.1 增强模式 | Knife4j
接口排序问题
-
knife4j 4.3.0版本,@ApiSupport、@ApiSort排序不会自动生成x-order扩展属性 · Issue #I7U2I0 · 萧明/knife4j - Gitee.com【解决了类Controller排序问题】
-
knife4j 中接口分组排序的方法_knife4j 接口排序-CSDN博客
SpringBoot2.x升级至3.x相关
- SpringBoot2.7升级项目到Springboot3.1踩坑指南(jdk17/jdk21)_升级到 jdk17 springboot3.1
- Spring Boot 3 之SpringBoot 版本升级最佳实践指南
- 记录从SpringBoot2.x升级到SpringBoot3.x的心得
- SpringBoot2.7升级到3.0的实践分享 - 踩刀诗人
- 记录SpringBoot2.7.5升级SpringBoot3.0.0问题_springboot2.7升级3.0
- Springboot3.0升级填坑-腾讯云开发者社区-腾讯云
- JeecgBoot 框架升级至 Spring Boot3 的实战步骤-腾讯云开发者社区-腾讯云
- How to prevent logback from outputting its own status at the start of every log when using a layout - Stack Overflow
- Spring Boot3.0升级,踩坑之旅,附解决方案(二) - 掘金
MyBatis Plus升级相关
- springboot3.2 整合 mybatis-plus_java.lang.illegalargumentexception: invalid value【解决引入最新MP依赖报错问题】
Knife4j升级相关
- 关于SpringBoot2.7.18升级到3.2.x后的Knife4j使用的系列问题汇总(已全部解决) · Issue #775 · xiaoymin/knife4j
- SpringBoot3整合Knife4j4.x版本(Swagger3、OpenApi3)_knife4j openapi3【有解决单文件多文件示例等】
- SpringBoot 整合 knfe4j ,使用 OpenAPI3 规范_knife4j-openapi3
- springboot3.2集成knife4j_springboot3.2 knife4j
- SpringBoot3整合Knife4j_springboot3 knife4j
- SpringBoot3中Swagger整合knife4j和springdoc的配置说明
- SpringBoot3.x版本将swagger2.0升级到swagger3.0,使用knife4j-openapi3-jakarta-spring-boot-starter依赖
- SpringBoot 使用 OpenAPI3 规范整合 knife4j的详细过程
- Swagger系列:SpringBoot3.x中使用Knife4j - Code技术分享
- SpringBoot3登录拦截器导致不能正常访问knife4j_knife4j放行后被拦截
- Knife4j文档请求异常(基于SpringBoot3,查找原因并解决)
- SpringBoot整合knife4j_knife4j集成springboot
- SpringBoot 3.0整合OpenAPI使用教程_knife4j-openapi3-jakarta-spring-boot-starter
- knife4j文档请求异常 · Issue #749 · xiaoymin/knife4j【Knife4j纯yml配置参考】
涉及Redis相关
- Springboot从2.x升级到3.x以后redis默认配置调整-阿里云开发者社区
- SpringBoot 2.x / 3.x 整合 Redis ( RedisTemplate 操作五大常用数据类型)
其他【启动告警解决】
- Spring源码系列:BeanDefinition源码解析 - 掘金
- 解决is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) - 神一样的存在 - 博客园
- 解决:is not eligible for getting processed by all BeanPostProcessors-CSDN博客
最后编辑于:2024-12-09 22:14:37
著作权归作者所有,转载或内容合作请联系作者
喜欢的朋友记得点赞、收藏、关注哦!!!