Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将DTO转换为实体,反之亦然_Java_Spring Mvc_Jpa - Fatal编程技术网

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

Java 将DTO转换为实体,反之亦然,java,spring-mvc,jpa,Java,Spring Mvc,Jpa,我正在我的web应用程序中使用springmvc体系结构和JPA。在哪里手动(即不使用任何框架)将数据传输对象(DTO)转换为JPA实体,反之亦然 在调度jsp页面之前,应该在控制器中完成实体->DTO转换 验证从jsp页面返回的DTO之后,还应该在控制器中完成DTO->实体转换 Its使您能够更好地控制流程,并且不必每次更改填充实体的某些逻辑时都更改服务/持久性类。我想您是在询问将整个实体-->数据写入转换逻辑的位置 喜欢你的实体吗 class StudentEntity { int a

我正在我的web应用程序中使用
springmvc
体系结构和
JPA
。在哪里手动(即不使用任何框架)将数据传输对象(DTO)转换为JPA实体,反之亦然

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

Its使您能够更好地控制流程,并且不必每次更改填充实体的某些逻辑时都更改服务/持久性类。

我想您是在询问将整个实体-->数据写入转换逻辑的位置

喜欢你的实体吗

class StudentEntity {
 int age ;
 String name;

 //getter
 //setter

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

}
你的DTO应该是

class StudentDTO  {
 int age ;
 String name;

 //getter
 //setter

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

}
你的控制器应该是

@Controller
class MyController {

    public String my(){

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

    //As vice versa

    }

}

这是一个有公认答案的老问题,但需要使用模型映射器API以简单的方式进行更新

<dependency>
    <groupId>org.modelmapper</groupId>
    <artifactId>modelmapper</artifactId>
    <version>0.7.4</version>
</dependency>

org.modelmapper
. 

它应该发生在控制器上,因为DTO是专用的传输对象。我不会把我的DTO再往下推

在实体上对服务和数据访问层进行编码,并在调用服务方法之前将DTO转换为实体,在从控制器返回响应之前将实体转换为DTO

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

详细的模型映射器配置和规则如下所述

我建议使用库:

和DTO:

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

    // SKIPPED
然后可以通过以下方式在服务层进行转换:

@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("..."));
    }
映射器可以表示为如下所示:

@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);
}

我建议另一种没有额外依赖性的方法:

import org.springframework.beans.BeanUtils
...
BeanUtils.copyProperties(sourceObject, targetObject);
如果DTO具有相同的属性类型和名称,则可用于将DTO转换为实体,反之亦然

如果要忽略某些字段,只需将它们添加到
targetObject
之后即可

BeanUtils.copyProperties(sourceObj, targetObj, "propertyToIgnoreA", "propertyToIgnoreB", "propertyToIgnoreC");
资料来源:


我认为这是最干净的方式。请记住检查Javadoc中的注意事项

使用了mapstruct库。在build.gradle中另外添加了以下内容

sourceSets {
    main.java.srcDirs += "build/generated/sources/annotationProcessor/java/main/"
}

同意。此外,如果您将实体和DTO中的转换逻辑结合起来,那么这两个转换逻辑就不能分离为单独的JAR工件。例如,如果不包括实体,就无法将DTO类提供给第三方,这(在大多数情况下)是您不希望的。如果您的实体中有延迟加载属性,该怎么办?如果在控制器中执行转换,则将加载属性,这可能是不需要的。我们应该为域对象添加一个额外的层吗?(这可能很昂贵)如果一个人关心模块化,这种方法将迫使DTO依赖实体,反之亦然。此外,在多模块项目中,如果实体和DTO位于单独的模块中(通常情况下),这将导致循环依赖。签出DTO是简单的对象,不应该包含任何业务逻辑,也就是说,它们不应该知道实体(值对象)或如何将自己转换为实体(值对象)。您的回答违反了OOP原则。对于干净的代码,我相信转换过程将在服务中进行,不在应用程序控制层。另一点需要注意的是,仍然与DDD相关的是,有一个业务规则涉及到您的实体,并且该实体只有一个原则,它不会添加到业务价值中。Martin(2013)在其关于DTO的干净代码书中也指出。阅读一下如何使用它。起初,我很痛苦,将转换放在DTO中,而实际上它需要在这个业务的特定转换类中。1。不应该有任何逻辑。2.数据不应该了解实体,反之亦然。3.你喜欢这个答案。在新的世界秩序中,,除非字段名不同,否则这看起来是不编写任何样板文件的完美方法。感谢您提供了一个合理的答案。虽然
BeanUtils.copyProperties
是一个有效的解决方案,但它仍然基于反射API,因此与MapStruct和Orika等工具相比,每次转换都会带来可观的开销基于构建时代码生成。MapStruct非常简单,我建议在性能非常重要的情况下使用它而不是BeanUtils,这就是我提到的“注意事项”。。。还有其他一些,所以Javadoc是必须阅读的。对于性能问题,我不使用它,除了使用MapStruct之外,它在第一次使用时会花费很多钱。我还建议使用此扩展。这允许您通过不再需要显式声明无参数构造函数(即构造函数())来保持kotlin数据类的不可变性:这(空,空)在我看来,控制器只是控制输入和输出数据。转换过程必须发生在服务类中。另外,这个modelmapper,它是否使用反射来执行转换?@ThiagoCunha:我没有看过modelmapper源代码,但反射似乎是我唯一的方法。对于另一部分,因为控制器是负责控制输入/输出数据(根据您)所以逻辑上转换也应该发生在那里。实际上转换代码可以放在一些实用程序类中,但是转换调用应该自然地从控制器中发生,尽管没有硬性的规则。这些只是观点。所以我更喜欢在仍然处于旧模式的情况下创建设计模式(笑声)。这是因为反射不会在编译时经过优化过程。我在一个通用代码生成模型中使用了转换器设计模式。我应用了一种很好的技术,尽管需要手动操作,但它还是很有效率。@Thiagucunha:嗨,我建议先通过模型映射器代码来确保它真正的使用反射,因为性能非常好。市场上几乎没有更多的API是针对同一个API的&这可能会使您从手工工作中解脱出来。
BeanUtils.copyProperties(sourceObj, targetObj, "propertyToIgnoreA", "propertyToIgnoreB", "propertyToIgnoreC");
sourceSets {
    main.java.srcDirs += "build/generated/sources/annotationProcessor/java/main/"
}