Mapstruct - 如何将 DTO 字符串参数转换为实体对象?

Mapstruct - How to convert a DTO String parameter to an Entity object?

我是 Mapstruct 的新手,我正在努力正确理解它。

我想要实现的是从 DTO 字符串参数(carModel)转换为他的实体,使用服务和存储库检索。

问题是 Mapstruct 生成的 Mapper class 试图用 @Autowired 注释注入服务 class,但它不起作用。该服务为空。

这是我的 @Mapper class:

@Mapper(componentModel = "spring", uses = CarModelService.class)
public interface KitMapper extends EntityMapper<KitDTO, Kit> {
    KitMapper INSTANCE = Mappers.getMapper(KitMapper.class);

    @Mapping(source = "weight", target = "systemWeight")
    @Mapping(source = "carModel", target = "carModel")
    Kit toEntity(KitDTO kitDTO);
}

public interface EntityMapper<D, E> {
    E toEntity(D dto);
    List<E> toEntity(List<D> dtoList);
}

@Service class:

@Service
@Transactional
public class CarModelService {
    private final CarModelRepository carModelRepository;

    @Transactional(readOnly = true)
    public CarModel findByName(String name) {
        return carModelRepository.findByName(name).orElse(null);
    }
}

@Repository class:

@Repository
public interface CarModelRepository extends JpaRepository<CarModel, Long> {
    Optional<CarModel> findByName(String carModelName);
}

DTO 和实体 classes:

public class KitDTO {
    private String id;
    private String carModel; // e.g. "Ferrari Monza"
    ....
}
@Entity
@Table(name = "kit")
public class Kit implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    @Column(name = "id")
    private Long id;

    @ManyToOne
    private CarModel carModel;

    ...
}
@Entity
@Table(name = "car_model")
public class CarModel implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    @Column(name = "id")
    private Long id;

    @Column(name = "name")
    private String name;

    ...
}

构建工作正常,但当我尝试使用 Mapper 时应用程序停止。它说 carModelService 为空。 这是映射器生成的实现 class:

@Component
public class KitMapperImpl implements KitMapper {

    @Autowired // <-- this seems not working
    private CarModelService carModelService;

    @Override
    public Kit toEntity(KitDTO kitDTO) {
        if ( kitDTO == null ) {
            return null;
        }

        Kit kit = new Kit();

        kit.setSystemWeight( String.valueOf( kitDTO.getWeight() ) );
        kit.carModel( carModelService.findByName(kitDTO.getCarModel()) ); // <-- carModelService is null!

        // other setters

        return kit;
    }
}

我尝试了很多东西,使用装饰器、@Context、表达式,将@Mapper class 注入@Service class。

我发现了很多问题,但实际上没有人帮助我:

MapStruct mapper not initialized with autowired when debug

如有任何帮助,我们将不胜感激!提前致谢!

能否分享错误信息? 从你分享的信息,我可以看到KitDto中的carModel是String,Entity中的是CarModel class。不确定 mapstruct 的自动生成实现 class 是如何实现的:kit.carModel( carModelService.findByName(kitDTO.getCarModel()) );.

但我想分享另一种方法,不知道这是否是最佳做法。在这种方法中,您可以创建一个 abstarct class 映射器,您可以在其中 @Autowired 存储库可以手动添加那些映射。 我分享了它的片段。希望这对你有所帮助。

    @Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public abstract class ProductMapper {
    @Autowired 
    private CarModelService carModelService;
    
    public abstract Kit convertDTOToEntity(KitDTO kitDTO);
    
       public Kit toEntity(KitDTO kitDTO);
        {   
        Kit kit = convertDTOToEntity(kitDTO);
        kit.setCarModel(carModelService.findByName(kitDTO.getCarModel()));
        return kit;
        }
    }

对其他方法感到好奇,将关注此线程。我们可以讨论最佳实践

找到解决方案!

我没有直接从 @RestController class 调用 Mapper 方法 toEntity(),而是在 CarModelService class 中注入了映射器并创建了一个方法调用映射器。 这样的流程是:

Controller --> Service --> Mapper

@Service
@Transactional
public class KitService {
    private final KitRepository kitRepository;

    private final KitSearchRepository kitSearchRepository;

    private final KitMapper kitMapper; // <-- mapper declaration

    public KitService(KitRepository kitRepository, KitSearchRepository kitSearchRepository, KitMapper kitMapper) {
        this.kitRepository = kitRepository;
        this.kitSearchRepository = kitSearchRepository;
        this.kitMapper = kitMapper; // <-- mapper initilization
    }

    // here the method which calls mapper
    public Kit convertDTOToEntity(KitDTO kitDTO) {
        return kitMapper.toEntity(kitDTO);
    }

这样,Mapstruct生成的class就不会在CarModelService上报错了。

似乎这种方法是实现此目的的唯一方法,在服务和映射器之间创建“桥梁”之王。

(您也可以使用 @Autowired 注释而不是构造函数)