Springfox、Springdoc和Swagger
Springfox、Swagger 和 Springdoc
Springfox、Swagger 和 Springdoc 是用于在 Spring Boot 项目中生成API文档的工具,但它们之间有显著的区别和演进关系:
1.Swagger
简介
- Swagger 是一个开源项目,旨在为 RESTful APIs 提供交互式文档。
- 最早由 SmartBear 开发,后来演进为 OpenAPI 规范 的前身。
- Swagger 的核心组件包括:
- Swagger UI:提供交互式的 Web 界面,展示 API 端点并允许直接调用测试。
- Swagger Editor:编写和查看 OpenAPI 描述文件的工具。
- Swagger Codegen:基于 API 描述文件生成客户端和服务端代码。
与 Spring 的关系
Swagger 本身不依赖 Spring,但通过扩展工具(如 Springfox)使其在 Spring 框架中得到使用。
Swagger2是Swagger规范的一个实现
Swagger3是基于OpenAPI规范的新版本,它是Swagger规范的后续标准,
提供了更好的可扩展性和更丰富的功能。Spring Boot从2.6.0版本开始不再原生支持Swagger2,因为Spring官方的更新导致了与Swagger2的不兼容。
开发者需要使用Springdoc OpenAPI库来替代Springfox,以在Spring Boot 2.6.0及以上版本中集成OpenAPI文档。
Springdoc OpenAPI提供了对OpenAPI 3.0规范的支持,并且与Spring Boot的新版本兼容。
2.Springfox
简介
- Springfox 是一个专门为 Spring Boot 集成 Swagger 的库。
- 核心功能:扫描 Spring 项目中的注解和配置,生成基于 Swagger 的 API 文档。
- 特点:
- 支持 Spring MVC 和 Spring WebFlux。
- 使用
@ApiOperation和@ApiModel等注解来生成文档。 - 支持 Swagger 2 和部分 OpenAPI 3 特性。
现状
- 停止活跃维护:Springfox 项目在 2021 年后维护频率大幅降低,社区对它的支持逐渐减少。3.0.x版本以后没有再更新
- 兼容性问题:
- 与 Spring Boot 2.6.x 和更高版本存在兼容性问题,主要是因为 Springfox 使用的
RequestMappingHandlerMapping被 Spring Framework 的 Web 模块改动影响。
- 与 Spring Boot 2.6.x 和更高版本存在兼容性问题,主要是因为 Springfox 使用的
何时使用
- 如果项目是基于 Spring Boot 2.5.x 或更早版本,并且已经使用了 Springfox,可以暂时保留。
- 对于新项目,不建议继续使用 Springfox。
3.Springdoc
简介
- Springdoc 是一个现代化工具,基于 OpenAPI 3 规范设计,替代 Springfox。
- 提供与 Spring Boot 的无缝集成:
- 自动生成 OpenAPI 3 文档。
- 提供嵌入式的 Swagger UI(无需单独配置)。
- 兼容 Spring MVC 和 Spring WebFlux。
优点
- 强大兼容性:
- 与 Spring Boot 2.x 和 3.x 完美兼容。
- 支持 Spring Framework 的最新功能,例如响应式流和新注解模型。
- 零配置:
- 大部分功能开箱即用,减少了复杂的注解和配置需求。
- 社区活跃:
- 相比 Springfox,Springdoc 项目更活跃,持续发布新版本,解决社区反馈。
使用方式
1.添加 Maven 依赖:
<dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-ui</artifactId><version>最新版本</version>
</dependency>
2.启用后,访问默认路径 http://localhost:8080/swagger-ui.html。
总结:它们的关系与选择
| 工具 | 关系 | 适用场景 | 当前建议 |
|---|---|---|---|
| Swagger | 基础规范和工具 | 原始工具,用于标准化 API 文档 | 用于 OpenAPI 标准支持 |
| Springfox | Swagger 的 Spring 集成实现 | 传统项目(Spring Boot 2.5.x) | 不再推荐,已过时 |
| Springdoc | 基于 OpenAPI 3 的现代化替代工具 | 新项目,支持最新的 Spring Boot | 强烈推荐 |
迁移建议:从 Springfox 到 Springdoc
如果你当前使用 Springfox,但需要升级 Spring Boot 或改进文档支持,可以迁移到 Springdoc:
- 替换依赖:
- 移除
springfox-swagger2和springfox-swagger-ui。 - 添加
springdoc-openapi-ui。
- 移除
- 注解适配:
- Springdoc 支持 OpenAPI 3 的注解,通常是标准的 JSR-303 和 Spring 注解。
- 替换
@ApiOperation为@Operation,替换@ApiModel为标准注解。
- 配置改动:
- Springdoc 几乎不需要额外配置,大部分文档生成会自动完成。
结论:对于新项目,推荐使用 Springdoc;对于维护中的老项目,可以逐步迁移到 Springdoc,以便享受最新功能和更好的兼容性。
使用springboot2.6+版本和swagger2不兼容的解决方案
以下是一个springboot2.7.10集成swagger2和knife4j的例子
1、引入knife4j
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version>
</dependency>
knife4j官方建议开发者不要使用

2、knife4j配置文件
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;@Configuration
@EnableSwagger2
@EnableKnife4j
public class Knife4jConfig {@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).useDefaultResponseMessages(false).enable(true).apiInfo(apiInfo()).select()//.apis(RequestHandlerSelectors.basePackage("com.linear.visual.controller")).apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build().securitySchemes(Collections.singletonList(securityScheme())).securityContexts(securityContexts());}private ApiInfo apiInfo() {return new ApiInfoBuilder().description("可视化接口").contact(new Contact("Linear", "linear", "linear")).version("v1.0.0").title("API测试文档").build();}@BeanSecurityScheme securityScheme() {return new ApiKey("Authorization", "Authorization", "header");}/*** 安全上下文*/private List<SecurityContext> securityContexts() {List<SecurityContext> securityContexts = new ArrayList<>();securityContexts.add(SecurityContext.builder().securityReferences(defaultAuth()).build());return securityContexts;}/*** 默认的安全上引用*/private List<SecurityReference> defaultAuth() {AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];authorizationScopes[0] = authorizationScope;List<SecurityReference> securityReferences = new ArrayList<>();securityReferences.add(new SecurityReference("Authorization", authorizationScopes));return securityReferences;}
}
如果使用低版本的springboot比如2.6以下的,基本上都可以成功的。
但是使用2.6以上版本,这个时候可能会报启动失败
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerExceptionat org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.26.jar:5.3.26]at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.26.jar:5.3.26]at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.26.jar:5.3.26]at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.26.jar:5.3.26]at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.26.jar:5.3.26]at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:937) ~[spring-context-5.3.26.jar:5.3.26]at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.26.jar:5.3.26]at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.10.jar:2.7.10]at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) ~[spring-boot-2.7.10.jar:2.7.10]at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.10.jar:2.7.10]at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) ~[spring-boot-2.7.10.jar:2.7.10]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) ~[spring-boot-2.7.10.jar:2.7.10]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) ~[spring-boot-2.7.10.jar:2.7.10]at com.asr.hedu.fsp.service.oms.course.OmsCourseBootstrap.main(OmsCourseBootstrap.java:47) ~[classes/:na]
Caused by: java.lang.NullPointerException: nullat springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0]at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113) ~[springfox-core-3.0.0.jar:3.0.0]at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89) ~[springfox-spi-3.0.0.jar:3.0.0]at java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) ~[na:na]at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) ~[na:na]at java.base/java.util.TimSort.sort(TimSort.java:234) ~[na:na]at java.base/java.util.Arrays.sort(Arrays.java:1515) ~[na:na]at java.base/java.util.ArrayList.sort(ArrayList.java:1750) ~[na:na]at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:392) ~[na:na]at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485) ~[na:na]at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[na:na]at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[na:na]at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0]at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655) ~[na:na]at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[na:na]at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[na:na]at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107) ~[springfox-spring-web-3.0.0.jar:3.0.0]at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91) ~[springfox-spring-web-3.0.0.jar:3.0.0]at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82) ~[springfox-spring-web-3.0.0.jar:3.0.0]at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100) ~[springfox-spring-web-3.0.0.jar:3.0.0]at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) ~[spring-context-5.3.26.jar:5.3.26]... 14 common frames omitted
这个问题经查询跟springboot的bean初始化有关系,后续的版本更改了相关的东西,具体是什么没有细究,反正参照stackoverflow中的修改方法,加入一下配置类就可以避免错误
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;/*** swagger config** @author zxl* @date 2023-05-16*/
@Configuration
public class SwaggerConfig {@Beanpublic BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {return new BeanPostProcessor() {@Overridepublic Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {customizeSpringfoxHandlerMappings(getHandlerMappings(bean));}return bean;}private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null).collect(Collectors.toList());mappings.clear();mappings.addAll(copy);}@SuppressWarnings("unchecked")private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {try {Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");assert field != null;field.setAccessible(true);return (List<RequestMappingInfoHandlerMapping>) field.get(bean);} catch (IllegalArgumentException | IllegalAccessException e) {throw new IllegalStateException(e);}}};}
}
加入后启动正常,但是访问swagger的/v2/api-docs接口,发现没有获得数据,接口内容是空的。
这是通过搜索得到有几种解决方案
1、ShortVideoSwagger2的配置类需要集成WebMvcConfigurationSupport
2、ShortVideoSwagger2的配置类增加@EnableWebMvc注解
3、springboot的配置增加增加一下配置
spring:mvc:pathmatch:matching-strategy: ANT_PATH_MATCHE
通过试验得知,这三种接口都可以解决,但是前两种是有副总用的
@EnableWebMvc建议慎用,最后在非springboot项目中使用
前两种解决方案会破坏springboot对springwebmvc的自动装配,导致自定义的一些convertor或者ObjectMapper失效。
目前我的项目中是自定义的ObjectMapper失效。所以最后使用第三种方式,后期的springboot版本的matching-strategy默认的改为了PATH_PATTERN_PARSER,把它改为ANT_PATH_MATCHER就可以了。
相关文章:
Springfox、Springdoc和Swagger
Springfox、Swagger 和 Springdoc Springfox、Swagger 和 Springdoc 是用于在 Spring Boot 项目中生成API文档的工具,但它们之间有显著的区别和演进关系: 1.Swagger 简介 Swagger 是一个开源项目,旨在为 RESTful APIs 提供交互式文档。最…...
在Spring Boot项目中如何实现获取FTP远端目录结构
Java语言实现获取FTP远端目录结构的实现方式有多种,在Spring Boot 项目中,最简单和快速的方式就是使用Spring Integration 实现FTP相关的功能。 前言 本篇的示例和演示基于Windows 的FTP 服务,关于如何在Windows 开启FTP服务可以参考: Windows 如何开启和使用FTP服务 本…...
Flutter_学习记录_device_info_plus 插件获取设备信息
引入三方库device_info_plus导入头文件 import package:device_info_plus/device_info_plus.dart;获取设备信息的主要代码 DeviceInfoPlugin deviceInfoPlugin DeviceInfoPlugin(); BaseDeviceInfo deviceInfo await deviceInfoPlugin.deviceInfo;完整案例 import package…...
Java高频面试之集合-10
hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶 面试官:详解红黑树?HashMap为什么不用二叉树/平衡树呢? 一、红黑树(Red-Black Treeÿ…...
never_give_up
一个很有意思的题: never_give_up - Bugku CTF平台 注意到注释里面有1p.html,我们直接在源代码界面看,这样就不会跳转到它那个链接的: 然后解码可得: ";if(!$_GET[id]) {header(Location: hello.php?id1);exi…...
Python Selenium库入门使用,图文详细。附网页爬虫、web自动化操作等实战操作。
文章目录 前言1 创建conda环境安装Selenium库2 浏览器驱动下载(以Chrome和Edge为例)3 基础使用(以Chrome为例演示)3.1 与浏览器相关的操作3.1.1 打开/关闭浏览器3.1.2 访问指定域名的网页3.1.3 控制浏览器的窗口大小3.1.4 前进/后…...
聊天室Python脚本——ChatGPT,好用
下面提供两个 Python 脚本,一个作为服务器端(chat_server.py),一个作为客户端(chat_client.py)。你可以在一台电脑上运行服务器脚本,然后在不同电脑上运行客户端脚本(连接时指定服务…...
AI4CODE】3 Trae 锤一个贪吃蛇的小游戏
【AI4CODE】目录 【AI4CODE】1 Trae CN 锥安装配置与迁移 【AI4CODE】2 Trae 锤一个 To-Do-List 这次还是采用 HTML/CSS/JAVASCRIPT 技术栈 Trae 锤一个贪吃蛇的小游戏。 1 环境准备 创建一个 Snake 的子文件夹,清除以前的会话记录。 2 开始构建 2.1 输入会…...
【语料数据爬虫】Python爬虫|批量采集会议纪要数据(1)
前言 本文是该专栏的第2篇,后面会持续分享Python爬虫采集各种语料数据的的干货知识,值得关注。 在本文中,笔者将主要来介绍基于Python,来实现批量采集“会议纪要”数据。同时,本文也是采集“会议纪要”数据系列的第1篇。 采集相关数据的具体细节部分以及详细思路逻辑,笔…...
Linux 进程的一生(一):进程与线程的创建机制解析
在 Linux 操作系统中,每个任务都以「进程」的形式存在。但 Linux 下的「线程」又是什么?Linux 并没有单独定义一种全新数据结构来表示线程,而是将线程视为一种特殊的进程——一种共享资源的轻量级进程。然而,在具体实现和运行机制…...
【面试题集合】
目录 强缓存VS协商缓存**一、强缓存(本地缓存)**1. **定义**2. **核心 HTTP 头**3. **缓存生效流程**4. **应用场景** **二、协商缓存(条件请求)**1. **定义**2. **核心 HTTP 头**3. **缓存生效流程**4. **应用场景** **三、强缓存…...
【Academy】SSRF ------ Server-side request forgery
SSRF ------ Server-side request forgery 1. 什么是 SSRF?2. SSRF 攻击的影响是什么?3. 常见的 SSRF 攻击3.1 针对服务器的 SSRF 攻击3.2 针对其他后端系统的 SSRF 攻击 4. 规避常见的 SSRF 防御4.1 具有基于黑名单的输入过滤器的 SSRF4.2 具有基于白名…...
Git 的详细介绍及用法
一、Git 的优点 分布式版本控制 每个开发者都拥有完整的仓库副本,无需依赖中央服务器(如 SVN)。支持离线操作(提交、查看历史、创建分支等)。 高效的分支管理 创建和切换分支速度快(几乎是瞬间完成&#x…...
Ubuntu22.04安装数据
数据库安装步骤: sudo apt-get update sudo apt install mysql-server mysql-client sudo systemctl start mysql sudo systemctl status mysql (1)在命令行登录 MySQL 数据库,并使用 mysql 数据库 (必须使用这个…...
2025 ubuntu24系统宿主机上在线安装mysql数据库完整演示
说明:这是ubuntu24系统和安装后mysql的版本 rootmaster:/home/ubuntu# cat /etc/os-release PRETTY_NAME"Ubuntu 24.04.2 LTS" NAME"Ubuntu" VERSION_ID"24.04" VERSION"24.04.2 LTS (Noble Numbat)" VERSION_CODENAMEnob…...
STM32之I2C硬件外设
注意:硬件I2C的引脚是固定的 SDA和SCL都是复用到外部引脚。 SDA发送时数据寄存器的数据在数据移位寄存器空闲的状态下进入数据移位寄存器,此时会置状态寄存器的TXE为1,表示发送寄存器为空,然后往数据控制寄存器中一位一位的移送数…...
windows版本的时序数据库TDengine安装以及可视化工具
了解时序数据库TDengine,可以点击官方文档进行详细查阅 安装步骤 首先找到自己需要下载的版本,这边我暂时只写windows版本的安装 首先我们需要点开官网,找到发布历史,目前TDengine的windows版本只更新到3.0.7.1,我们…...
【AI】单台10卡4090 openEuler服务器离线部署kasm workspace 提供简单的GPU云服务 虚拟化桌面
下载网址 Downloads | Kasm Workspaces 文件连接 wget https://kasm-static-content.s3.amazonaws.com/kasm_release_plugin_images_amd64_1.16.1.98d6fa.tar.gz wget https://kasm-static-content.s3.amazonaws.com/kasm_release_1.16.1.98d6fa.tar.gz wget https://kasm-st…...
NetAssist 5.0.14网络助手基础使用及自动应答使用方案
以下是NetAssist v5.0.14自动应答功能的详细使用步骤: 一、基础准备: 工具下载网址页面:https://www.cmsoft.cn/resource/102.html 下载安装好后,根据需要可以创建多个server,双击程序图标运行即可,下面…...
《深度解析DeepSeek-M8:量子经典融合,重塑计算能效格局》
在科技飞速发展的今天,量子计算与经典算法的融合成为了前沿领域的焦点。DeepSeek-M8的“量子神经网络混合架构”,宛如一把钥匙,开启了经典算法与量子计算协同推理的全新大门,为诸多复杂问题的解决提供了前所未有的思路。 量子计算…...
力扣1251年
正确写法: select p.product_id, ifnull(round(sum(units*price)/sum(units),2),0) average_price from prices p left join unitssold u on u.product_idp.product_id and u.purchase_date between start_date and end_date group by p.product_id; 错误写法&a…...
【写作模板】JosieBook的写作模板
文章目录 ⭐前言⭐一、设计模式怎样解决设计问题?🌟1、寻找合适的对象✨(1)✨(2)✨(3) 🌟2、决定对象的粒度🌟3、指定对象接口🌟4、描述对象的实现🌟5、运用复用机制🌟6、关联运行时和编译时的结…...
47.HarmonyOS NEXT 登录模块开发教程(二):一键登录页面实现
温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦! HarmonyOS NEXT 登录模块开发教程(二):一键登录页面实现 文章目录 HarmonyOS NEXT 登录模块开发教程࿰…...
5.1 程序调试
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的 本节中为了演示方便,使用的代码如下: 【例 5.1】【项目:code5-001】程序的调试。 static void Ma…...
Cursor初体验:excel转成CANoe的vsysvar文件
今天公司大佬先锋们给培训了cursor的使用,还给注册了官方账号!跃跃欲试,但是测试任务好重,结合第三方工具开发也是没有头绪。 但巧的是,刚好下午有同事有个需求,想要把一个几千行的excel转成canoe的系统变…...
vue3-element-admin 前后端本地启动联调
一、后端环境准备 1.1、下载地址 gitee 下载地址 1.2、环境要求 JDK 17 1.3、项目启动 克隆项目 git clone https://gitee.com/youlaiorg/youlai-boot.git数据库初始化 执行 youlai_boot.sql 脚本完成数据库创建、表结构和基础数据的初始化。 修改配置 application-dev.y…...
emacs使用mongosh的方便工具发布
github项目地址: GitHub - csfreebird/emacs_mongosh: 在emacs中使用mongosh快速登录mongodb数据库 * 用途 在emacs中使用mongosh快速登录mongodb数据库, 操作方法: M-x mongosh, 输入数据库名称,然后就可以自动登录,前提是你已经配置好了…...
《MySQL数据库从零搭建到高效管理|库的基本操作》
目录 一、数据库的操作 1.1 展示数据库 1.2 创建数据库 1.3 使用数据库 1.4 查看当前数据库 1.5 删除数据库 1.6 小结 二、常用数据类型 2.1 数值类型 2.2 字符串类型 2.3 日期类型 一、数据库的操作 打开MySQL命令行客户端,安装完MySQL后会有两个客户端…...
Linux Shell 脚本编程极简入门指南
一、学习前提准备 ✅ 环境要求: Linux系统(Ubuntu/CentOS等)或 WSL (Windows用户) 任意文本编辑器(推荐VSCode/Vim) 基础命令行操作能力 🔍 验证环境: # 查看系统默认Shell echo $SHELL #…...
多视图几何--相机标定--从0-1理解张正友标定法
1基本原理 1.1 单应性矩阵(Homography)的建立 相机模型:世界坐标系下棋盘格平面(Z0)到图像平面的投影关系为: s [ u v 1 ] K [ r 1 r 2 t ] [ X Y 1 ] s \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} K…...
