首页 > 解决方案 > How to avoid services in DtoMappers layer

问题描述

Good day, I have a Spring Boot based backend , we are using own library to convert JPA entities to Dto's (library works based on reflection). The problem is , we inject service layer directly to some mappers. Let's say I have a UserEntity and UserDto. UserDto has a field called avatar and avatars are stored in S3. So in order to build a UserDto we are using the code like this.

@Component
class UserMapper {

 @Inject
 S3Service s3Service;

 public UserDto toDto(UserEntity entity){
     UserDto dto = new UserDto();
     BeanUtils.copy(entity,dto);
     dto.setAvatar(s3Service.getAvatarByUser(entity));

}

}

I don't like this approach because Mapper mustn't know anything about Service layer . However this mapper is used by other mappers as well. In case I want to return an OrderDto, it has a nested UserDto so OrderDto calls UserMapper internally. Are there any best practices for Mappers to be service free ?

So far I tried the following.

  1. Store avatar in ThreadLocal cache. When controller calls a service to get a user, service will store user's avatar in the ThreadLocal, and then Mapper will get it from ThreadLocal cache. Disadvantage - it's hard to test it and requires me to make Mocks
  2. Create a separate POJO called UserWithAvatar that stores UserEntity entity;String avatar and create a mapper for UserWithAvatar instead of UserEntity. Disadvantage - as I said this mapper will be used by OrderMapper and order mapper takes OrderEntity with nested UserEntity instead of UserWithAvatar

标签: javaspringdesign-patternsapplication-layer

解决方案


我认为映射器应该在服务范围内,但我会尝试满足您的要求

你有2个选择:

  1. 您将服务和映射器都注入控制器,将实体返回到控制器并在返回响应之前使用映射器映射它

  2. 使用事件发布来发布一个事件,然后映射器捕获并生成映射。之后,您可以直接将 dto 返回给控制器或产生另一个事件。(事件发布默认是同步的,所以你不必担心并发问题)

事件发布是通过 spring 完成的,导致代码非常不耦合,其中发布者对事件订阅者一无所知,因此这两个可以在 2 个独立的层中,彼此不知道任何事情

易于遵循的指南:https ://www.baeldung.com/spring-events


推荐阅读