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ự.