0

0

从 JDK 8 到 JDK 17:Swagger 升级迁移指南

看不見的法師

看不見的法師

发布时间:2025-11-26 19:20:29

|

254人浏览过

|

来源于php中文网

原创

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

从 jdk 8 到 jdk 17:swagger 升级迁移指南

随着 java 生态向 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 构建的 SpringFoxSwagger 2.x)因依赖旧规范无法兼容新版本。Jakarta EE 的崛起:Java EE 移交 Eclipse 基金会后更名为 Jakarta EE,包名从 javax.* 改为 jakarta.*。核心冲突:Spring Boot 3.xSpringDocSwagger 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

定义接口的响应状态码和描述

Viggle AI
Viggle AI

Viggle AI是一个AI驱动的3D动画生成平台,可以帮助用户创建可控角色的3D动画视频。

下载

@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,无需配置 DocketSwagger2Markup。必要配置:仅需定义 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 文档体系,充分发挥 SpringDocKnife4j 的现代化文档能力。

基础分组配置:

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.servletjakarta.servletjavax.validationjakarta.validationjavax.persistencejakarta.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.servletjakarta.servlet。运行 mvn dependency:tree | grep javax.servlet 确认无冲突依赖。更新第三方库至 Jakarta 兼容版本(如 Hibernate 6.x、Tomcat 10.x)。

html-%E6%8A%A5-404">5.2. Knife4j 访问 /doc.html 报 404

原因:静态资源被拦截或未正确映射。

解决步骤:

确认使用的是 Knife4j OpenAPI3 的 Spring Boot Starter(knife4j-openapi3-jakarta-spring-boot-starter),而非旧版 Knife4jSpringFox。检查静态资源路径(若自定义了 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。包扫描路径未覆盖(通过 @ComponentScanspringdoc.packagesToScan 配置)。排除旧版 Swagger 依赖冲突:mvn dependency:tree -Dincludes=io.springfox

6、总结

从 JDK 8 迁移到 JDK 17 不仅是版本的升级,更是技术栈向现代 Java 生态的过渡。通过 依赖替换、注解迁移、包名调整、模块化适配 四步核心操作,可高效完成 Swagger 升级。Knife4j 和 SpringDoc 的组合,不仅解决了兼容性问题,还提供了更强大的 API 文档管理能力。升级后,建议通过自动化测试和持续监控,确保系统的稳定性和可维护性。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

831

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

737

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

733

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16925

2023.08.03

PHP 表单处理与文件上传安全实战
PHP 表单处理与文件上传安全实战

本专题聚焦 PHP 在表单处理与文件上传场景中的实战与安全问题,系统讲解表单数据获取与校验、XSS 与 CSRF 防护、文件类型与大小限制、上传目录安全配置、恶意文件识别以及常见安全漏洞的防范策略。通过贴近真实业务的案例,帮助学习者掌握 安全、规范地处理用户输入与文件上传的完整开发流程。

1

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django DRF 源码解析
Django DRF 源码解析

共21课时 | 1.4万人学习

Docker 17 中文开发手册
Docker 17 中文开发手册

共0课时 | 0人学习

php全栈开发经验分享直播课
php全栈开发经验分享直播课

共28课时 | 10.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号