告别手动映射:在 Spring Boot 3 中优雅集成 MapStruct
在日常的后端开发中,我们经常需要在不同的对象之间进行数据转换,例如将数据库实体(Entity)转换为数据传输对象(DTO)发送给前端,或者将接收到的 DTO 转换为实体进行业务处理或持久化。手动进行这种对象属性的拷贝工作不仅枯燥乏味,而且容易出错,特别是在对象属性较多时。
MapStruct 是一个 Java 注解处理器,它可以极大地简化这一过程。它通过在编译时生成高性能、类型安全的映射代码来解决对象映射的痛点。与一些基于反射的映射框架(如 ModelMapper、Dozer)不同,MapStruct 生成的代码是普通的 Java 方法调用,因此具有更好的性能和编译时检查,能够提前发现潜在的映射错误。
本文将详细介绍如何在最新的 Spring Boot 3 项目中集成和使用 MapStruct。
为什么选择 MapStruct?
在深入集成之前,我们先快速回顾一下 MapStruct 的主要优势:
- 编译时生成代码: 这是 MapStruct 最核心的特点。它不是在运行时通过反射进行属性查找和复制,而是在编译阶段根据你定义的接口生成具体的实现类。这意味着:
- 高性能: 生成的代码是直接的方法调用,没有反射带来的开销。
- 类型安全: 编译时就能检查映射是否合法,避免运行时错误。
- 易于调试: 你可以看到生成的代码,理解映射过程。
- 减少样板代码: 无需手动编写大量的
getter
和setter
调用来复制属性。 - Spring 集成: MapStruct 可以很容易地生成 Spring Bean,无缝集成到 Spring IoC 容器中。
- 灵活: 支持复杂的映射场景,如嵌套对象、列表、自定义转换逻辑、条件映射等。
在 Spring Boot 3 项目中集成 MapStruct
Spring Boot 3 要求 Java 17 或更高版本。确保你的项目满足这个前提。
集成的步骤主要包括添加依赖、配置构建工具以及编写 Mapper 接口。
步骤 1: 添加 MapStruct 依赖
在你的 Spring Boot 项目的构建文件中,你需要引入 MapStruct 的核心库和注解处理器。
-
Maven (
pom.xml
)<properties><org.mapstruct.version>1.5.5.Final</org.mapstruct.version> <!-- 确保使用最新的稳定版本 --><maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version> <!-- 确保编译器插件版本与你的JDK兼容且支持注解处理 --> </properties><dependencies><!-- MapStruct Core --><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>${org.mapstruct.version}</version></dependency><!-- 其他 Spring Boot Dependencies... --> </dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>${maven-compiler-plugin.version}</version><configuration><source>17</source> <!-- 与你的项目JDK版本一致 --><target>17</target> <!-- 与你的项目JDK版本一致 --><annotationProcessorPaths><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${org.mapstruct.version}</version></path><!-- 如果你使用了 Lombok,这里也需要添加 Lombok 的注解处理器 --><!-- MapStruct 与 Lombok 的集成非常常见 --><!--<path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></path><path><groupId>org.projectlombok</groupId><artifactId>lombok-mapstruct-binding</artifactId><version>0.2.0</version> // 这是一个辅助库,帮助 MapStruct 识别 Lombok 生成的方法</path>--></annotationProcessorPaths><!-- 推荐配置: 设置 MapStruct 的组件模型为 spring --><compilerArgs><compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg></compilerArgs></configuration></plugin></plugins> </build>
-
Gradle (
build.gradle
- Groovy DSL)plugins {id 'java'id 'org.springframework.boot' version '3.x.x' // 使用你的 Spring Boot 版本id 'io.spring.dependency-management' version '1.1.x' // 使用你的 Spring Dependency Management 版本 }java {sourceCompatibility = JavaVersion.VERSION_17 // 确保与你的项目JDK版本一致 }repositories {mavenCentral() }ext {mapstructVersion = "1.5.5.Final" // 确保使用最新的稳定版本// lombokVersion = "x.x.x" // 如果使用 Lombok// lombokMapstructBindingVersion = "0.2.0" // 如果使用 Lombok }dependencies {implementation "org.mapstruct:mapstruct:${mapstructVersion}"// 注解处理器依赖 - 注意 scopeannotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"// 如果使用 Lombok// compileOnly "org.projectlombok:lombok:${lombokVersion}"// annotationProcessor "org.projectlombok:lombok:${lombokVersion}"// annotationProcessor "org.projectlombok:lombok-mapstruct-binding:${lombokMapstructBindingVersion}"// 其他 Spring Boot Dependencies... }tasks.withType(JavaCompile) {options.encoding = 'UTF-8'// 推荐配置: 设置 MapStruct 的组件模型为 springoptions.compilerArgs += ['-Amapstruct.defaultComponentModel=spring'] }
-
Gradle (
build.gradle.kts
- Kotlin DSL)plugins {javaid("org.springframework.boot") version "3.x.x" // 使用你的 Spring Boot 版本id("io.spring.dependency-management") version "1.1.x" // 使用你的 Spring Dependency Management 版本 }java {sourceCompatibility = JavaVersion.VERSION_17 // 确保与你的项目JDK版本一致 }repositories {mavenCentral() }val mapstructVersion = "1.5.5.Final" // 确保使用最新的稳定版本 // val lombokVersion = "x.x.x" // 如果使用 Lombok // val lombokMapstructBindingVersion = "0.2.0" // 如果使用 Lombokdependencies {implementation("org.mapstruct:mapstruct:$mapstructVersion")// 注解处理器依赖 - 注意 scopeannotationProcessor("org.mapstruct:mapstruct-processor:$mapstructVersion")// 如果使用 Lombok// compileOnly("org.projectlombok:lombok:$lombokVersion")// annotationProcessor("org.projectlombok:lombok:$lombokVersion")// annotationProcessor("org.projectlombok:lombok-mapstruct-binding:$lombokMapstructBindingVersion")// 其他 Spring Boot Dependencies... }tasks.withType<JavaCompile> {options.encoding = "UTF-8"// 推荐配置: 设置 MapStruct 的组件模型为 springoptions.compilerArgs.add("-Amapstruct.defaultComponentModel=spring") }
关键点说明:
mapstruct-processor
: 这是 MapStruct 的核心,它是一个注解处理器。- 构建工具配置:
maven-compiler-plugin
或 Gradle 的annotationProcessor
必须配置正确,指向mapstruct-processor
依赖。这样,在编译*.java
文件时,编译器会调用 MapStruct 处理器来生成 Mapper 实现类。 - JDK 版本: 确保你的
source
和target
JDK 版本与 Spring Boot 3 的要求一致(Java 17+)。 - Lombok 集成: 如果你的实体或 DTO 使用了 Lombok 生成
getter
/setter
,强烈建议添加lombok-mapstruct-binding
并确保 Lombok 的注解处理器也在列表中。处理器的顺序有时很重要,通常 Lombok 在前。 -Amapstruct.defaultComponentModel=spring
: 这个编译器参数告诉 MapStruct 默认使用spring
作为生成的组件模型。这意味着 MapStruct 会为生成的 Mapper 实现类添加@Component
(或 Spring 可识别的其他注解),从而让 Spring 能够扫描到并将其注册为 Bean,无需你在每个@Mapper
注解中重复指定componentModel = "spring"
。
步骤 2: 定义你的实体类和 DTO
假设我们有以下简单的实体和 DTO:
// src/main/java/.../domain/Product.java
public class Product {private Long id;private String name;private String description;private double price;// 省略 Getters 和 Setters (如果使用 Lombok 则无需手动编写)// public Long getId() { ... }// public void setId(Long id) { ... }// ...
}// src/main/java/.../dto/ProductDto.java
public class ProductDto {private Long productId;private String productName;private String details;private double itemPrice;// 省略 Getters 和 Setters (如果使用 Lombok 则无需手动编写)// public Long getProductId() { ... }// public void setProductId(Long productId) { ... }// ...
}
注意 Product
和 ProductDto
的属性名称不完全匹配。
步骤 3: 创建 Mapper 接口
创建一个 Java 接口,并使用 @Mapper
注解标记它。
// src/main/java/.../mapper/ProductMapper.java
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
// import org.mapstruct.factory.Mappers; // 当使用 componentModel="spring" 时,通常无需手动获取实例@Mapper(componentModel = "spring") // 关键:告诉 MapStruct 生成 Spring Bean
public interface ProductMapper {// 映射 Product -> ProductDto// 如果属性名不同,使用 @Mapping 指定源属性和目标属性@Mapping(source = "id", target = "productId")@Mapping(source = "name", target = "productName")@Mapping(source = "description", target = "details")@Mapping(source = "price", target = "itemPrice")ProductDto toDto(Product product);// 映射 ProductDto -> Product// 注意,如果需要双向映射,需要单独定义方法@Mapping(source = "productId", target = "id")@Mapping(source = "productName", target = "name")@Mapping(source = "details", target = "description")@Mapping(source = "itemPrice", target = "price")Product toEntity(ProductDto productDto);// 你也可以定义其他映射方法,例如 List<Product> -> List<ProductDto>// List<ProductDto> toDtoList(List<Product> products);// MapStruct 会自动处理集合的映射
}
@Mapper(componentModel = "spring")
的作用:
这个属性告诉 MapStruct 生成的实现类应该符合 Spring 的组件模型。这意味着生成的实现类(例如 ProductMapperImpl.java
)会自动带上 Spring 的 @Component
注解(或者如果配置了其他组件扫描规则,可能是 @Service
, @Repository
等,但默认是 @Component
),从而使得 Spring 能够扫描到它,并将其作为一个 Bean 放入应用程序上下文中。这样,你就可以在其他 Spring 管理的 Bean 中通过 @Autowired
或构造函数注入来使用它了。
@Mapping
的作用:
当源对象和目标对象的属性名称不一致时,你需要使用 @Mapping
注解来明确指定映射关系。source
指定源对象的属性名,target
指定目标对象的属性名。如果属性名相同,MapStruct 会默认进行映射,无需 @Mapping
。
步骤 4: 在 Spring 组件中使用 Mapper
由于你在 Mapper 接口上设置了 componentModel = "spring"
,MapStruct 生成的实现类会自动成为 Spring Bean。你可以在 Service、Controller 或其他组件中像注入普通 Bean 一样注入和使用它。
// src/main/java/.../service/ProductService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class ProductService {private final ProductMapper productMapper;// 假设你有一个 Repository 来获取数据// private final ProductRepository productRepository;@Autowired // 推荐使用构造函数注入public ProductService(ProductMapper productMapper /*, ProductRepository productRepository */) {this.productMapper = productMapper;// this.productRepository = productRepository;}public ProductDto getProductDto(Long id) {// 模拟从数据库获取实体Product product = findProductEntityById(id); // 这是一个假设的方法if (product != null) {// 使用 MapStruct 生成的 Mapper 将实体转换为 DTOreturn productMapper.toDto(product);}return null; // 或抛出异常}public Product createProduct(ProductDto productDto) {// 使用 MapStruct 生成的 Mapper 将 DTO 转换为实体Product product = productMapper.toEntity(productDto);// 可以在这里进行进一步的业务处理或调用 Repository 保存实体// productRepository.save(product); // 假设保存操作return product; // 返回创建的实体}// 模拟获取 Product 实体的方法private Product findProductEntityById(Long id) {// 实际应用中会调用 Repositoryif (id == 1L) {Product p = new Product();p.setId(1L);p.setName("Sample Product");p.setDescription("This is a detailed description.");p.setPrice(199.99);return p;}return null;}
}
步骤 5: 构建项目
执行构建命令(如 mvn clean install
或 gradle build
)。构建过程中,MapStruct 的注解处理器会被触发,生成 Mapper 接口的实现类。这些生成的类通常位于项目的 target/generated-sources/annotations
(Maven) 或 build/generated/sources/annotationProcessor/java/main
(Gradle) 目录下。
启动你的 Spring Boot 应用程序,Spring 会扫描并注册生成的 Mapper 实现类,你就可以在运行时正常使用了。
进阶用法和注意事项
- 集合映射: MapStruct 可以自动处理集合类型的映射,如
List<Product> toProductDtoList(List<Product> products);
。 - 嵌套对象映射: 如果你的对象包含其他复杂对象,MapStruct 默认会尝试递归映射这些嵌套对象,前提是你为这些嵌套对象也提供了相应的 Mapper。
- 自定义映射逻辑: 对于复杂的转换,可以使用
@BeforeMapping
,@AfterMapping
注解在映射前或后执行自定义代码,或者定义自定义的方法并在@Mapping
中引用。 - 默认值和表达式: 可以使用
@Mapping(target = "someField", defaultValue = "N/A")
或@Mapping(target = "calculatedField", expression = "java(source.getPropertyA() + source.getPropertyB())")
来设置默认值或使用表达式进行计算。 - 忽略字段: 使用
@Mapping(target = "fieldToIgnore", ignore = true)
可以忽略特定字段的映射。 - 更新现有对象: 除了创建新对象,MapStruct 也可以将源对象的属性映射到已存在的目标对象上,使用
@MappingTarget
注解:void updateProduct(@MappingTarget Product product, ProductDto productDto);
- 配置未映射策略: 可以通过
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
等配置来控制当存在未映射的目标属性时的行为(报告警告、忽略或报错)。
总结
在 Spring Boot 3 项目中集成 MapStruct 是一个非常推荐实践。它利用注解处理器在编译时生成高效、类型安全的映射代码,显著减少了手动编写映射代码的工作量和潜在错误。通过简单的依赖添加、构建工具配置以及 @Mapper
注解和 componentModel = "spring"
的使用,MapStruct 可以无缝地集成到 Spring IoC 容器中,让你像使用其他 Spring Bean 一样方便地进行对象映射。
如果你还在手动进行对象拷贝,或者使用基于反射的映射工具,不妨试试 MapStruct,相信它能为你的开发带来效率和可靠性的提升。
相关文章:
告别手动映射:在 Spring Boot 3 中优雅集成 MapStruct
在日常的后端开发中,我们经常需要在不同的对象之间进行数据转换,例如将数据库实体(Entity)转换为数据传输对象(DTO)发送给前端,或者将接收到的 DTO 转换为实体进行业务处理或持久化。手动进行这…...
JavaScript学习教程,从入门到精通,Ajax数据交换格式与跨域处理(26)
Ajax数据交换格式与跨域处理 一、Ajax数据交换格式 1. XML (eXtensible Markup Language) XML是一种标记语言,类似于HTML但更加灵活,允许用户自定义标签。 特点: 可扩展性强结构清晰数据与表现分离文件体积相对较大 示例代码࿱…...
抖音IP属地跟无线网有关系吗?一文解析
在抖音等社交平台上,IP属地显示功能让许多用户感到好奇——为什么自己的位置信息有时准确,有时却显示在其他城市?这时,用户会疑惑:抖音IP属地跟无线网有关系吗?本文将详细解析IP属地和无线网的概念…...
RDK X3新玩法:超沉浸下棋机器人开发日记
一、项目介绍 产品中文名:超沉浸式智能移动下棋机器人 产品英文名:Hackathon-TTT 产品概念:本项目研发的下棋机器人,是一款能自主移动、具备语音交互并能和玩家在真实的棋盘上进行“人机博弈”的移动下棋平台,能够带给…...
Trae 实测:AI 助力前端开发,替代工具还远吗?
Trae 实测:AI 助力前端开发,替代工具还远吗? 字节上线了一款 AI 新产品,名叫 Trae 。这是一款 IDE 工具,中文意思是「集成开发环境」,做技术的读者对此应该很熟悉。简单理解,就是程序员用来写代…...
SpringCloud基于Eureka和Feign实现一个微服务系统
Spring Cloud 是基于 Spring Boot 的 微服务开发全栈解决方案,通过集成多种开源组件,提供分布式系统构建所需的服务治理、配置管理、容错机制等核心能力,简化微服务架构的复杂性。其核心目标是实现服务间的高效协同与弹性伸缩,支撑企业级云原生应用开发。Spring Clou…...
nacos设置权重进行负载均衡不生效
nacos设置权重进行负载均衡不生效,必须在启动类下加上这个bean Beanpublic IRule nacosRule(){return new NacosRule();}如下图所示...
Flowable7.x学习笔记(十四)查看部署流程Bpmn2.0-xml
前言 Flowable 在其前端 Modeler 中,采用 BPMN 2.0 标准将流程中的任务、网关、事件等元素以 XML 形式存储,并附带图形互换(Diagram Interchange,DI)数据,以保证在前端与后端都能精准重建可视化流程图。 生…...
大模型应用中Agent2Agent(A2A)的应用场景,以及A2A与MCP的区别和适用场景
大家好,我是微学AI,今天给大家介绍一下大模型应用中Agent2Agent(A2A)的应用场景,以及A2A与MCP的区别和适用场景。 文章目录 一、引言二、Agent2Agent(A2A)协议原理2.1 核心架构2.2 基础框架与依…...
Windows server:
企鹅裙:429603659 域搭建 (细节上的问题) 1.将IP地址修改为静态IP,搭建完后设置DNS为本身(在搭建完域服务器后设置DNS) 2.配置之前需将计算机名更改为后面题目中所要求的. 3.一些版本之中比如Windows Server2012之中搭建域之后重启会显示…...
Python 3.14:探索新版本的魅力与革新
在Python编程语言的不断演进中,Python 3.14作为又一重要里程碑,承载着开发者们的期待与热情,悄然走进了我们的视野。尽管在撰写本文时,Python 3.14可能尚未正式成为主流版本(注:实际发布情况需根据最新信息…...
LabVIEW基于VI Server的控件引用操作
本 VI 通过展示控件引用(Control References)的使用,借助 VI Server 实现对前面板对象的编程操作。 详细说明 隐式属性节点(Implicitly Linked Property Node):通过右键单击控件(或其控件终…...
【不同名字的yolo的yaml文件名是什么意思】
以下是这些 YOLO 系列配置文件的详细解析,按版本和功能分类说明: 一、YOLOv3 系列 文件名核心特性适用场景yolov3.yaml原始 YOLOv3 结构,3 尺度预测(13x13,26x26,52x52)通用目标检测yolov3-spp.yaml增加 SPPÿ…...
《100天精通Python——基础篇 2025 第3天:变量与数据类型全面解析,掌握Python核心语法》
目录 一、Python变量的定义和使用二、Python整数类型(int)详解三、Python小数/浮点数(float)类型详解四、Python复数类型(complex)详解---了解五、Python字符串详解(包含长字符串和原始字符串)5.1 处理字符串中的引号5.2 字符串的…...
精益数据分析(24/126):聚焦第一关键指标,驱动创业成功
精益数据分析(24/126):聚焦第一关键指标,驱动创业成功 在创业和数据分析的探索之旅中,我们都在不断寻找能够助力成功的关键因素。今天,我依旧带着与大家共同进步的初心,深入解读《精益数据分析…...
【刷题Day26】Linux命令、分段分页和中断(浅)
说下你常用的 Linux 命令? 文件与目录操作: ls:列出当前目录的文件和子目录,常用参数如-l(详细信息)、-a(包括隐藏文件)cd:切换目录,用于在文件系统中导航m…...
互联网实验室的质量管控痛点 质检LIMS系统在互联网企业的应用
在互联网行业流量红利消退与用户体验至上的时代背景下,产品迭代速度与质量稳定性成为企业核心竞争力的分水岭。传统测试实验室依赖人工操作、碎片化工具与线下沟通的管理模式,已难以应对敏捷开发、多端适配、数据安全等复合型挑战。 一、互联网实验室的…...
VScode远程连接服务器(免密登录)
一、本机生成密钥对 本地终端输入ssh-keygen,生成公钥(id_rsa.pub)和私钥(id_rsa) 二、在远程服务器根目录的.ssh文件夹的authorized_keys中输入id_rsa的内容 三、修改vscode的config文件.ssh/config,加…...
【Go语言】RPC 使用指南(初学者版)
RPC(Remote Procedure Call,远程过程调用)是一种计算机通信协议,允许程序调用另一台计算机上的子程序,就像调用本地程序一样。Go 语言内置了 RPC 支持,下面我会详细介绍如何使用。 一、基本概念 在 Go 中&…...
安卓四大组件之ContentProvider
目录 实现步骤 代码分析 onCreate insert query ContextHolder Cursor 作用与用法 基本步骤: 可能的面试题:为什么使用Cursor? 为什么使用Cursor 使用Cursor的好处 静态内部类实现单例模式 AnndroidManifest.xml配置信息 注释的…...
C#中实现XML解析器
XML(可扩展标记语言)是一种广泛用于存储和传输数据的格式,因其具有良好的可读性和可扩展性,在许多领域都有应用。 实现思路: 词法分析 词法分析的目的是将输入的 XML 字符串分解为一个个的词法单元,例如…...
神经符号混合与跨模态对齐:Manus AI如何重构多语言手写识别的技术边界
在全球化数字浪潮下,手写识别技术长期面临"巴别塔困境"——人类书写系统的多样性(从中文象形文字到阿拉伯语连写体)与个体书写风格的随机性,构成了人工智能难以逾越的双重壁垒。传统OCR技术在处理多语言手写场景时,准确率往往不足70%,特别是在医疗处方、古代文…...
TestBrain开源程序是一款集使用AI(如deepseek)大模型自动生成测试用例、和测试用例评审、RAG知识库管理的web平台系统
一、软件介绍 文末提供程序和源码下载 TestBrain开源程序是一款集使用AI(如deepseek)大模型自动生成测试用例、和测试用例评审、RAG知识库管理的web平台系统一个基于LLM的智能测试用例生成平台(功能慢慢丰富中,未来可能将测试相关的所有活动集成到一起),…...
软件工程效率优化:一个分层解耦与熵减驱动的系统框架
软件工程效率优化:一个分层解耦与熵减驱动的系统框架** 摘要 (Abstract) 本报告构建了一个全面、深入、分层的软件工程效率优化框架,旨在超越简单的技术罗列,从根本的价值驱动和熵减原理出发,系统性地探讨提升效率的策略与实践。…...
【金仓数据库征文】- 深耕国产数据库优化,筑牢用户体验新高度
目录 引言 一、性能优化:突破数据处理极限,提升运行效率 1.1 智能查询优化器:精准优化数据检索路径 1.2 并行处理技术:充分释放多核计算潜力 1.3 智能缓存机制:加速数据访问速度 二、稳定性提升:筑牢…...
前端面试常见部分问题,及高阶部分问题
面试中也极有可能让你徒手写代码,无聊的面试问题o( ̄︶ ̄)o 一、HTML/CSS 基础与进阶 常见问题 什么是语义化标签?有哪些常用语义化标签? 答案:语义化标签是指具有明确含义的 HTML 标签,如 <header>、<footer>、<article>、<section> 等。它们有…...
使用 AutoGen 与 Elasticsearch
作者:来自 Elastic Jeffrey Rengifo 学习如何使用 AutoGen 为你的 agent 创建一个 Elasticsearch 工具。 Elasticsearch 拥有与行业领先的生成式 AI 工具和提供商的原生集成。查看我们的网络研讨会,了解如何超越 RAG 基础,或使用 Elastic 向量…...
kafka与flume的整合、spark-streaming
kafka与flume的整合 前期配置完毕,开启集群 需求1: 利用flume监控某目录中新生成的文件,将监控到的变更数据发送给kafka,kafka将收到的数据打印到控制台(三个node01中运行) 1.在kafka中建立topic kafka…...
高级电影感户外街拍人像摄影后期Lr调色教程,手机滤镜PS+Lightroom预设下载!
调色介绍 高级电影感户外街拍人像摄影后期 Lr 调色,是运用 Adobe Lightroom 软件,对户外街拍的人像照片进行后期处理,以塑造出具有电影质感的独特视觉效果。此调色过程借助 Lr 丰富的工具与功能,从色彩、光影、对比度等多维度着手…...
react 常用钩子 hooks 总结
文章目录 React钩子概念图状态管理钩子 state management副作用钩子 effect hooks引用钩子 Ref hooks上下文钩子其他钩子过渡钩子 处理过渡效果性能优化钩子 performance hooksReact 19 新钩子 React钩子概念图 状态管理钩子 state management useState useReducer useSyncEx…...
2025 年导游证报考条件新政策解读与应对策略
2025 年导游证报考政策有了不少新变化,这些变化会对报考者产生哪些影响?我们又该如何应对?下面就为大家详细解读新政策,并提供实用的应对策略。 最引人注目的变化当属中职旅游类专业学生的报考政策。以往,中专学历报考…...
重置 Git 项目并清除提交历史
在某些情况下,你可能需要完全重置一个 Git 项目,清除所有提交历史,然后将当前代码作为全新的初始提交。本文将详细介绍这个过程的操作步骤和注意事项。 重要警告 ⚠️ 注意:以下操作将永久删除项目的所有提交历史、分支和标签。…...
GitHub Copilot (Gen-AI) 很有用,但不是很好
摘要:以下是我在过去三个月中在实际 、 开发中使用 GitHub Copilot Pro 后的想法。由于技术发展迅速,值得注意的是,这些印象是基于我截至 2025 年 3 月的经验。 1 免费试用促使我订阅 GitHub Copilot Pro 我以前读过有关 AI 代码生成器的文…...
K8S Service 原理、案例
一、理论介绍 1.1、3W 法则 1、是什么? Service 是一种为一组功能相同的 pod 提供单一不变的接入点的资源。当 Service 存在时,它的IP地址和端口不会改变。客户端通过IP地址和端口号与 Service 建立连接,这些连接会被路由到提供该 Service 的…...
Base64编码原理:二进制数据与文本的转换技术
🔄 Base64编码原理:二进制数据与文本的转换技术 开发者的数据编码困境 作为开发者,你是否曾遇到这些与Base64相关的挑战: 📊 需要在JSON中传输二进制数据,但不确定如何正确编码🖼️ 想要在HT…...
系统设计(1)—前端—CDN—Nginx—服务集群
简介: 本指南旨涵盖前端、CDN、Nginx 负载均衡、服务集群、Redis 缓存、消息队列、数据库设计、熔断限流降级以及系统优化等模块的核心要点。我们将介绍各模块常见的设计方案与优化策略,并结合电商秒杀、SaaS CRM 系统、支付系统等高并发场景讨论实践技巧…...
Easysearch 基础运维扫盲指南:从 HTTP 到 HTTPS、认证与安全访问全解析
Easysearch 基础运维扫盲指南:从 HTTP 到 HTTPS、认证与安全访问全解析 众所周知,原生 Elasticsearch 默认开启的是 HTTP 明文接口,并且不开启任何身份认证或传输加密。若想启用 TLS/SSL 加密及账号密码验证,通常需要配置繁琐的安…...
在Android中如何使用Protobuf上传协议
在 Android 中使用 Protobuf(Protocol Buffers)主要分为以下几个步骤: ✅ 1. 添加 Protobuf 插件和依赖 在项目的 build.gradle(Project 级)文件中添加 Google 的 Maven 仓库(通常默认已有)&am…...
【数据可视化艺术·应用篇】三维管线分析如何重构城市“生命线“管理?
在智慧城市、能源管理、工业4.0等领域的快速发展中,地下管线、工业管道、电力通信网络等“城市血管”的复杂性呈指数级增长。传统二维管理模式已难以应对跨层级、多维度、动态变化的管线管理需求。三维管线分析技术应运而生,成为破解这一难题的核心工具。…...
2025年的营销趋势-矩阵IP
从 2025 年的营销生态来看,创始人 IP 与智能矩阵的结合确实呈现出颠覆性趋势,这一现象背后隐藏着三个值得深度解析的商业逻辑: 一、创始人 IP 的本质是 "信任货币" 的数字化迁徙 当新能源汽车市场陷入参数混战,雷军将个…...
对接金蝶获取接口授权代码
接口服务信息 using RestSharp; using System.Configuration; using System.Threading.Tasks; public class KingdeeAccessTokenService { private readonly RestClient _client; private readonly KingdeeApiConfig _config; public KingdeeAccessTokenService() …...
探秘 3D 展厅之卓越优势,解锁沉浸式体验新境界
(一)打破时空枷锁,全球触达 3D 展厅的首要优势便是打破了时空限制。在传统展厅中,观众需要亲临现场,且必须在展厅开放的特定时间内参观。而 3D 展厅依托互联网,让观众无论身处世界哪个角落,只…...
prometheus通过Endpoints自定义grafana的dashboard模块
1、prometheus自定义的dashboard模块 文件路径/etc/prometheus/config_out/prometheus-env.yaml - job_name: serviceMonitor/monitoring/pfil/0honor_labels: falsekubernetes_sd_configs:- role: endpointsnamespaces:names:- monitoringrelabel_configs:- source_labels:- …...
java排序算法-计数排序
计数排序的思路 计数排序的基本思路: 确定取值范围: 遍历整个待排序的数组,确定数组中元素的取值范围,找到最小值和最大值。创建计数数组: 创建一个计数数组,其长度为取值范围的大小,用于统计…...
力扣-hot100(滑动窗口最大值)
239. 滑动窗口最大值 困难 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1: 输入:nums […...
每日c/c++题 备战蓝桥杯(P1049 [NOIP 2001 普及组] 装箱问题)
洛谷P1049 装箱问题题解:动态规划在背包问题中的经典应用 题目描述 P1049 装箱问题是一道典型的0-1背包问题变种。题目要求在给定箱子容量V和n个物品体积的情况下,选择若干物品装入箱子,使得箱子的剩余空间最小。最终输出这个最小剩余空间的…...
【尚硅谷Redis6】自用学习笔记
Redis介绍 Redis是单线程 多路IO复用技术(类似黄牛买票) 默认有16个库,用select进行切换 默认端口号为6379 Memcached:多线程 锁(数据类型单一,不支持持久化) 五大常用数据类型 Redis key …...
产品更新丨谷云科技ETLCloud V3.9.2版本发布
谷云科技 ETLCloud 集成平台迎来了每月一次的功能迭代,本月发布版本号为 3.9.2 版本,为用户带来了新的功能、优化改进以及问题修复,以下是详细介绍: 新增组件 本次更新新增了众多实用组件,涵盖了京东和 Shopify 相关…...
Promise并发控制与HTTP请求优化
Promise并发方法对比 #mermaid-svg-tnmGzOkgNUCrbvfI {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-tnmGzOkgNUCrbvfI .error-icon{fill:#552222;}#mermaid-svg-tnmGzOkgNUCrbvfI .error-text{fill:#552222;stroke…...
G1垃圾回收器中YoungGC和MixedGC的区别
在 G1 垃圾回收器中,Mixed GC 和 Young GC 的区别主要体现在以下几个方面: 作用范围 Young GC:仅针对年轻代中的Region进行回收,包括 Eden 区和 Survivor 区的 Region。Mixed GC:会回收所有年轻代的 Region 以及部分…...