将DTO转换为实体,反之亦然

xyz*_*xyz 16 java jpa spring-mvc

我在我的Web应用程序中使用Spring MVC架构JPA.

哪里可以手动将DTO转换为实体,反之亦然(不使用任何框架)?

Sab*_*han 19

这是一个已接受答案的旧问题,但是使用模型映射器API以简单的方式更新它.

<dependency>
    <groupId>org.modelmapper</groupId>
    <artifactId>modelmapper</artifactId>
    <version>0.7.4</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

使用此API,您可以避免手动设置器和getter,如接受的答案中所述.

在我看来,两个转换都应该在私有实用程序方法的帮助下在控制器上进行,并使用Java8流的映射(如果交换了DTO集合),如本文所示.

它应该发生在控制器上,因为DTO应该是独占的传输对象.我不会进一步减少我的DTO.

您可以在实体上编写服务和数据访问层,并在调用服务方法之前将DTO转换为实体,并在从控制器返回响应之前将实体转换为DTO.

我更喜欢这种方法,因为实体很少更改,并且可以根据需要从DTO添加/删除数据.

这里描述详细的模型映射器配置和规则

  • @ThiagoCunha:我没有看过modelmapper源代码,但是反射对我来说似乎是唯一的方法。另一方面,由于控制器负责控制输入/输出数据(根据您的要求),因此逻辑上也应该进行转换。实际上,转换代码可以放在某些实用程序类中,但是转换调用自然应该从控制器进行,尽管有没有硬性规定,这些只是意见。 (2认同)
  • @ThiagoCunha:嗨,我建议首先检查模型映射器代码,以确保它确实使用反射,因为性能非常好。市场上几乎没有类似的 API,并且可以让您免于手动工作。 (2认同)

NIr*_*odi 9

我想你问的是在哪里写整个实体 - > DTO转换逻辑.

喜欢你的实体

class StudentEntity {
 int age ;
 String name;

 //getter
 //setter

 public StudentDTO _toConvertStudentDTO(){
    StudentDTO dto = new StudentDTO();
    //set dto values here from StudentEntity
    return dto;
 }

}
Run Code Online (Sandbox Code Playgroud)

你的DTO应该是这样的

class StudentDTO  {
 int age ;
 String name;

 //getter
 //setter

 public StudentEntity _toConvertStudentEntity(){
    StudentEntity entity = new StudentEntity();
    //set entity values here from StudentDTO
    return entity ;
 }

}
Run Code Online (Sandbox Code Playgroud)

你的控制器应该是这样的

@Controller
class MyController {

    public String my(){

    //Call the conversion method here like
    StudentEntity entity = myDao.getStudent(1);
    StudentDTO dto = entity._toConvertStudentDTO();

    //As vice versa

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 如果一个人关心模块化,这种方法会迫使DTO依赖于实体,反之亦然.此外,在多模块项目中,如果您的实体和DTO位于单独的模块中(通常是这种情况),这将导致循环依赖.结帐[这个答案](/sf/answers/3119311541/) (5认同)
  • DTO是不应该包含任何业务逻辑的简单对象,即,它们不应了解实体(值对象)或如何将自身转换为实体(值对象)。 (3认同)
  • 1. DTO不应该有任何逻辑。2. DTO 不应该了解实体,反之亦然。3.你违反了建议零售价 (3认同)
  • 您的答案违反了OOP原则。 (2认同)
  • 当谈到干净的代码时,我相信转换过程将在服务内进行,而不是在应用程序控制层进行。还有一点需要注意的是,仍然与 DDD 相关,就是有一个业务规则触及你的实体,而实体只有一个原则,并且不会增加业务价值。Martin (2013) 在他的关于 DTO 的干净代码书中也指出了这一点。阅读一下如何使用它。起初,我很受伤,将转换放入 DTO,而实际上它需要位于该业务的特定转换类中。 (2认同)

Wes*_*Gun 8

我建议另一种无需额外依赖的方法:

import org.springframework.beans.BeanUtils
...
BeanUtils.copyProperties(sourceObject, targetObject);
Run Code Online (Sandbox Code Playgroud)

如果属性类型和名称相同,则可用于将DTO转换为实体,反之亦然。

如果您想忽略某些字段,只需在后面添加它们targetObject

BeanUtils.copyProperties(sourceObj, targetObj, "propertyToIgnoreA", "propertyToIgnoreB", "propertyToIgnoreC");
Run Code Online (Sandbox Code Playgroud)

来源:http//appsdeveloperblog.com/dto-to-entity-and-entity-to-dto-conversion/

我认为这是最干净的方法。

  • 虽然 BeanUtils.copyProperties 是一个可行的解决方案,但它仍然基于 Reflection API,因此与基于构建时代码生成的 MapStruct 和 Orika 等工具相比,每次转换都会产生相当大的开销。MapStruct 非常简单,我建议在性能很重要的情况下使用它而不是 BeanUtils (2认同)

小智 7

在我看来

  • 在调度jsp页面之前,应该在Controller中完成实体 - > DTO转换
  • 在验证从jsp页面返回的DTO之后,DTO - >实体转换也应该在Controller中完成

它使您可以更好地控制进程,并且每次更改填充实体的某些逻辑时,您不必更改服务/持久性类.


Ale*_*kov 5

我可以建议使用mapstruct库:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-jdk8</artifactId>
    <version>1.2.0.Final</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

例如,如果您有这样一个实体:

public class Entity {
    private Integer status;
    private String someString;
    private Date startDate;
    private Date endDate;

    // SKIPPED
Run Code Online (Sandbox Code Playgroud)

和DTO:

public class Dto {
    private Boolean status;
    private String someString;
    private Long startDate;
    private Long endDate;

    // SKIPPED
Run Code Online (Sandbox Code Playgroud)

然后可以通过以下方式在服务层中完成转换:

@Service
public class SomeServiceImpl implements SomeService {

    @Autowired
    SomeDao someDao;

    @Autowired
    SomeMapper someMapper;


    public Dto getSomething(SomeRequest request) throws SomeException {
        return someDao.getSomething(request.getSomeData())
                .map(SomeMapper::mapEntityToDto)
                .orElseThrow(() -> new SomeException("..."));
    }
Run Code Online (Sandbox Code Playgroud)

映射器可以表示如下:

@Mapper 
public interface SomeMapper {
    @Mappings(
            {@Mapping(target = "entity", 
                      expression = "java(entity.getStatus() == 1 ? Boolean.TRUE : Boolean.FALSE)"),
             @Mapping(target = "endDate", source = "endDate"),
             @Mapping(target = "startDate", source = "startDate")
            })

    Dto mapEntityToDto(Entity entity);
}
Run Code Online (Sandbox Code Playgroud)

  • 除了使用 MapStruct 我还建议使用这个扩展 https://github.com/Pozo/mapstruct-kotlin 这允许您通过不再要求您显式声明无参数 ctor 来保持您的 kotlin 数据类不可变,即构造函数():这个(空,空) (2认同)