java - 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.
- 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 - Create a separate POJO called UserWithAvatar that stores
UserEntity entity;String avatar
and create a mapper forUserWithAvatar
instead ofUserEntity
. Disadvantage - as I said this mapper will be used byOrderMapper
and order mapper takesOrderEntity
with nestedUserEntity
instead ofUserWithAvatar
解决方案
我认为映射器应该在服务范围内,但我会尝试满足您的要求
你有2个选择:
您将服务和映射器都注入控制器,将实体返回到控制器并在返回响应之前使用映射器映射它
使用事件发布来发布一个事件,然后映射器捕获并生成映射。之后,您可以直接将 dto 返回给控制器或产生另一个事件。(事件发布默认是同步的,所以你不必担心并发问题)
事件发布是通过 spring 完成的,导致代码非常不耦合,其中发布者对事件订阅者一无所知,因此这两个可以在 2 个独立的层中,彼此不知道任何事情
推荐阅读
- javascript - 如何在 reactJS 中处理 2 Header?
- javascript - 我的网站上有两个谷歌广告,第一个只有在第二个存在时才会显示
- python - python闭包中的条件性能
- android - 从挂起函数异常返回对象
- python-3.x - 如何使用 child.text 函数读取带有 iso-8859-1 编码的 lxml 的简单 xml 文件
- c - 当客户端限制为 TLS 1.2 时 SQLDriverConnect 挂起
- swift - MacOS如何使用Process Class执行命令需要输入密码
- pyspark - 获取数组 Pyspark 中的第一个元素
- ruby-on-rails - 构造一个有效的路由
- python - 通过布尔索引数组的布尔索引数组,没有循环