从 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 构建的
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 (兼容 |
Servlet 规范 | 基于 | 迁移至 |
注解库 | io.swagger.annotations | io.swagger.v3.oas.annotations |
注解风格 | @Api , | @Tag , |
依赖管理 | 需手动管理版本,易冲突 | 通过 |
文档生成 | 需配置 | 自动扫描,通过 |
文档规范 | OpenAPI 2.0 | OpenAPI 3.0 |
UI 工具 | Swagger UI(基础功能) | Knife4j(增强功能,支持离线文档、权限控制、接口分组等) |
维护状态 | 停止维护(最后版本 | 活跃维护( |
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 依赖管理升级
移除旧依赖
<!-- 删除 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>
添加新依赖
<!-- 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>
排除冲突依赖
<!-- 检查并排除其他库中的 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 或 | 隐藏接口或参数 | @Hidden // 隐藏整个接口方法 |
@ApiImplicitParams | @Parameters + | 描述非直接声明的参数(如 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{@Beanpublic 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{// 用户管理分组@Beanpublic GroupedOpenApi userApi(){return GroupedOpenApi.builder().group("用户管理")// 分组显示名称.pathsToMatch("/api/user/**")// 路径匹配规则.packagesToScan("com.example.user")// 包扫描路径.build();}// 订单管理分组@Beanpublic GroupedOpenApi orderApi(){return GroupedOpenApi.builder().group("订单管理").pathsToMatch("/api/order/**").packagesToScan("com.example.order").build();}// 分组自定义排序@Beanpublic GroupedOpenApi firstGroup(){return GroupedOpenApi.builder().group("01-核心接口").order(1)// 分组排序(数值越小越靠前).pathsToMatch("/core/**").build();}@Beanpublic 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# 禁用 UIapi-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;@Configuration public class WebConfig implements WebMvcConfigurer {@Overridepublic 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;@Configuration public class SecurityConfig{@Beanpublic 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 文档管理能力。升级后,建议通过自动化测试和持续监控,确保系统的稳定性和可维护性。
感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!
CentOS 7 内核升级指南:解决兼容性问题并提升性能
Kubernetes RBAC 深入解析:权限体系详解、配置与排查
Kubernetes镜像拉取认证完全指南:8种实战方法解决私有仓库访问难题
MySQL性能优化(七):MySQL执行计划,真的很重要,来一起学习吧
喜欢就点个"在看"呗,留言、转发朋友圈
相关文章:

从 JDK 8 到 JDK 17:Swagger 升级迁移指南
点击上方“程序猿技术大咖”,关注并选择“设为星标” 回复“加群”获取入群讨论资格! 随着 Java 生态向 JDK 17 及 Jakarta EE 的演进,许多项目面临从 JDK 8 升级的挑战,其中 Swagger(API 文档工具)的兼容性…...
配置git命令缩写
以下是 Git 命令缩写的配置方法及常用方案,适用于 Linux/macOS/Windows 系统: 🔧 一、配置方法 1. 命令行设置(推荐) # 基础命令缩写 git config --global alias.st status git config --global alias.co che…...
Redis 缓存问题及其解决方案
1. 缓存雪崩 概念:缓存雪崩是指在缓存层出现大范围缓存失效或缓存服务器宕机的情况下,大量请求直接打到数据库,导致数据库压力骤增,甚至可能引发数据库宕机。 影响:缓存雪崩会导致系统性能急剧下降,甚至导…...

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

【发布实录】云原生+AI,助力企业全球化业务创新
5 月 22 日,在最新一期阿里云「飞天发布时刻」,阿里云云原生应用平台产品负责人李国强重磅揭晓面向 AI 场景的云原生产品体系升级,通过弹性智能的一体化架构、开箱即用的云原生 AI 能力,为中国企业出海提供新一代技术引擎。 发布会…...
vue中的派发事件与广播事件,及广播事件应用于哪些场景和一个表单验证例子
在 Vue 2.X 中,$dispatch 和 $broadcast 方法已经被废弃。官方认为基于组件树结构的事件流方式难以理解,并且在组件结构扩展时容易变得脆弱。因此,Vue 2.X 推荐使用其他方式来实现组件间的通信,例如通过 $emit 和 $on 方法&#x…...
DeepSeek 赋能智能养老:情感陪伴机器人的温暖革新
目录 一、引言二、智能养老情感陪伴机器人的市场现状与需求2.1 市场现状2.2 老年人情感陪伴需求分析 三、DeepSeek 技术详解3.1 DeepSeek 的技术特点3.2 与其他类似技术的对比优势 四、DeepSeek 在智能养老情感陪伴机器人中的具体应用4.1 自然语言处理与对话交互4.2 情感识别与…...

LabVIEW主轴故障诊断案例
LabVIEW 开发主轴机械状态识别与故障诊断系统,适配工业场景主轴振动监测需求。通过整合品牌硬件与软件算法,实现从信号采集到故障定位的全流程自动化,为设备维护提供数据支撑,提升数控机床运行可靠性。 面向精密制造企业数控机…...
gRPC 的四种通信模式完整示例
gRPC 的四种基本通信模式,包括完整的 .proto 文件定义和 Go 语言实现代码: 1. 简单 RPC (Unary RPC) - 请求/响应模式 客户端发送单个请求,服务端返回单个响应 calculator.proto protobuf syntax "proto3";package calculato…...
C#中Struct与IntPtr转换:实用扩展方法
C#中Struct与IntPtr转换:实用扩展方法 在 C# 编程的世界里,我们常常会遇到需要与非托管代码交互,或者进行一些底层内存操作的场景。这时,IntPtr类型就显得尤为重要,它可以表示一个指针或句柄,用来指向非托…...
Web安全:XSS、CSRF等常见漏洞及防御措施
Web安全:XSS、CSRF等常见漏洞及防御措施 一、XSS(跨站脚本攻击) 定义与原理 XSS攻击指攻击者将恶意脚本(如JavaScript、HTML标签)注入到Web页面中,当用户访问该页面时,脚本在浏览器端执行&…...
Java基础之数组(附带Comparator)
文章目录 基础概念可变参数组数组与ListComparator类1,基本概念2,使用Comparator的静态方法(Java 8)3,常用Comparator方法4,例子 排序与查找数组复制其他 基础概念 int[] anArray new int[10];只有创建对象时才会使用new关键字,所以数组是个…...

计算机组成与体系结构:补码数制二(Complementary Number Systems)
目录 4位二进制的减法 补码系统 🧠减基补码 名字解释: 减基补码有什么用? 计算方法 ❓为什么这样就能计算减基补码 💡 原理揭示:按位减法,模拟总减法! 那对于二进制呢?&…...

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

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

Java应用10(客户端与服务器通信)
Java客户端与服务器通信 Java提供了多种方式来实现客户端与服务器之间的通信,下面我将介绍几种常见的方法: 1. 基于Socket的基本通信 服务器端代码 import java.io.*; import java.net.*;public class SimpleServer {public static void main(String…...
STM32学习之I2C(理论篇)
📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…...
【C/C++】algorithm清单以及适用场景
文章目录 algorithm清单以及适用场景1 算法介绍1.1 分类1.2 非修改序列算法1.3 修改序列算法1.4 排序与堆算法1.5 集合操作算法(要求有序)1.5 查找算法1.6 二分查找算法(有序区间)1.7 去重与分区算法1.8 数值算法 <numeric>…...

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

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

小黑一层层削苹果皮式大模型应用探索:langchain中智能体思考和执行工具的demo
引言 小黑黑通过探索langchain源码,设计了一个关于agent使用工具的一个简化版小demo(代码可以跑通),主要流程: 1.问题输入给大模型。 2.大模型进行思考,输出需要执行的action和相关思考信息。 3.通过代理&…...
CppCon 2015 学习:Intro to the C++ Object Model
这段代码展示了使用 make 工具来编译 C 程序的简单过程。 代码和步骤解析: C 代码(intro.cpp):#include <iostream> int main() { std::cout<<"hello world\n"; } 这是一个简单的 C 程序,它包…...
Go 语言中的 make 函数详解
Go 语言中的 make 函数详解 make 是 Go 语言中的一个内置函数,用于初始化切片(slice)、映射(map)和通道(channel)这些引用类型。这些类型必须在使用前通过 make 初始化&#x…...

阿里云ACP云计算备考笔记 (4)——企业应用服务
目录 第一章 企业应用概览 第二章 云解析 1、云解析基本概念 2、域名管理流程 3、云解析记录类型 4、域名管理 ① 开启注册局安全锁 ② 域名赎回 第二章 内容分发网络CDN 1、CDN概念 2、使用CDN前后对比 3、使用CDN的优势 4、阿里云CDN的优势 5、配置网页性能优化…...
用 NGINX 构建高效 SMTP 代理`ngx_mail_smtp_module`
一、模块定位与作用 协议代理 NGINX 监听指定端口(如 25、587、465 等),接收客户端的 SMTP 会话请求。代理层在会话中透明转发客户端的 EHLO、MAIL FROM、RCPT TO、DATA 等命令到后端 MTA。 认证控制 通过 smtp_auth 指令指定允许的 SASL 认…...
【前端】常用组件的CSS
1. button的样式修改 每个环节有五个不同的状态:link,hover,active,focus和visited. Link是正常的外观,hover当你鼠标悬停时,active是单击它时的状态,focus跟随活动状态,visited是你在最近点击的链接未聚焦时结束的状态。 纯CSS 以下为例子,按下后从浅紫到深紫。注…...
【华为云学习与认证】以华为云物联网为基座的全栈开发(从物联网iot平台模块到应用展示、数据分析、机器学习、嵌入式开发等)的系统性学习与认证路线
总目标 学习以华为云物联网为基座的全栈开发(从物联网iot平台模块到应用展示、数据分析、机器学习、嵌入式开发等)的系统性学习与认证路线。计划包含阶段学习、技术文档、实操实际操作、开发路径与考证规划,提供职业生涯基础性规划。 注意&…...
OpenCV 键盘响应来切换图像
一、知识点 1、int waitKey(int delay 0); (1)、等待按键。 等待指定的毫秒数,返回按键的ASCII码。 (2)、返回值: int型,表示按键ASCII码。 若没有按键,指定时间过去,返回-1。 (3)、参数delay: 等待时间,单位毫…...

ARM SMMUv3简介(一)
1.概述 SMMU(System Memory Management Unit,系统内存管理单元)是ARM架构中用于管理设备访问系统内存的硬件模块。SMMU和MMU的功能类似,都是将虚拟地址转换成物理地址,不同的是MMU转换的虚拟地址来自CPU,S…...
C#提取CAN ASC文件时间戳:实现与性能优化
C#提取CAN ASC文件时间戳:实现与性能优化 在汽车电子和工业控制领域,CAN总线是最常用的通信协议之一。而ASC(ASCII)文件作为CAN总线数据的标准日志格式,广泛应用于数据记录和分析场景。本文将深入探讨如何高效地从CAN…...