☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

随着 %ignore_a_1% 生态向 jdk 17 及 jakarta ee 的演进,许多项目面临从 jdk 8 升级的挑战,其中 swagger(api 文档工具)的兼容性调整尤为关键。本文将从 技术栈差异、升级迁移步骤、常见问题 等多个维度,解析 jdk 8(springfox)向 jdk 17(springdoc/knife4j)的升级路径。
1、背景
1.1 技术演进
JDK 版本演进:JDK 17 是继 JDK 8 后的首个 LTS 版本,支持模块化、Records 等新特性,但移除了部分旧 API(如 javax.servlet)。直接影响:基于 JDK 8 构建的 SpringFox(Swagger 2.x)因依赖旧规范无法兼容新版本。Jakarta EE 的崛起:Java EE 移交 Eclipse 基金会后更名为 Jakarta EE,包名从 javax.* 改为 jakarta.*。核心冲突:Spring Boot 3.x 和 SpringDoc(Swagger 3.x)强制依赖 Jakarta EE 9+,导致旧项目升级时需全局替换包名。
1.2 升级的必要性
安全风险:SpringFox 已停止维护,存在未修复漏洞(如 CVE-2021-28170)。功能需求:SpringDoc 支持 OpenAPI 3.0 规范,提供更灵活的文档定义和响应示例。生态兼容:微服务、云原生场景下,JDK 17 的容器化支持更优。
2、技术栈对比与选型
2.1 JDK 8 与 JDK 17 的 Swagger 技术栈对比
特性
JDK 8 + SpringFox (Swagger 2.x)
JDK 17 + SpringDoc/Knife4j (Swagger 3.x)
核心框架
SpringFox 2.x(已停止维护)
SpringDoc OpenAPI 3.x(官方推荐)
JDK 兼容性
仅支持 JDK 8~11
支持 JDK 17+ 的模块化特性
Spring Boot 支持
Spring Boot 2.x
Spring Boot 3.x(兼容 2.7.x)
Servlet 规范
基于 javax.servlet
迁移至 jakarta.servlet(Jakarta EE 9+)
注解库
io.swagger.annotations
io.swagger.v3.oas.annotations
注解风格
@Api, @ApiOperation
@Tag, @Operation(更符合 OpenAPI 3.0)
依赖管理
需手动管理版本,易冲突
通过 Spring Boot Starter 简化依赖
文档生成
需配置 Docket
自动扫描,通过 OpenAPI Bean 全局配置
文档规范
OpenAPI 2.0
OpenAPI 3.0
UI 工具
Swagger UI(基础功能)
Knife4j(增强功能,支持离线文档、权限控制、接口分组等)
维护状态
停止维护(最后版本 3.0.0)
活跃维护(SpringDoc 2.x + Knife4j 4.x)
2.2 版本兼容性矩阵
技术栈
JDK 8
JDK 11
JDK 17
Spring Boot 2.7.x
Spring Boot 3.x
SpringFox 2.x
✅
⚠️ 部分兼容
❌
✅
❌
SpringDoc 1.x
✅
✅
❌
✅
❌
SpringDoc 2.x
❌
✅
✅
✅
✅
3、快速升级步骤
3.1 依赖管理升级
移除旧依赖 io.springfoxspringfox-swagger23.0.0io.springfoxspringfox-swagger-ui3.0.0添加新依赖 org.springdocspringdoc-openapi-starter-webmvc-ui2.5.0com.github.xiaoyminknife4j-openapi3-jakarta-spring-boot-starter4.5.0排除冲突依赖 org.apache.tomcat.embedtomcat-embed-corejavax.servletjavax.servlet-api
3.2 代码层迁移(注解更新)
控制器注解迁移:
SpringFox (Swagger 2.x)
SpringDoc (OpenAPI 3.x)
用途
示例
@Api
@Tag
标记控制器类的作用
@Tag(name = “用户管理”, description = “用户接口”)
@ApiOperation
@Operation
描述接口方法的功能
@Operation(summary = “创建用户”, description = “根据DTO创建用户”)
@ApiParam
@Parameter
描述接口参数(路径、查询、表单参数等)
@Parameter(name = “id”, description = “用户ID”, required = true)
@ApiResponse
@ApiResponse
定义接口的响应状态码和描述
闪念贝壳
闪念贝壳是一款AI 驱动的智能语音笔记,随时随地用语音记录你的每一个想法。
218 查看详情
@ApiResponse(responseCode = “404”, description = “用户不存在”)
@ApiIgnore
@Hidden 或 @Parameter(hidden = true)
隐藏接口或参数
@Hidden // 隐藏整个接口方法
@ApiImplicitParams
@Parameters + @Parameter
描述非直接声明的参数(如 Header 参数)
@Parameters({ @Parameter(name = “token”, in = HEADER, description = “认证令牌”) })
@ApiImplicitParam
@Parameter
单个隐式参数定义
同上
// JDK 8(SpringFox)@Api(tags = "用户管理", description = "用户接口")@RestControllerpublic class UserController { @ApiOperation("创建用户") @PostMapping("/users") public User createUser(@ApiParam("用户DTO") @RequestBody UserDTO dto) { // ... } @ApiImplicitParams({ @ApiImplicitParam(name = "token", value = "认证令牌", paramType = "header") }) @GetMapping("/profile") public UserProfile getProfile() { //... }}
// JDK 17(SpringDoc)@Tag(name = "用户管理", description = "用户接口")@RestControllerpublic class UserController { @Operation(summary = "创建用户", description = "根据DTO创建用户") @PostMapping("/users") public User createUser(@Parameter(description = "用户DTO", required = true) @RequestBody UserDTO dto) { // ... } @Parameters({ @Parameter(name = "token", description = "认证令牌", in = ParameterIn.HEADER) }) @GetMapping("/profile") public UserProfile getProfile() { // ... }}
模型类注解迁移:
SpringFox (Swagger 2.x)
SpringDoc (OpenAPI 3.x)
用途
示例
@ApiModel
@Schema
描述数据模型类
@Schema(name = “UserDTO”, description = “用户传输对象”)
@ApiModelProperty
@Schema
描述模型字段的详细信息
@Schema(description = “用户名”, example = “张三”, requiredMode = REQUIRED)
// JDK 8(SpringFox)@ApiModel(value = "User", description = "用户实体")public class User { @ApiModelProperty(value = "用户名", required = true, example = "张三") private String name;}
// JDK 17(SpringDoc)@Schema(name = "User", description = "用户实体")public class User { @Schema(description = "用户名", example = "张三", requiredMode = Schema.RequiredMode.REQUIRED) private String name;}
3.3 全局配置调整
是否还需要传统 SwaggerConfig?
不需要:Knife4j OpenAPI3 基于 SpringDoc,无需配置 Docket 或 Swagger2Markup。必要配置:仅需定义 OpenAPI Bean(如上文的 OpenApiConfig)即可。
3.3.1 SpringDoc 配置类
@Configurationpublic class OpenApiConfig { @Bean public OpenAPI customOpenAPI() { return new OpenAPI() .info(new Info() .title("API 文档") .version("1.0") .description("JDK 17 迁移示例") .contact(new Contact().name("xcbeyond技术支持").email("support@example.com")) .license(new License().name("Apache 2.0").url("https://springdoc.org"))) .externalDocs(new ExternalDocumentation() .description("详细文档") .url("https://xcbeyond.com")) .components(new Components() .addSecuritySchemes("BearerAuth", new SecurityScheme() .type(SecurityScheme.Type.HTTP) .scheme("bearer") .bearerFormat("JWT"))); }}
3.3.2 分组配置(多模块场景)
在微服务架构中,API 文档分组配置的核心管理需求是:
模块化展示:将不同业务域(用户/订单/支付)分离展示。权限隔离:区分公共 API 和管理 API。版本管理:同时维护 v1 和 v2 接口。依赖解耦:避免单个文档过大导致加载性能问题。
分组配置参数详解:
配置方法
参数说明
默认值
示例
.group(String group)
分组唯一标识(显示在 UI 中)
必填
.group(“用户管理”)
.pathsToMatch(String… paths)
路径匹配规则(支持 Ant 风格)
可选
.pathsToMatch(“/api/user/**”)
.packagesToScan(String… pkgs)
扫描的包路径
可选
.packagesToScan(“com.example”)
.pathsToExclude(String… paths)
排除的路径
空数组
.pathsToExclude(“/internal/**”)
.addOpenApiMethodFilter(Predicate)
自定义方法过滤逻辑
无
见下面示例
.displayName(String name)
显示名称(覆盖 group 的显示)
同 group 值
.displayName(“用户模块”)
.addOperationCustomizer(…)
自定义操作处理器
无
见下面示例
通过合理的分组配置,可在 JDK 17 环境下构建清晰、安全、易维护的 API 文档体系,充分发挥 SpringDoc 和 Knife4j 的现代化文档能力。
基础分组配置:
import org.springdoc.core.models.GroupedOpenApi;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class OpenApiGroupConfig { // 用户管理分组 @Bean public GroupedOpenApi userApi() { return GroupedOpenApi.builder() .group("用户管理") // 分组显示名称 .pathsToMatch("/api/user/**") // 路径匹配规则 .packagesToScan("com.example.user") // 包扫描路径 .build(); } // 订单管理分组 @Bean public GroupedOpenApi orderApi() { return GroupedOpenApi.builder() .group("订单管理") .pathsToMatch("/api/order/**") .packagesToScan("com.example.order") .build(); } // 分组自定义排序 @Bean public GroupedOpenApi firstGroup() { return GroupedOpenApi.builder() .group("01-核心接口") .order(1) // 分组排序(数值越小越靠前) .pathsToMatch("/core/**") .build(); } @Bean public GroupedOpenApi secondGroup() { return GroupedOpenApi.builder() .group("02-辅助接口") .order(2) .pathsToMatch("/support/**") .build(); }}
按安全权限分组:
@Beanpublic GroupedOpenApi adminApi() { return GroupedOpenApi.builder() .group("管理员接口") .pathsToMatch("/api/admin/**") // 只包含带有 @PreAuthorize("hasRole('ADMIN')") 的接口 .addOpenApiMethodFilter(method -> method.isAnnotationPresent(PreAuthorize.class) && method.getAnnotation(PreAuthorize.class).value().contains("ADMIN") ) .build();}
多版本 API 分组:
@Beanpublic GroupedOpenApi v1Api() { return GroupedOpenApi.builder() .group("API-v1") .pathsToMatch("/api/v1/**") .displayName("版本 1.0 (已弃用)") .build();}@Beanpublic GroupedOpenApi v2Api() { return GroupedOpenApi.builder() .group("API-v2") .pathsToMatch("/api/v2/**") .displayName("版本 2.0 (最新)") .build();}
第三方接口分组:
@Beanpublic GroupedOpenApi paymentApi() { return GroupedOpenApi.builder() .group("支付网关") .pathsToMatch("/payment/**") // 排除内部实现类 .packagesToExclude("com.example.internal.payment") .build();}
3.4 包名迁移与模块化适配
3.4.1 全局替换包名
IDE 操作:使用 IntelliJ/Eclipse 的全局替换功能(Ctrl+Shift+R),将以下包名替换:javax.servlet → jakarta.servletjavax.validation → jakarta.validationjavax.persistence → jakarta.persistenceMaven 插件辅助:使用 maven-replacer-plugin 自动化替换:com.google.code.maven-replacer-pluginreplacer1.5.3process-sourcesreplace**/*.javajavax.servletjakarta.servlet
3.4.2 模块化配置(JDK 17+)
// src/main/java/module-info.javaopen module com.example.api { requires spring.boot; requires spring.boot.autoconfigure; requires spring.web; requires springdoc.openapi.common; requires com.fasterxml.jackson.databind; exports com.example.api.controller; exports com.example.api.model;}
4、迁移后的验证与优化
4.1 验证访问
启动应用后,访问以下地址:
Knife4j UI 文档:http://localhost:8080/doc.html
OpenAPI JSON:http://localhost:8080/v3/api-docs
4.2 文档增强
响应示例:
@Operation(summary = "创建用户")@ApiResponses({ @ApiResponse( responseCode = "201", content = @Content( mediaType = "application/json", schema = @Schema(implementation = User.class), examples = @ExampleObject( name = "successExample", value = """ { "id": 1, "name": "张三" } """ ) ) ), @ApiResponse( responseCode = "400", content = @Content( examples = @ExampleObject( name = "errorExample", value = """ { "code": "INVALID_REQUEST", "message": "用户名不能为空" } """ ) ) )})public ResponseEntity createUser(@RequestBody User user) { ... }
离线文档导出:
Knife4j 导出:访问 http://localhost:8080/doc.html#/home,点击“下载 Markdown”或“下载 OpenAPI JSON”。
4.3 性能与安全优化
生产环境禁用 UI: springdoc: swagger-ui: enabled: false # 禁用 UI api-docs: enabled: true # 保留 JSON 生成(供内部系统使用)启用 OAuth2 支持: @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers(“/v3/api-docs/**”).hasRole(“DEVOPS”) .anyRequest().authenticated() ) .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); return http.build(); }
5、常见问题与解决方案
5.1. 错误:Type javax.servlet.http.HttpServletRequest not present
错误日志:java.lang.TypeNotPresentException: Type javax.servlet.http.HttpServletRequest not present
原因:未迁移到 Jakarta EE 包名。
解决步骤:
检查是否遗漏包名替换(使用 IDE 全局搜索 javax.servlet),更新依赖至 Jakarta 版本。全局替换代码中的 javax.servlet 为 jakarta.servlet。运行 mvn dependency:tree | grep javax.servlet 确认无冲突依赖。更新第三方库至 Jakarta 兼容版本(如 Hibernate 6.x、Tomcat 10.x)。
5.2. Knife4j 访问 /doc.html 报 404
原因:静态资源被拦截或未正确映射。
解决步骤:
确认使用的是 Knife4j OpenAPI3 的 Spring Boot Starter(knife4j-openapi3-jakarta-spring-boot-starter),而非旧版 Knife4j 或 SpringFox。检查静态资源路径(若自定义了 WebMvcConfigurer):Knife4j 的静态资源默认位于 classpath:/META-INF/resources/webjars/knife4j-openapi3-ui/,需确保资源未被拦截或覆盖。
import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 添加 Knife4j 的静态资源映射 registry.addResourceHandler("/doc.html") .addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/"); }}
检查 Spring Security 配置是否放行 /doc.html 和 /webjars/**:如果项目集成了 Spring Security,需放行 Knife4j 的静态资源和 API 文档接口。
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.web.SecurityFilterChain;@Configurationpublic class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth // 放行 Knife4j 相关路径 .requestMatchers( "/doc.html", "/webjars/**", "/v3/api-docs/**", "/favicon.ico" ).permitAll() .anyRequest().authenticated() ) .csrf(csrf -> csrf.disable()); // 如果不需要 CSRF 防护 return http.build(); }}
5.3 注解不生效或文档无内容
检查项:
确保控制器添加 @Tag,方法添加 @Operation。模型类字段未标注 @Schema。包扫描路径未覆盖(通过 @ComponentScan 或 springdoc.packagesToScan 配置)。排除旧版 Swagger 依赖冲突:mvn dependency:tree -Dincludes=io.springfox
6、总结
从 JDK 8 迁移到 JDK 17 不仅是版本的升级,更是技术栈向现代 Java 生态的过渡。通过 依赖替换、注解迁移、包名调整、模块化适配 四步核心操作,可高效完成 Swagger 升级。Knife4j 和 SpringDoc 的组合,不仅解决了兼容性问题,还提供了更强大的 API 文档管理能力。升级后,建议通过自动化测试和持续监控,确保系统的稳定性和可维护性。
以上就是从 JDK 8 到 JDK 17:Swagger 升级迁移指南的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/984325.html
微信扫一扫
支付宝扫一扫