本文最后更新于:2025年2月18日 下午
Swagger2 升级到 openapi3
springboot 2.2.6
-> springboot 2.7.18
由于springboot2.x最新版是2.7.18,所以为了更安全,也为了能用上之前版本缺失的配置,所以推荐升级到2.7.18,这个版本默认是开启静态资源访问的,无需再手动配置。
pom.xml
1 2 3 4 5 6 <dependency > <groupId > com.github.xiaoymin</groupId > <artifactId > knife4j-openapi3-spring-boot-starter</artifactId > <version > 4.4.0</version > </dependency >
application.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 springdoc: swagger-ui: path: /swagger-ui.html tags-sorter: alpha operations-sorter: alpha api-docs: path: /v3/api-docs group-configs: - group: '用户模块' paths-to-match: '/vr/**' packages-to-scan: org.example.controller - group: '管理员模块' paths-to-match: '/vrs/**' packages-to-scan: org.example.converter knife4j: enable: true production: true setting: language: zh_cn api-doc: config: title: XXX系统 - 项目对接文档 description: 本文为XXX系统内部资料,未经过项目负责人允许情况下禁止借阅和传播! version: v1.0.0 - Alpha terms-of-service-url: localhost name: Peter Zhu url: http://localhost email: localhost@localhost.com
配置文件
完整配置文档参考地址:https://springdoc.org/#springdoc-openapi-core-properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 import io.swagger.v3.oas.models.Components;import io.swagger.v3.oas.models.OpenAPI;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.security.SecurityRequirement;import io.swagger.v3.oas.models.security.SecurityScheme;import lombok.Data;import org.springdoc.core.customizers.GlobalOpenApiCustomizer;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.HttpHeaders;@Data @Configuration @ConfigurationProperties(prefix = "api-doc.config") public class ApiConfig { private String title; private String description; private String version; private String termsOfServiceUrl; private String name; private String url; private String email; @Bean public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer () { return openApi -> { if (openApi.getPaths()!=null ){ openApi.getPaths().forEach((s, pathItem) -> { pathItem.readOperations().forEach(operation -> { operation.addSecurityItem(new SecurityRequirement ().addList(HttpHeaders.AUTHORIZATION)); }); }); } }; } @Bean public OpenAPI customOpenAPI () { return new OpenAPI () .info(new Info () .title(title) .contact( new Contact () .name(name) .email(email) .url(url)) .version(version) .description(description) .termsOfService(termsOfServiceUrl) .license(new License ().name("Apache 2.0" ) .url("http://doc.xiaominfoss.com" )) ) .addSecurityItem(new SecurityRequirement ().addList(HttpHeaders.AUTHORIZATION)) .components(new Components ().addSecuritySchemes(HttpHeaders.AUTHORIZATION,new SecurityScheme () .name(HttpHeaders.AUTHORIZATION).type(SecurityScheme.Type.HTTP).scheme("bearer" ))); } }
相关注解变化
迁移后注解变更参考文档:https://springdoc.org/#migrating-from-springfox
Replace swagger 2 annotations with swagger 3 annotations (it is already included with springdoc-openapi-starter-webmvc-ui
dependency). Package for swagger 3 annotations is io.swagger.v3.oas.annotations
.
@Api
→ @Tag
@ApiIgnore
→ @Parameter(hidden = true)
or @Operation(hidden = true)
or @Hidden
@ApiImplicitParam
→ @Parameter
@ApiImplicitParams
→ @Parameters
@ApiModel
→ @Schema
@ApiModelProperty(allowEmptyValue = true)
→ @Schema(nullable = true)
@ApiModelProperty
→ @Schema
@ApiOperation(value = "foo", notes = "bar")
→ @Operation(summary = "foo", description = "bar")
@ApiParam
→ @Parameter
@ApiResponse(code = 404, message = "foo")
→ @ApiResponse(responseCode = "404", description = "foo")
This step is optional: Only if you have multiple Docket
beans replace them with GroupedOpenApi
beans.
user.java
实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import io.swagger.v3.oas.annotations.media.Schema;import lombok.Data;import org.example.enums.User.GenderStatus;import java.util.Date;@Data @Schema(defaultValue = "用户注册类") public class UserRegistrationAO { @Schema(allowableValues = "用户名",name = "username") private String username; @Schema(allowableValues = "密码",name = "password") private String password; @Schema(allowableValues = "生日",name = "birthday") private Date birthday; @Schema(allowableValues = "性别",name = "gender") private GenderStatus gender; @Schema(allowableValues = "联系方式",name = "phone") private String phone; @Schema(allowableValues = "邮箱",name = "email") private String email; @Schema(allowableValues = "地址",name = "address") private String address; }
枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import com.baomidou.mybatisplus.annotation.EnumValue;import com.fasterxml.jackson.annotation.JsonValue;import lombok.Getter;@Getter public enum GenderStatus { MAN(0 ,"男" ), WOMEN(1 ,"女" ); @EnumValue private final int value; @JsonValue private final String message; GenderStatus(int value, String message) { this .value = value; this .message = message; } }
Controller
控制层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 import cn.hutool.core.bean.BeanUtil;import com.alibaba.excel.EasyExcel;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;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.responses.ApiResponse;import io.swagger.v3.oas.annotations.responses.ApiResponses;import io.swagger.v3.oas.annotations.tags.Tag;import lombok.RequiredArgsConstructor;import org.example.mapper.VisitorRecordsMapper;import org.example.model.domain.VisitorRecordsDO;import org.example.result.Result;import org.example.result.Result200;import org.example.result.Result201;import org.example.service.VisitorRecordsService;import org.example.model.vo.VisitorRecordsVO;import org.springframework.web.bind.annotation.*;import javax.validation.constraints.NotBlank;import java.io.File;import java.util.List;import java.util.Properties;import java.util.UUID;@RestController @RequestMapping(value = "vr") @ApiResponses({ @ApiResponse(responseCode = "200",description = "请求成功!"), @ApiResponse(responseCode = "201",description = "上传失败!") }) @Tag(name = "访问记录") @CrossOrigin @RequiredArgsConstructor public class VisitorRecordsController { private final VisitorRecordsService visitorRecordsService; private final VisitorRecordsMapper visitorRecordsMapper; @ApiOperationSupport(author = "Peter") @Operation(summary = "分页查询所有记录") @GetMapping("queryAllByPages") public Result<Page<VisitorRecordsVO>> queryAllVisitorRecordsByPage ( @NotBlank @Parameter(name = "num") @RequestParam(defaultValue = "1") Integer num, @NotBlank @Parameter(name = "size") @RequestParam(defaultValue = "10") Integer size) { Page<VisitorRecordsDO> page = new Page <>(num, size); Page<VisitorRecordsVO> page1 = new Page <>(num, size); visitorRecordsService.page(page); page1.setRecords(BeanUtil.copyToList(page.getRecords(), VisitorRecordsVO.class)); page1.setTotal(page.getTotal()); page1.setPages(page.getPages()); return Result200.ok(page1); } }
Result.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import io.swagger.v3.oas.annotations.media.Schema;import lombok.Data;@Data @Schema(defaultValue = "Result",description = "响应类") public class Result <T> { @Schema(defaultValue = "响应码",name = "code",description = "响应码") private Integer code; @Schema(defaultValue = "响应信息",name = "message",description = "响应信息") private String message; @Schema(defaultValue = "响应数据",name = "data",description = "响应数据") private T data; public Result () {} public static <T> Result<T> build (T data) { Result<T> result = new Result <>(); if (data != null ) result.setData(data); return result; } public static <T> Result<T> build (T body, Integer code, String message) { Result<T> result = build(body); result.setCode(code); result.setMessage(message); return result; } public static <T> Result<T> build (T body, ResultCodeEnum resultCodeEnum) { Result<T> result = build(body); result.setCode(resultCodeEnum.getCode()); result.setMessage(resultCodeEnum.getMessage()); return result; } public static <T> Result<T> ok (T data) { return build(data,ResultCodeEnum.SUCCESS); } public Result<T> message (String msg) { this .setMessage(msg); return this ; } public Result<T> code (Integer code) { this .setCode(code); return this ; } }
启动后访问:localhost/doc.html