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

看不見的法師
发布: 2025-11-26 19:20:29
原创
192人浏览过

☞☞☞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

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

知海图Chat
知海图Chat

知乎与面壁智能合作推出的智能对话助手

知海图Chat 157
查看详情 知海图Chat

@ApiResponse(responseCode = "404", description = "用户不存在")

@ApiIgnore

@Hidden 或 @Parameter(hidden = true)

隐藏接口或参数

@Hidden // 隐藏整个接口方法

@ApiImplicitParams

@Parameters + @Parameter

描述非直接声明的参数(如 Header 参数)

@Parameters({ @Parameter(name = "token", in = HEADER, description = "认证令牌") })

@ApiImplicitParam

@Parameter

单个隐式参数定义

同上

<code class="javascript">// 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() {      //...   }}</code>
登录后复制
<code class="javascript">// 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() {      // ...   }}</code>
登录后复制

模型类注解迁移:

SpringFox (Swagger 2.x)

SpringDoc (OpenAPI 3.x)

用途

示例

@ApiModel

@Schema

描述数据模型类

@Schema(name = "UserDTO", description = "用户传输对象")

@ApiModelProperty

@Schema

描述模型字段的详细信息

@Schema(description = "用户名", example = "张三", requiredMode = REQUIRED)

<code class="javascript">// JDK 8(SpringFox)@ApiModel(value = "User", description = "用户实体")public class User {    @ApiModelProperty(value = "用户名", required = true, example = "张三")    private String name;}</code>
登录后复制
<code class="javascript">// JDK 17(SpringDoc)@Schema(name = "User", description = "用户实体")public class User {    @Schema(description = "用户名", example = "张三", requiredMode = Schema.RequiredMode.REQUIRED)    private String name;}</code>
登录后复制

3.3 全局配置调整

是否还需要传统 SwaggerConfig?

不需要:Knife4j OpenAPI3 基于 SpringDoc,无需配置 DocketSwagger2Markup。必要配置:仅需定义 OpenAPI Bean(如上文的 OpenApiConfig)即可。
3.3.1 SpringDoc 配置类
<code class="javascript">@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")));    }}</code>
登录后复制
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 的现代化文档能力。

基础分组配置:

<code class="javascript">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();    }}</code>
登录后复制

按安全权限分组:

<code class="javascript">@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();}</code>
登录后复制

多版本 API 分组:

<code class="javascript">@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();}</code>
登录后复制

第三方接口分组:

<code class="javascript">@Beanpublic GroupedOpenApi paymentApi() {    return GroupedOpenApi.builder()            .group("支付网关")            .pathsToMatch("/payment/**")            // 排除内部实现类            .packagesToExclude("com.example.internal.payment")             .build();}</code>
登录后复制

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+)
<code class="javascript">// 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;}</code>
登录后复制

4、迁移后的验证与优化

4.1 验证访问

启动应用后,访问以下地址:

Knife4j UI 文档:http://localhost:8080/doc.html

OpenAPI JSON:http://localhost:8080/v3/api-docs

4.2 文档增强

响应示例:

<code class="javascript">@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<User> createUser(@RequestBody User user) { ... }</code>
登录后复制

离线文档导出:

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/,需确保资源未被拦截或覆盖。
<code class="javascript">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/");   }}</code>
登录后复制
检查 Spring Security 配置是否放行 /doc.html 和 /webjars/**:如果项目集成了 Spring Security,需放行 Knife4j 的静态资源和 API 文档接口。
<code class="javascript">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();   }}</code>
登录后复制

5.3 注解不生效或文档无内容

检查项:

确保控制器添加 @Tag,方法添加 @Operation。模型类字段未标注 @Schema。包扫描路径未覆盖(通过 @ComponentScanspringdoc.packagesToScan 配置)。排除旧版 Swagger 依赖冲突:mvn dependency:tree -Dincludes=io.springfox

6、总结

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

以上就是从 JDK 8 到 JDK 17:Swagger 升级迁移指南的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

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