我有2个微服务:我们称它们为A和B。
由B处理的实体(其中引用了a的实体)被实现为简单的长id(例如groupId)
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "WorkShifts")
@AllArgsConstructor
@Builder(toBuilder = true)
public class WorkShiftEntity extends BaseEntitySerial {
@Column(name = "group_id")
private Long groupId;
private String description;
@Column(name = "start_time")
private Time startTime;
@Column(name = "end_time")
private Time endTime;
@Column(name = "work_shift")
private Integer workShift;
}
我想要实现的是使用mapstruct填充B(由A持有)的缺失组数据。到目前为止,我尝试使用@AfterMapping函数向a请求缺失的数据。我的映射器是:
@Mapper(componentModel = "spring", uses = LocalTimeMapper.class, builder = @Builder(disableBuilder = true), config = CommonMapperConfig.class)
public abstract class WorkShiftMapper extends BaseMapper implements IBaseMapper<WorkShiftEntity, WorkShiftDTO, Long>, LogSupport {
@Autowired
RestTemplate restTemplate;
@Mapping(target = "groupId", source = "group.id")
public abstract WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO);
@AfterMapping
public void afterEntityToDto(final WorkShiftEntity workShiftEntity, @MappingTarget final WorkShiftDTO workShiftDTO) {
if (workShiftEntity == null) {
return;
}
GroupDTO groupDTO = EcofinderUtils.getGroupDTO(restTemplate, workShiftEntity.getGroupId());
try {
GenericUtils.enhanceDTOForAttributeWithDTO(workShiftDTO, groupDTO, "group");
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
@AfterMapping
public void afterEntityToDtoList(final List<WorkShiftEntity> workShiftEntity, @MappingTarget final List<WorkShiftDTO> workShiftDTO) {
if (workShiftEntity == null || workShiftEntity.size() == 0) {
return;
}
List<GroupDTO> groups = EcofinderUtils.getAllGroupDTOById(restTemplate, workShiftEntity.stream().map(WorkShiftEntity::getGroupId).distinct().toList());
try {
//Compile the resulting DTOs with the data got from the registry
//Group
GenericUtils.enhanceDTOListWithDataFromDTOJoiningEntities(workShiftDTO, groups, workShiftEntity, "group", "groupId");
} catch (AppException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
}
给我映射功能的实现接口是:
public interface IBaseMapper<T extends BaseEntity<K>, D extends IBaseDTO<K>, K extends Serializable> {
D entityToDto(T entity);
List<D> entityToDtoList(List<T> entity);
T dtoToEntity(D dto);
}
生成的代码的问题在于,将实体列表映射到DTO列表的函数对每个实体使用EntityToToTo,导致n个请求到a。之后,调用另一个@AfterMapping函数(仅在一个请求中收集所有ID并提取所有数据的函数,这是映射列表时唯一应该使用的函数)。
//GENERATED CODE BY MAPSTRUCT
@Override
public WorkShiftDTO entityToDto(WorkShiftEntity workShiftEntity) {
if ( workShiftEntity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( workShiftEntity.getId() );
workShiftDTO.setDescription( workShiftEntity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );
afterEntityToDto( workShiftEntity, workShiftDTO );
return workShiftDTO;
}
@Override
public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
//more code...
List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
for ( WorkShiftEntity workShiftEntity : entity ) {
list.add( entityToDto( workShiftEntity ) );
}
afterEntityToDtoList( entity, list );
return list;
}
有没有办法让mapstruct实现entityToDto函数两次,其中一个版本使用@AfterMapping函数,另一个版本不使用,以便让EntityToTodToList函数使用不带@AfterMapping调用的版本?
类似于:
@Override
public WorkShiftDTO entityToDto(WorkShiftEntity workShiftEntity) {
if ( workShiftEntity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( workShiftEntity.getId() );
workShiftDTO.setDescription( workShiftEntity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );
afterEntityToDto( workShiftEntity, workShiftDTO );
return workShiftDTO;
}
public WorkShiftDTO entityToDtoNoAfter(WorkShiftEntity workShiftEntity) {
if ( workShiftEntity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( workShiftEntity.getId() );
workShiftDTO.setDescription( workShiftEntity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );
return workShiftDTO;
}
@Override
public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
//more code...
List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
for ( WorkShiftEntity workShiftEntity : entity ) {
list.add( entityToDtoNoAfter( workShiftEntity ) );
}
afterEntityToDtoList( entity, list );
return list;
}
其他方法也很受欢迎,这种方法对我来说只是感觉更自然。
提前致谢!
经过大约两天的深入研究和多次尝试,我想我已经找到了一个不错的解决方案。
我可以给这些函数一个名字,这样它们就像有一个特定的作用域一样工作。映射器界面变成:
public interface IBaseMapper<T extends BaseEntity<K>, D extends IBaseDTO<K>, K extends Serializable> {
@BeanMapping(qualifiedByName = "EntityToDTO")
D entityToDto(T entity);
@Named("EntityToDTOList")
public abstract D entityToDTOListEntity(T entity);
@IterableMapping(qualifiedByName = "EntityToDTOList")
List<D> entityToDtoList(List<T> entity);
T dtoToEntity(D dto);
}
这样我就可以把我需要的所有功能组合在一起。
映射器抽象类:
@Mapping(target = "groupId", source = "group.id")
public abstract WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO);
@AfterMapping
@Named("EntityToDTO")
public void afterEntityToDto(final WorkShiftEntity workShiftEntity, @MappingTarget final WorkShiftDTO workShiftDTO) {
if (workShiftEntity == null) {
return;
}
GroupDTO groupDTO = EcofinderUtils.getGroupDTO(restTemplate, workShiftEntity.getGroupId());
try {
GenericUtils.enhanceDTOForAttributeWithDTO(workShiftDTO, groupDTO, "group");
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
@AfterMapping
@Named("EntityToDTOList")
public void afterEntityToDtoList(final List<WorkShiftEntity> workShiftEntity, @MappingTarget final List<WorkShiftDTO> workShiftDTO) {
if (workShiftEntity == null || workShiftEntity.size() == 0) {
return;
}
List<GroupDTO> groups = EcofinderUtils.getAllGroupDTOById(restTemplate, workShiftEntity.stream().map(WorkShiftEntity::getGroupId).distinct().toList());
try {
//Compile the resulting DTOs with the data got from the registry
//Group
GenericUtils.enhanceDTOListWithDataFromDTOJoiningEntities(workShiftDTO, groups, workShiftEntity, "group", "groupId");
} catch (AppException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
通过这样做,生成的Impl类是:
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-20T15:08:38+0200",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 17.0.1 (Oracle Corporation)"
)
@Component
public class WorkShiftMapperImpl extends WorkShiftMapper {
@Autowired
private LocalTimeMapper localTimeMapper;
@Override
public WorkShiftDTO entityToDto(WorkShiftEntity entity) {
if ( entity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( entity.getId() );
workShiftDTO.setDescription( entity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( entity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( entity.getEndTime() ) );
workShiftDTO.setWorkShift( entity.getWorkShift() );
afterEntityToDto( entity, workShiftDTO );
return workShiftDTO;
}
@Override
public WorkShiftDTO entityToDTOListEntity(WorkShiftEntity entity) {
if ( entity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( entity.getId() );
workShiftDTO.setDescription( entity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( entity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( entity.getEndTime() ) );
workShiftDTO.setWorkShift( entity.getWorkShift() );
return workShiftDTO;
}
@Override
public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
if ( entity == null ) {
return null;
}
List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
for ( WorkShiftEntity workShiftEntity : entity ) {
list.add( entityToDTOListEntity( workShiftEntity ) );
}
afterEntityToDtoList( entity, list );
return list;
}
@Override
public WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO) {
if ( workShiftDTO == null ) {
return null;
}
WorkShiftEntity workShiftEntity = new WorkShiftEntity();
workShiftEntity.setGroupId( workShiftDTOGroupId( workShiftDTO ) );
workShiftEntity.setId( workShiftDTO.getId() );
workShiftEntity.setDescription( workShiftDTO.getDescription() );
workShiftEntity.setStartTime( localTimeMapper.map( workShiftDTO.getStartTime() ) );
workShiftEntity.setEndTime( localTimeMapper.map( workShiftDTO.getEndTime() ) );
workShiftEntity.setWorkShift( workShiftDTO.getWorkShift() );
return workShiftEntity;
}
private Long workShiftDTOGroupId(WorkShiftDTO workShiftDTO) {
if ( workShiftDTO == null ) {
return null;
}
GroupDTO group = workShiftDTO.getGroup();
if ( group == null ) {
return null;
}
Long id = group.getId();
if ( id == null ) {
return null;
}
return id;
}
}
这正是我想要的。
假设我有这样的映射: 现在,我需要将子列表映射到子列表,但它们都有相同的父对象。我希望这样做: 但不管用,有机会做吗?
下面是我的DTO。 源DTO 目标DTO
给定: 我想把所有的车都标出来。将轮胎分为单独的轮胎板。我知道我可以做一个
假设我有以下课程:
我创建映射如下所示。如何将平面dto对象属性(街道、城市等)映射到域对象中的嵌套地址。当我试着去做的时候,我发现了一个错误: [错误]诊断:返回类型中的属性“Address.PostalCode”未知。@Mapping(来源=“City”,目标=“Address.City”), 还有类...
我试图使用MapStruct在dto和实体对象之间映射convert,但是生成的映射器实现只返回空的映射对象。 BeermapperImpl 任何人都可以提供我的代码可能出错的地方?谢谢!