如何在Spring Boot中使用Mapstruct映射父母和孩子?

丹尼尔

我有父母(产品)和孩子(书,家具),并想将产品实体映射到产品DTO。如您所见,产品已映射并存储在数据库的单个表中。如何映射具有其子级额外详细信息的父产品?

我看着这个这个这个有一些想法,但没有运气

实体

@Entity
@Table(name = "product")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Product {
  @Id
  private long id;
  private String productName;
}

@Entity
@DiscriminatorValue("Book")
public class Book extends Product { 
  private String author;
  ...
}
@Entity
@DiscriminatorValue("Furniture")
public class Furniture extends Product {
  String color;
  ...
}

DTO

public class ProductDto {
  private long id;
  private String productName;
  ...
}

public class BookDto extends ProductDto {
  private String author;
  ...
}
public class FurnitureDto extends ProductDto {
   String color;
   ... 
}

映射器

@Mapper(uses = {BookMapper.class,FurnitureMapper.class})
public interface ProductMapper {
    
    ProductDto productToProductDto(Product product);
    Product productDtoToProduct(ProductDto productDto);
}

@Mapper
public interface BookMapper {
    BookDto bookToBookDto(Book book);
    Book bookDtoToBook(BookDto bookDto);
}

@Mapper
public interface FurnitureMapper {
    FurnitureDto furnitureToFurnitureDto(Furniture furniture);
    Furniture furnitureDtoToFurniture(FurnitureDto furnitureDto);
}

服务

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    ProductRepository productRepository;
    @Autowired
    ProductMapper productMapper;

    @Override
    public List<ProductDto> getAllProducts() {
        List<ProductDto> listOfProducts = new ArrayList<>();
        productRepository.findAll().forEach(i -> 
        listOfProducts.add(productMapper.productToProductDto(i)));
        return listOfProducts;
    }
}

已编辑

将产品实体映射到产品dto后,得到以下结果。它不绑定数据,也不包括其子级属性。上面的映射器部分正确吗?

[
    {
        "id": 0,
        "productName": null
    },
    {
        "id": 0,
        "productName": null
    },
    ...
]

但是结果应该像下面这样:

[
    {
        "id": 11,
        "productName": ABC,
        "author":"James"
    },
    {
        "id": 22,
        "productName": XYZ,
        "color":"Oak"
    },
    ...
]
Tasos P.

TL; DR

没有干净的方法可以做到这一点。原因在于Java的编译时方法选择。但是有一种使用访客模式的干净方法。

为什么不起作用

在迭代包含不同类型(产品,书籍,家具)的实体列表时,需要为每种类型调用不同的映射方法(即,不同的MapStruct映射器)。

除非您instanceof按照Amir的建议进行操作,并明确选择映射器,否则您需要使用方法重载来为每个实体类调用不同的映射方法。问题是Java将在编译时选择重载的方法,此时,编译器仅看到Product对象列表(存储库方法返回对象)。MapStruct或Spring或您自己的自定义代码尝试执行此操作并不重要。这也是为什么ProductMapper总是调用your的原因:它是在编译时可见的唯一类型。

使用访客模式

由于我们需要手动选择正确的映射器,因此我们可以选择哪种方法更清洁或更可维护。这绝对是有根据的。

我的建议是按以下方式使用访客模式(实际上是它的一种变体):

为需要映射的实体引入一个新接口:

public interface MappableEntity {

    public ProductDto map(EntityMapper mapper);
}

您的实体将需要实现此接口,例如:

public class Book extends Product implements MappableEntity {
//...
@Override
    public ProductDto map(EntityMapper mapper) {
        return mapper.map(this);//This is the magic part. We choose which method to call because the parameter is this, which is a Book!
    }
}

EntityMapper是访问者接口:

public interface EntityMapper {

    ProductDto map(Product entity);

    BookDto map(Book entity);

    FurnitureDto map(Furniture entity);

    // Add your next entity here
}

最后,您需要MasterMapper:

// Not a class name I'm proud of
public class MasterMapper implements EntityMapper {

    // Inject your mappers here

    @Override
    public ProductDto map(Product product) {
        ProductMapper productMapper = Mappers.getMapper(ProductMapper.class);
        return productMapper.map(product);
    }

    @Override
    public BookDto map(Book product) {
        BookMapper productMapper = Mappers.getMapper(BookMapper.class);
        return productMapper.map(product);
    }

    @Override
    public FurnitureDto map(Furniture product) {
        FurnitureMapper productMapper = Mappers.getMapper(FurnitureMapper.class);
        return productMapper.map(product);
    }

    // Add your next mapper here

}

您的服务方法将如下所示:

MasterMapper mm = new MasterMapper();
List<Product> listOfEntities = productRepository.findAll();
List<ProductDto> listOfProducts = new ArrayList<>(listOfEntities.size());
listOfEntities.forEach(i -> {
        if (i instanceof MappableEntity) {
            MappableEntity me = i;
            ProductDto dto = me.map(mm);
            listOfProducts.add(dto);
        } else {
            // Throw an AssertionError during development (who would run server VMs with -ea ?!?!)
            assert false : "Can't properly map " + i.getClass() + " as it's not implementing MappableEntity";
            // Use default mapper as a fallback
            final ProductDto defaultDto = Mappers.getMapper(ProductMapper.class).map(i);
            listOfProducts.add(defaultDto);
        }
     });
    return listOfProducts;

您可以放心地忽略Mappers.getMapper()调用:由于该问题与Spring无关,因此我为简化起见GitHub上使用MapStruct的工厂创建了一个工作示例您只需使用CDI注入映射器即可。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在父母静态方法中使用孩子的变量?

来自分类Dev

我如何使用班级的父母和孩子?

来自分类Dev

如何在Spring Boot中使用CommonsMultipartResolver

来自分类Dev

如何使用Mapstruct和Kotlin在另一个映射器中使用映射器?

来自分类Dev

如何在Selenium JavaScript中使用最后一个孩子作为父母?

来自分类Dev

如何在Spring Boot中使用内部类并将其映射为列字段变量?

来自分类Dev

父母与同类型的孩子-如何映射?

来自分类Dev

如何在 Spring Boot 和 Spring Data 中使用两个 Cassandra 数据源?

来自分类Dev

如何使用jQuery使孩子成为父母的父母?

来自分类Dev

如何在父母和孩子之间共享过滤器

来自分类Dev

如何在父母和孩子之间共享过滤器

来自分类Dev

你如何在laravel eloquent中查询孩子和父母

来自分类Dev

你如何在laravel eloquent中查询孩子和父母

来自分类Dev

如何在Spring Boot中使用推土机?

来自分类Dev

如何在Spring Boot中使用分割项目

来自分类Dev

如何在Spring Boot中使用websocket并响应js?

来自分类Dev

如何在Spring Boot Controller中使用Jquery AJAX

来自分类Dev

如何在Spring Boot中使用@Valid验证对象?

来自分类Dev

如何在 Spring Boot 中使用 ST_CONTAINS?

来自分类Dev

如何在Mapstruct集合映射器中使用修饰方法?

来自分类Dev

如何在skaffold和dekorate中使用spring boot maven插件build-image?

来自分类Dev

如何在SOAPHandler中使用Spring bean

来自分类Dev

如何在Spring MVC中使用JasperReports?

来自分类Dev

如何在Spring API中使用umlaut

来自分类Dev

如何在Spring MVC中使用CDN

来自分类Dev

如何在Spring Controller中使用if ...

来自分类Dev

如何在 HOC 中使用 React Spring?

来自分类Dev

如何在PostgreSQL和Hibernate / Spring中使用LIMIT子句

来自分类Dev

如何从位置获取父母和孩子的ID

Related 相关文章

  1. 1

    如何在父母静态方法中使用孩子的变量?

  2. 2

    我如何使用班级的父母和孩子?

  3. 3

    如何在Spring Boot中使用CommonsMultipartResolver

  4. 4

    如何使用Mapstruct和Kotlin在另一个映射器中使用映射器?

  5. 5

    如何在Selenium JavaScript中使用最后一个孩子作为父母?

  6. 6

    如何在Spring Boot中使用内部类并将其映射为列字段变量?

  7. 7

    父母与同类型的孩子-如何映射?

  8. 8

    如何在 Spring Boot 和 Spring Data 中使用两个 Cassandra 数据源?

  9. 9

    如何使用jQuery使孩子成为父母的父母?

  10. 10

    如何在父母和孩子之间共享过滤器

  11. 11

    如何在父母和孩子之间共享过滤器

  12. 12

    你如何在laravel eloquent中查询孩子和父母

  13. 13

    你如何在laravel eloquent中查询孩子和父母

  14. 14

    如何在Spring Boot中使用推土机?

  15. 15

    如何在Spring Boot中使用分割项目

  16. 16

    如何在Spring Boot中使用websocket并响应js?

  17. 17

    如何在Spring Boot Controller中使用Jquery AJAX

  18. 18

    如何在Spring Boot中使用@Valid验证对象?

  19. 19

    如何在 Spring Boot 中使用 ST_CONTAINS?

  20. 20

    如何在Mapstruct集合映射器中使用修饰方法?

  21. 21

    如何在skaffold和dekorate中使用spring boot maven插件build-image?

  22. 22

    如何在SOAPHandler中使用Spring bean

  23. 23

    如何在Spring MVC中使用JasperReports?

  24. 24

    如何在Spring API中使用umlaut

  25. 25

    如何在Spring MVC中使用CDN

  26. 26

    如何在Spring Controller中使用if ...

  27. 27

    如何在 HOC 中使用 React Spring?

  28. 28

    如何在PostgreSQL和Hibernate / Spring中使用LIMIT子句

  29. 29

    如何从位置获取父母和孩子的ID

热门标签

归档