当前位置: 首页 > 知识库问答 >
问题:

Spring靴中的DTO对流模式

彭华皓
2023-03-14

主要问题是如何在不违反SOLID原则的情况下将DTO转换为实体,将实体转换为Dtos。
例如,我们有这样的json:

{ id: 1,
  name: "user", 
  role: "manager" 
} 

DTO是:

public class UserDto {
 private Long id;
 private String name;
 private String roleName;
}

和实体是:

public class UserEntity {
  private Long id;
  private String name;
  private Role role
} 
public class RoleEntity {
  private Long id;
  private String roleName;
}

还有一个有用的Java8DTO转换模式

但是在他们的例子中,没有OneTo多项关系。为了创建UserEntity,我需要使用道层(服务层)按角色获取角色名称。我可以将UserRepository(或UserService)注入到Conconeter中吗?因为似乎转换器组件将打破SRP,它必须只转换,不能知道服务或存储库。

转换器示例:

@Component
public class UserConverter implements Converter<UserEntity, UserDto> {
   @Autowired
   private RoleRepository roleRepository;    

   @Override
   public UserEntity createFrom(final UserDto dto) {
       UserEntity userEntity = new UserEntity();
       Role role = roleRepository.findByRoleName(dto.getRoleName());
       userEntity.setName(dto.getName());
       userEntity.setRole(role);
       return userEntity;
   }

   ....

在卷积器类中使用存储库好吗?或者我应该创建另一个服务/组件,负责从DTO创建实体(如UserFactory)?

共有3个答案

闻人鸿文
2023-03-14

就个人而言,转换器应该位于控制器和服务之间,DTO唯一应该担心的是服务层中的数据以及如何向控制器公开哪些信息。

controllers <-> converters <-> services ... 

在您的情况下,您可以使用JPA在持久层填充用户的角色。

慕凌龙
2023-03-14

如果您有一个服务层,那么使用它来进行转换或将任务委托给转换器将更有意义
理想情况下,转换器应该只是转换器:映射器对象,而不是服务
现在,如果逻辑不太复杂且转换器不可重复使用,您可以将服务处理与映射处理混合使用,在这种情况下,您可以将转换器前缀替换为服务

而且,如果只让服务与存储库通信,看起来会更好
否则图层会变得模糊,设计也会变得凌乱:我们真的不知道是谁调用了谁。

我会这样做:

controller -> service -> converter 
                      -> repository

或自行执行转换的服务(转换不太复杂且不可重用):

controller -> service ->  repository            

老实说,我讨厌DTO,因为它们只是重复的数据
我之所以介绍它们,是因为客户在信息方面的需求与实体表示不同,而且定制类(在本例中不是重复类)更清晰

岳枫
2023-03-14

尽量将转换与其他层分离:

public class UserConverter implements Converter<UserEntity, UserDto> {
   private final Function<String, RoleEntity> roleResolver;

   @Override
   public UserEntity createFrom(final UserDto dto) {
       UserEntity userEntity = new UserEntity();
       Role role = roleResolver.apply(dto.getRoleName());
       userEntity.setName(dto.getName());
       userEntity.setRole(role);
       return userEntity;
  }
}

@Configuration
class MyConverterConfiguration {
  @Bean
  public Converter<UserEntity, UserDto> userEntityConverter(
               @Autowired RoleRepository roleRepository
  ) {
    return new UserConverter(roleRepository::findByRoleName)
  }
}

您甚至可以定义一个自定义的转换器

正如其他一些人指出的那样,这种抽象隐藏了应用程序的一部分,当用于集合时,这部分应用程序的性能可能非常差(因为数据库查询通常可以批处理。我建议你定义一个转换器

如果您想在定义转换器时获得更多的舒适性,请查看MapSTRt或ModelMapper。最后但并非最不重要的是给datus一个机会(免责声明:我是作者),它可以让你流畅地定义你的映射,而没有任何隐含的功能:

@Configuration
class MyConverterConfiguration {

  @Bean
  public Mapper<UserDto, UserEntity> userDtoCnoverter(@Autowired RoleRepository roleRepository) {
      Mapper<UserDto, UserEntity> mapper = Datus.forTypes(UserDto.class, UserEntity.class)
        .mutable(UserEntity::new)
        .from(UserDto::getName).into(UserEntity::setName)
        .from(UserDto::getRole).map(roleRepository::findByRoleName).into(UserEntity::setRole)
        .build();
      return mapper;
  }
}

(此示例在转换集合时仍会遇到数据库瓶颈

我认为这将是最可靠的方法,但给定的上下文/场景正遭受着无法处理的依赖性和性能影响,这让我认为强制使用SOLID可能是一个坏主意。这是一种权衡

 类似资料:
  • 我正在使用带有bootrepackagegradle的springboot来构建发布jar文件。我的项目需要在交付给客户之前混淆代码。我尝试了proguard和其他一些工具,但出现了许多问题。我想知道如何为spring boot配置这些工具。 我用这些配置试过ProGuard 但是生成的jar无法运行

  • 我正在学习如何使用Docker与一个Spring Boot应用程序。我遇到了一个小障碍,我希望有人能看到这个问题。我的应用程序严重依赖于环境特定属性文件中设置的@value。在我的/src/main/resources中,我有三个属性文件 应用程序.属性 应用程序-local.properties 应用程序-prod.properties 我通常用:java-jar-dspring.profile

  • 我正在使用Spring Boot 1.2.7和Thymeleaf。 所有html页面都在文件夹中,当我说

  • 我正在用Thymeleaf构建一个Spring Boot应用程序。我的模板(视图)和静态文件夹都在src/main/Resources/静态和src/main/Resources/tem板下。当我通过main方法(使用eclipse)运行应用程序时,一切都很好。但是,我已经按照说明创建了一个war文件,当我将其部署到Tomcat 7时——静态内容丢失了,只显示了Thymeleaf html模板。

  • 我想在我的spring boot项目中使用Kafka Streams实时处理。所以我需要Kafka Streams配置,或者我想使用KStreams或KTable,但我在互联网上找不到示例。 我做了制作人和消费者现在我想流实时。

  • 我试图在spring boot应用程序中构建shaded jar,但是遇到了一些问题。我不知道我做错了什么。我还阅读了以下链接,但没有运气maven-shade-plugin错误:无法在org . Apache . maven . plugins . shade . resource . manifestresourceformer中找到“resource”的setter、adder或field