Chuyển tới nội dung chính

Chuyển đổi dữ liệu (MapStruct)

govex-cloud-mapstruct là thư viện annotation + runtime conversion cho các mapper MapStruct sinh tự động: khai báo mapper bằng @AutoMapper, @AutoMapMapper, @AutoEnumMapper và gọi chuyển đổi qua bean GConversionService. Thêm dependency khi service cần chuyển đổi entity ↔ DTO/VO mà không muốn viết tay mapper.

Khi nào sử dụng

  • Cần chuyển entity ↔ DTO/VO, kể cả List, mà không viết mapper thủ công.
  • Cần chuyển Map sang object (ví dụ map cấu hình động thành class cấu hình).
  • Cần chuyển đổi enum sang giá trị code và ngược lại.
  • Cần tránh đệ quy vô hạn khi map quan hệ vòng (entity cha ↔ con).
  • Cần một điểm gọi chuyển đổi thống nhất trong mã nghiệp vụ (GConversionService).

Cài đặt

Thêm dependency (không khai version — version do BOM quản lý, xem Cài đặt):

<dependency>
<groupId>vn.govex.cloud</groupId>
<artifactId>govex-cloud-mapstruct</artifactId>
</dependency>

Annotation của dependency có RetentionPolicy.SOURCE và chỉ được xử lý tại compile-time: bắt buộc khai báo govex-cloud-mapstruct-processor trong annotationProcessorPaths thì mapper mới được sinh — xem govex-cloud-mapstruct-processor.

Cấu hình

Auto-configuration tạo sẵn hai bean và có thể thay thế bằng bean riêng:

BeanKiểuĐiều kiệnMô tả
converterFactoryConverterFactory@ConditionalOnMissingBeanMặc định SpringConverterFactory tra mapper trong ApplicationContext
converterGConversionService@ConditionalOnMissingBeanFacade chuyển đổi dùng trong mã nghiệp vụ

Có thể thay ConverterFactory bằng cơ chế tra cứu khác (ví dụ DefaultConverterFactory quét classpath qua Mappers của MapStruct).

Sử dụng

Khai báo mapper trên lớp nguồn

@AutoMapper(target = UserVO.class)
@Data
public class User {
private String name;
private Integer age;
}

Processor sinh interface UserToUserVOMapper (tên mặc định {Nguồn}To{Đích}Mapper) — có thể đổi bằng mapperName/mapperNameSuffix.

Gọi chuyển đổi qua bean converter

@RequiredArgsConstructor
@Service
public class UserService {

private final GConversionService converter;

public UserVO toVo(User user) {
return converter.convert(user, UserVO.class);
}

public List<UserVO> toVoList(List<User> users) {
return converter.convert(users, UserVO.class);
}

public UserVO update(User source, UserVO target) {
return converter.convert(source, target);
}
}

Map sang object và enum

@AutoMapMapper
public class Setting {
private String key;
private String value;
}

// Map<String, Object> map = ...;
Setting setting = converter.convert(map, Setting.class);

@AutoEnumMapper("code")
public enum Status {
ACTIVE(1), INACTIVE(0);
// getter cho field code...
}

Tránh đệ quy khi map quan hệ vòng

@AutoMapper(target = NodeVO.class, cycleAvoiding = true)
public class Node {
private Node parent;
private List<Node> children;
}
NodeVO vo = converter.convert(node, NodeVO.class, new CycleAvoidingMappingContext());

Cấu hình tập trung cho mapper

@AutoMapperConfig(mapperPackage = "vn.govex.app.mapper")
public class MapperConfig { }

Mỗi module biên dịch chỉ được có một class gắn @AutoMapperConfig; các policy mặc định (unmapped source/target, null handling...) khai báo tại đây áp dụng cho toàn bộ mapper trong module.

Lưu ý

  • Bắt buộc có govex-cloud-mapstruct-processor trên annotation processor path; nếu không, annotation bị bỏ qua và không có mapper nào được sinh.
  • Mapper mặc định sinh trong package của lớp nguồn; đổi qua mapperPackage@AutoMapperConfig hoặc compiler option.
  • Adapter @Component (MapperConverterAdapter, MapMapperConverterAdapter) mặc định nằm trong package vn.govex.cloud.mapstruct — package này được auto-configuration component-scan. Đổi adapterPackage/autoConfigPackage phải đảm bảo package đó cũng được scan.
  • GConversionService.convert ném ConvertException khi không tìm thấy mapper phù hợp; kiểm tra lại cặp kiểu nguồn/đích khi gặp lỗi này.
  • Khi dùng chung với Lombok, thêm lombok-mapstruct-binding vào annotationProcessorPaths để hai processor phối hợp đúng thứ tự.