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

news2025/7/26 13:29:46

点击上方“程序猿技术大咖”,关注并选择“设为星标”

回复“加群”获取入群讨论资格!

随着 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.x 和 SpringDocSwagger 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.xSpring Boot 3.x

(兼容 2.7.x

Servlet 规范

基于 javax.servlet

迁移至 jakarta.servletJakarta EE 9+

注解库io.swagger.annotationsio.swagger.v3.oas.annotations
注解风格@Api

@ApiOperation

@Tag

@Operation(更符合 OpenAPI 3.0

依赖管理

需手动管理版本,易冲突

通过 Spring Boot Starter 简化依赖

文档生成

需配置 Docket

自动扫描,通过 OpenAPI Bean 全局配置

文档规范OpenAPI 2.0OpenAPI 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 依赖管理升级

  1. 移除旧依赖

    <!-- 删除 SpringFox 相关依赖 -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>3.0.0</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>3.0.0</version>
    </dependency>
  2. 添加新依赖

    <!-- SpringDoc 核心 -->
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
        <!-- 最新版本见:https://springdoc.org/ -->
        <version>2.5.0</version>
    </dependency>
    
    <!-- Knife4j 增强 UI(可选) -->
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
        <!-- 最新版本见:https://doc.xiaominfo.com/ -->
        <version>4.5.0</version>
    </dependency>
  3. 排除冲突依赖

    <!-- 检查并排除其他库中的 javax.servlet 依赖 -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <exclusions>
            <exclusion>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

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

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

@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 ="用户接口")
@RestController
public 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 ="用户接口")
@RestController
public 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 配置类
@Configuration
public 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;

@Configuration
public 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();
    }
}

按安全权限分组:

@Bean
public 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 分组:

@Bean
public GroupedOpenApi v1Api(){
    return GroupedOpenApi.builder()
            .group("API-v1")
            .pathsToMatch("/api/v1/**")
            .displayName("版本 1.0 (已弃用)")
            .build();
}

@Bean
public GroupedOpenApi v2Api(){
    return GroupedOpenApi.builder()
            .group("API-v2")
            .pathsToMatch("/api/v2/**")
            .displayName("版本 2.0 (最新)")
            .build();
}

第三方接口分组:

@Bean
public 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.servlet

    • javax.validation → jakarta.validation

    • javax.persistence → jakarta.persistence

  • Maven 插件辅助

    使用 maven-replacer-plugin 自动化替换:

    <plugin>
        <groupId>com.google.code.maven-replacer-plugin</groupId>
        <artifactId>replacer</artifactId>
        <version>1.5.3</version>
        <executions>
            <execution>
                <phase>process-sources</phase>
                <goals><goal>replace</goal></goals>
            </execution>
        </executions>
        <configuration>
            <includes>**/*.java</includes>
            <replacements>
                <replacement>
                    <token>javax.servlet</token>
                    <value>jakarta.servlet</value>
                </replacement>
            </replacements>
        </configuration>
    </plugin>
3.4.2 模块化配置(JDK 17+)
// src/main/java/module-info.java
open 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<User>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 包名。

解决步骤

  1. 检查是否遗漏包名替换(使用 IDE 全局搜索 javax.servlet),更新依赖至 Jakarta 版本。

  2. 全局替换代码中的 javax.servlet 为 jakarta.servlet

  3. 运行 mvn dependency:tree | grep javax.servlet 确认无冲突依赖。

  4. 更新第三方库至 Jakarta 兼容版本(如 Hibernate 6.x、Tomcat 10.x)。

5.2. Knife4j 访问 /doc.html 报 404

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

解决步骤

  1. 确认使用的是 Knife4j OpenAPI3 的 Spring Boot Starter(knife4j-openapi3-jakarta-spring-boot-starter),而非旧版 Knife4j 或 SpringFox

  2. 检查静态资源路径(若自定义了 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;
    
    @Configuration
    public 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/");
        }
    }
  3. 检查 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;
    
    @Configuration
    public 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 注解不生效或文档无内容

检查项

  1. 确保控制器添加 @Tag,方法添加 @Operation

  2. 模型类字段未标注 @Schema

  3. 包扫描路径未覆盖(通过 @ComponentScan 或 springdoc.packagesToScan 配置)。

  4. 排除旧版 Swagger 依赖冲突:

    mvn dependency:tree -Dincludes=io.springfox

6、总结

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


感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!

  • CentOS 7 内核升级指南:解决兼容性问题并提升性能

  • Kubernetes RBAC 深入解析:权限体系详解、配置与排查

  • Kubernetes镜像拉取认证完全指南:8种实战方法解决私有仓库访问难题

  • MySQL性能优化(七):MySQL执行计划,真的很重要,来一起学习吧

喜欢就点个"在看"呗,留言、转发朋友圈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2404368.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 Coze 工作流一键生成抖音书单视频:全流程拆解与技术实现

使用 Coze 工作流一键生成抖音书单视频&#xff1a;全流程拆解与技术实现&#xff08;提供工作流&#xff09; 摘要&#xff1a;本文基于一段关于使用 Coze 平台构建抖音爆火书单视频的详细讲解&#xff0c;总结出一套完整的 AI 视频自动化制作流程。内容涵盖从思路拆解、节点配…

【发布实录】云原生+AI,助力企业全球化业务创新

5 月 22 日&#xff0c;在最新一期阿里云「飞天发布时刻」&#xff0c;阿里云云原生应用平台产品负责人李国强重磅揭晓面向 AI 场景的云原生产品体系升级&#xff0c;通过弹性智能的一体化架构、开箱即用的云原生 AI 能力&#xff0c;为中国企业出海提供新一代技术引擎。 发布会…

LabVIEW主轴故障诊断案例

LabVIEW 开发主轴机械状态识别与故障诊断系统&#xff0c;适配工业场景主轴振动监测需求。通过整合品牌硬件与软件算法&#xff0c;实现从信号采集到故障定位的全流程自动化&#xff0c;为设备维护提供数据支撑&#xff0c;提升数控机床运行可靠性。 ​ 面向精密制造企业数控机…

计算机组成与体系结构:补码数制二(Complementary Number Systems)

目录 4位二进制的减法 补码系统 &#x1f9e0;减基补码 名字解释&#xff1a; 减基补码有什么用&#xff1f; 计算方法 ❓为什么这样就能计算减基补码 &#x1f4a1; 原理揭示&#xff1a;按位减法&#xff0c;模拟总减法&#xff01; 那对于二进制呢&#xff1f;&…

C#使用MindFusion.Diagramming框架绘制流程图(2):流程图示例

上一节我们初步介绍MindFusion.Diagramming框架 C#使用MindFusion.Diagramming框架绘制流程图(1):基础类型-CSDN博客 这里演示示例程序: 新建Windows窗体应用程序FlowDiagramDemo,将默认的Form1重命名为FormFlowDiagram. 右键FlowDiagramDemo管理NuGet程序包 输入MindFusio…

【物联网-ModBus-RTU

物联网-ModBus-RTU ■ 优秀博主链接■ ModBus-RTU介绍■&#xff08;1&#xff09;帧结构■&#xff08;2&#xff09;查询功能码 0x03■&#xff08;3&#xff09;修改单个寄存器功能码 0x06■&#xff08;4&#xff09;Modbus RTU 串口收发数据分析 ■ 优秀博主链接 Modbus …

Java应用10(客户端与服务器通信)

Java客户端与服务器通信 Java提供了多种方式来实现客户端与服务器之间的通信&#xff0c;下面我将介绍几种常见的方法&#xff1a; 1. 基于Socket的基本通信 服务器端代码 import java.io.*; import java.net.*;public class SimpleServer {public static void main(String…

Python_day47

作业&#xff1a;对比不同卷积层热图可视化的结果 一、不同卷积层的特征特性 卷积层类型特征类型特征抽象程度对输入的依赖程度低层卷积层&#xff08;如第 1 - 3 层&#xff09;边缘、纹理、颜色、简单形状等基础特征低高&#xff0c;直接与输入像素关联中层卷积层&#xff08…

如何在mac上安装podman

安装 Podman 在 macOS 上 在 macOS 上安装 Podman 需要使用 Podman 的桌面客户端工具 Podman Desktop 或通过 Homebrew 安装命令行工具。 使用 Homebrew 安装 Podman&#xff1a; (base) ninjamacninjamacdeMacBook-Air shell % brew install podman > Auto-updating Hom…

小黑一层层削苹果皮式大模型应用探索:langchain中智能体思考和执行工具的demo

引言 小黑黑通过探索langchain源码&#xff0c;设计了一个关于agent使用工具的一个简化版小demo&#xff08;代码可以跑通&#xff09;&#xff0c;主要流程&#xff1a; 1.问题输入给大模型。 2.大模型进行思考&#xff0c;输出需要执行的action和相关思考信息。 3.通过代理&…

阿里云ACP云计算备考笔记 (4)——企业应用服务

目录 第一章 企业应用概览 第二章 云解析 1、云解析基本概念 2、域名管理流程 3、云解析记录类型 4、域名管理 ① 开启注册局安全锁 ② 域名赎回 第二章 内容分发网络CDN 1、CDN概念 2、使用CDN前后对比 3、使用CDN的优势 4、阿里云CDN的优势 5、配置网页性能优化…

ARM SMMUv3简介(一)

1.概述 SMMU&#xff08;System Memory Management Unit&#xff0c;系统内存管理单元&#xff09;是ARM架构中用于管理设备访问系统内存的硬件模块。SMMU和MMU的功能类似&#xff0c;都是将虚拟地址转换成物理地址&#xff0c;不同的是MMU转换的虚拟地址来自CPU&#xff0c;S…

hadoop集群datanode启动显示init failed,不能解析hostname

三个datanode集群&#xff0c;有一个总是起不起来。去查看log显示 Initialization failed for Block pool BP-1920852191-192.168.115.154-1749093939738 (Datanode Uuid 89d9df36-1c01-4f22-9905-517fee205a8e) service to node154/192.168.115.154:8020 Datanode denied com…

浏览器工作原理05 [#] 渲染流程(上):HTML、CSS和JavaScript是如何变成页面的

引用 浏览器工作原理与实践 一、提出问题 在上一篇文章中我们介绍了导航相关的流程&#xff0c;那导航被提交后又会怎么样呢&#xff1f;就进入了渲染阶段。这个阶段很重要&#xff0c;了解其相关流程能让你“看透”页面是如何工作的&#xff0c;有了这些知识&#xff0c;你可…

|从零开始的Pyside2界面编程| 用Pyside2打造一个AI助手界面

&#x1f411; |从零开始的Pyside2界面编程| 用Pyside2打造一个AI助手界面 &#x1f411; 文章目录 &#x1f411; |从零开始的Pyside2界面编程| 用Pyside2打造一个AI助手界面 &#x1f411;♈前言♈♈调取Deepseek大模型♈♒准备工作♒♒调用API♒ ♈将模型嵌入到ui界面中♈♈…

pikachu靶场通关笔记20 SQL注入03-搜索型注入(GET)

目录 一、SQL注入 二、搜索型注入 三、源码分析 1、渗透思路1 2、渗透思路2 四、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入百分号单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取…

产品笔试专业名词梳理

目录 产品常识 四种常见广告形式 贴片广告 中插广告 信息流广告 横幅广告 BAT和TMD BAT TMD 付费渗透率 蓝海市场、红海市场 蓝海市场 红海市场 竞品研究 SWOT分析 SWOT分析的核心目的&#xff1a; SWOT分析的优点&#xff1a; SWOT分析的局限与注意事项&…

【前端】es6相关,柯里化

0. 严格模式 严格模式的概念从ES6引进。通过严格模式&#xff0c;可以在函数内部选择进行较为严格的全局或局部的错误条件检测。 MDN中严格模式的描述 严格模式通过抛出错误来消除了一些原有静默错误严格模式修复了一些导致 JavaScript引擎难以执行优化的缺陷&#xff1a;有时…

51单片机基础部分——矩阵按键检测

前言 上一节&#xff0c;我们说到了独立按键的检测以及使用&#xff0c;但是独立按键每一个按键都要对应一个IO口进行检测&#xff0c;在一些需要多按键的情况下&#xff0c;使用过多的独立按键会过多的占用单片机的IO资源&#xff0c;为了解决这个问题的出现&#xff0c;我们…

SpringBoot2.3.1集成Knife4j接口文档

首先要查看项目中pom文件里面有没有swagger和knife4j的依赖&#xff0c;如果有的话删除&#xff0c;加入以下依赖 <!-- swagger --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-spring-boot-starter</…