当前位置: 首页 > news >正文

MapStruct动态生成实现

MapStruct 笔记

  1. 什么是 MapStruct?
    MapStruct 是一个用于 Java 的代码生成器,它通过注解处理器在编译时生成实现类,用于对象之间的转换,特别是在数据传输对象(DTO)与实体之间的转换。它的主要优势在于性能高效、类型安全和易于维护。

  2. 主要特性
    编译时生成代码: 避免了运行时反射的开销。
    类型安全: 编译时检查类型,减少运行时错误。
    支持复杂映射: 可以处理嵌套对象和集合。
    自定义转换: 可以定义自定义方法来处理特殊的转换逻辑。
    简化代码: 减少手动编写转换代码的工作量。

  3. 使用步骤
    3.1 添加依赖
    对于 Maven 项目,在 pom.xml 中添加以下依赖:

<dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>1.4.2.Final</version> <!-- 请根据最新版本进行调整 -->
</dependency>
<dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.4.2.Final</version><scope>provided</scope>
</dependency>

对于 Gradle 项目,在 build.gradle 中添加:

implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'

3.2 创建数据模型
根据你提供的接口定义,定义实体类和相关的 DTO:


// 实体类
public class AssetsAcceptItemsDetail {private Long id;private String name;private String description;// Getters and Setters
}
// 保存视图对象
public class AssetsAcceptItemsDetailSaveVo {private Long id;private String name;private String description;// Getters and Setters
}
// 其他相关类
public class AssetsVoForAcceptattach {private String assetName;private String assetDescription;// Getters and Setters
}

3.3 创建 Mapper 接口
定义 Mapper 接口,使用 @Mapper 注解,映射不同的转换方法:


import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface AssetsAcceptItemsDetailCovert {AssetsAcceptItemsDetailCovert INSTANCE = Mappers.getMapper(AssetsAcceptItemsDetailCovert.class);AssetsAcceptItemsDetail clone(AssetsAcceptItemsDetail source);List<AssetsAcceptItemsDetail> clone(List<AssetsAcceptItemsDetail> sourceList);List<AssetsAcceptItemsDetail> saveVo2List(List<AssetsAcceptItemsDetailSaveVo> source);AssetsAcceptItemsDetail storeAssets2Model(AssetsVoForAcceptattach assetsVoForAcceptattach);
}

3.4 使用 Mapper
在你的服务或控制器中使用 Mapper:

public class AssetsService {private final AssetsAcceptItemsDetailCovert mapper = AssetsAcceptItemsDetailCovert.INSTANCE;public AssetsAcceptItemsDetail cloneDetail(AssetsAcceptItemsDetail detail) {return mapper.clone(detail);}public List<AssetsAcceptItemsDetail> cloneDetailList(List<AssetsAcceptItemsDetail> detailList) {return mapper.clone(detailList);}public List<AssetsAcceptItemsDetail> convertSaveVoList(List<AssetsAcceptItemsDetailSaveVo> saveVoList) {return mapper.saveVo2List(saveVoList);}public AssetsAcceptItemsDetail convertToModel(AssetsVoForAcceptattach assetsVo) {return mapper.storeAssets2Model(assetsVo);}
}

3.5 编译和生成代码
当你编译项目时,MapStruct 会自动生成实现类 AssetsAcceptItemsDetailCovertImpl,你可以在 target/generated-sources/annotations 目录下找到它。

  1. 复杂映射示例
    如果你的对象有嵌套属性,MapStruct 也可以处理。例如,假设你有以下类:
public class AssetsAcceptItemsDetail {private Long id;private String name;private String description;private List<Asset> assets; // 假设有一个资产列表// Getters and Set

在使用 MapStruct 进行对象映射时,确实有不同的方式来处理字段的映射。你提到的两种方式各有优缺点,下面我们来详细讨论一下。

  1. 使用 @Mapping 注解的方式
@Mapping(source = "name", target = "fullName")
@Mapping(source = "description", target = "details")
AssetsAcceptItemsDetailVo toVo(AssetsAcceptItemsDetail detail);

优点
明确性: 每个字段的映射关系都非常清晰,便于理解和维护。
灵活性: 可以针对每个字段定义不同的映射规则,适用于复杂的转换需求。
自定义映射: 可以为特定字段提供自定义的转换逻辑。
缺点
冗长: 当字段较多时,代码会变得冗长,尤其是当源对象和目标对象有很多字段时。
维护成本: 如果字段发生变化(如添加、删除或重命名),需要在多个地方更新映射。
2. 直接使用 Mappers.getMapper()

AssetsAcceptItemsDetailCovert INSTANCE = Mappers.getMapper(AssetsAcceptItemsDetailCovert.class);

优点
简单性: 如果源对象和目标对象的字段名称相同,则不需要显式地定义每个字段的映射,减少了代码量。
易于维护: 当字段名称一致时,添加或删除字段时不需要更改映射逻辑,MapStruct 会自动处理。
缺点
灵活性不足: 如果字段名称不一致,或者需要进行复杂的转换逻辑,就需要使用 @Mapping 注解,可能会导致代码的重复。
可读性: 对于复杂的对象,直接使用 Mappers.getMapper() 可能会让人不易理解映射关系。
3. 何时选择哪种方式
字段名称一致且简单的情况:
如果源对象和目标对象的字段名称和类型完全一致,并且没有复杂的转换逻辑,使用 Mappers.getMapper() 是一个很好的选择。这种方式简单明了,易于维护。
字段名称不一致或需要复杂逻辑的情况:
如果字段名称不一致,或者需要自定义转换逻辑,使用 @Mapping 注解的方式将更加清晰和灵活。虽然代码会更长,但能够提供更好的可读性和可维护性。
4. 示例
简单映射示例(字段名称一致)

@Mapper
public interface AssetsAcceptItemsDetailCovert {AssetsAcceptItemsDetailCovert INSTANCE = Mappers.getMapper(AssetsAcceptItemsDetailCovert.class);AssetsAcceptItemsDetailVo toVo(AssetsAcceptItemsDetail detail);
}

复杂映射示例(字段名称不一致)

@Mapper
public interface AssetsAcceptItemsDetailCovert {AssetsAcceptItemsDetailCovert INSTANCE = Mappers.getMapper(AssetsAcceptItemsDetailCovert.class);@Mapping(source = "name", target = "fullName")@Mapping(source = "description", target = "details")AssetsAcceptItemsDetailVo toVo(AssetsAcceptItemsDetail detail);
}
  1. 结论
    选择哪种方式取决于你的具体需求。如果你的对象映射比较简单且字段一致,使用 Mappers.getMapper() 是一个简洁的选择;如果字段不一致或者需要复杂的映射逻辑,使用 @Mapping 注解将更加灵活和可控。希望这些解释能帮助你更好地理解这两种方式的优缺点!如果你有更多问题,欢迎继续讨论。

MapStruct 笔记(修正版)

  1. 使用 @Mapping 注解
    @Mapping 注解用于明确指定源对象和目标对象之间字段的映射关系。它的主要作用是处理字段名称不一致的情况。

1.1 特性
明确性: 可以清晰地定义每个字段的映射关系。
灵活性: 可以为字段提供自定义的转换逻辑。
必要性: 如果源和目标对象的字段名称一致,则不需要使用 @Mapping 注解。
1.2 示例
场景: 假设你有以下两个类,它们的字段名称不同:

public class AssetsAcceptItemsDetail {private Long id;private String name;private String description;// Getters and Setters
}
public class AssetsAcceptItemsDetailVo {private Long id;private String fullName; // 与 name 不同private String details;   // 与 description 不同// Getters and Setters
}

Mapper 接口:

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper
public interface AssetsAcceptItemsDetailCovert {@Mapping(source = "name", target = "fullName")@Mapping(source = "description", target = "details")AssetsAcceptItemsDetailVo toVo(AssetsAcceptItemsDetail detail);AssetsAcceptItemsDetail toDetail(AssetsAcceptItemsDetailVo detailVo);
}

1.3 说明
在这个例子中,@Mapping 注解用于指明 name 字段对应 fullName 字段,description 字段对应 details 字段。
如果字段名称相同(如 id),则不需要使用 @Mapping 注解。
2. 使用 Mappers.getMapper() 的方式
当源对象和目标对象的字段名称和类型一致时,可以直接使用 Mappers.getMapper() 方式来简化映射。

2.1 特性
简洁性: 如果字段名称和类型完全一致,代码会更加简洁。
自动处理: MapStruct 会自动处理字段名称一致的情况,无需显式定义。
2.2 示例
场景: 假设你有以下两个类,它们的字段名称和类型一致:

public class User {private Long id;private String name;private String email;// Getters and Setters
}
public class UserDTO {private Long id;private String name; // 与 User 的 name 相同private String email; // 与 User 的 email 相同// Getters and Setters
}

Mapper 接口:

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface UserMapper {UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);UserDTO userToUser DTO(User user);User userDTOToUser (UserDTO userDTO);
}

2.3 说明
在这个例子中,User 和 User DTO 的字段名称和类型一致,因此不需要使用 @Mapping 注解。
通过 Mappers.getMapper(UserMapper.class) 获取 User Mapper 的实例,自动处理字段映射。
2.4 使用 Mapper
在服务或控制器中使用 Mapper 实例:

public class UserService {public UserDTO convertToDTO(User user) {return UserMapper.INSTANCE.userToUser DTO(user);}public User convertToEntity(UserDTO userDTO) {return UserMapper.INSTANCE.userDTOToUser (userDTO);}
}
  1. 总结
    使用 @Mapping 注解的方式
    优点: 明确、灵活,适合字段名称不一致的情况。
    示例代码:
@Mapping(source = "name", target = "fullName")
@Mapping(source = "description", target = "details")
AssetsAcceptItemsDetailVo toVo(AssetsAcceptItemsDetail detail);

使用 Mappers.getMapper() 的方式
优点: 简洁、自动处理,适合字段名称一致的情况。
示例代码:

UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDTO userToUser DTO(User user);

结论
选择使用哪种方式取决于你的具体需求。如果你有很多字段需要映射,并且它们的名称和类型一致,使用 Mappers.getMapper() 是一个更简洁的选择;如果字段名称不一致或者需要复杂的映射逻辑,使用 @Mapping 注解将更加灵活和可控。


http://www.mrgr.cn/news/95979.html

相关文章:

  • 【AI】Orin Nano+ubuntu22.04上移植YoloV11,并使用DeepStream测试成功
  • mysql高级,mysql体系结构,mysql引擎,存储过程,索引,锁
  • (UI自动化测试web端)第二篇:元素定位的方法_css定位之ID选择器
  • uniapp动态循环表单校验失败:初始值校验
  • 解决Spring Cloud OpenFeign端点未暴露问题
  • Modbus RTU ---> Modbus TCP透传技术实现(Modbus透传、RS485透传、RTU透传)分站代码实现、协议转换器
  • 反序列化漏洞
  • Docker+Ollama+Xinference+RAGFlow+Dify部署及踩坑问题
  • msyql--基本操作之运维篇
  • 【JavaSE】抽象类和接口
  • uniapp页面列表,详情返回不刷新,新增或编辑后返回刷新
  • mysql中show命令的使用
  • NodeJs之fs模块
  • 【408--复习笔记】计算机组成原理
  • 【模型压缩+推理加速】知识蒸馏综述解读
  • 嵌入式硬件工程师从小白到入门-原理图(三)
  • ofd转pdf报错:org.ofdrw.reader.ZipUtil.unZipFileByApacheCommonCompress【已解决】
  • 语言模型理论基础-持续更新-思路清晰
  • Vue 2 探秘:visible 和 append-to-body 是谁的小秘密?
  • Brainstorm绘制功能连接图(matlab)