[英]How to separate the dto mapping logic
我在代碼中組織映射方法時遇到了一些問題。 我正在 controller 層中執行映射邏輯,但某些實體需要對每個操作(插入、更新和刪除)使用不同的 dto。
我創建了一個具有 2 種類型的通用 controller:原始實體和 dto 類型。 但是在這種情況下,這會導致它使用多個 dto 表示。 我不確定創建 3 個泛型類型是否是處理此問題的好方法。
另一個問題是我的 controller 層隨着許多映射方法變得越來越大。 即使使用 ModelMapper 作為自動映射器,在某些情況下我更喜歡自己做而不是創建復雜的轉換器類。
如何組織我的 dto 映射代碼,並且不讓我的 controller 使用很多映射方法?
PS:我的項目是 rest api 與 jax-rs、cdi 和 jpa
我建議您遵循以下規則:
問候。
一種常見的方法是將 DTO 轉換邏輯拆分為自己的 class。 根據項目的大小,創建存儲庫 class 也可能有用。 這給我們留下了三個類:
該存儲庫允許我們完全隱藏 controller 中的 DTO。 相反,controller 將只處理域對象,並且根本不知道從 DTO 到域 object 的轉換。
存儲庫(假設是從FooDto
對象創建的Foo
域對象)是:
public Foo {
private long id;
private String name;
// ...getters & setters...
}
public interface FooRepository {
public List<Foo> findAll();
public Optional<Foo> findById(long id);
public Foo create(long id, String name);
public Foo update(long id, String name);
public void delete(long id);
}
DTO 轉換邏輯為:
public class FooDto {
private long id;
private String name;
// ...getters & setters...
}
public class FooDtoMapper {
public Foo fromDto(FooDto dto) {
Foo foo = new Foo();
foo.setId(dto.getId();
foo.setName(dto.getName();
return foo;
}
public FooDto toDto(Foo foo) {
FooDto dto = new FooDto();
dto.setId(foo.getId();
dto.setName(foo.getName();
return dto;
}
}
創建FooDtoMapper
,我們可以創建FooRepository
實現:
public class DatabaseFooRepository implements FooRepository {
@Inject
private DatabaseConnection dbConnection;
@Inject
private FooDtoMapper mapper;
@Override
public List<Foo> findAll() {
return dbConnection.getAllFromCollection("FOO", FooDto.class)
.stream()
.map(mapper::fromDto)
.collect(Collectors.toList());
}
// ...implement other methods
}
dbConnection
object 是從中提取 DTO 的數據庫的抽象。 在此示例中,我們可以假設getAllFromCollection("FOO", FooDto.class)
返回一個List<FooDto>
,然后我們將其 stream 並使用FooDtoMapper
object ( mapper
)轉換為List<Foo>
。 在您的項目中,這可能會替換為特定於 JPA 的代碼,但原理仍然相同:從 JPA 接口獲取 DTO,並使用mapper
object 將它們轉換為域對象。
這導致以下 controller 邏輯:
@Path("foo")
@Controller
public class FooController {
@Inject
private FooRepository repository;
@GET
public Response findAll() {
List<Foo> foos = repository.findAll();
Response.ok(foos);
}
// ...other controller methods...
}
使用這種模式,我們抽象了從 DTO 轉換為它自己的 class 的邏輯,而 controller 只負責處理域對象。
一般來說,最好有許多簡單的類來做一件事,而不是把所有的邏輯放在一個 class(就像你原來的控制器一樣)中,以期減少類的數量。 例如, FooDtoMapper
只負責從FooDto
對象轉換為Foo
對象,反之亦然。 DatabaseFooRepository
只負責從數據庫中獲取 DTO,並使用FooDtoMapper
將 DTO 轉換為域對象(即從數據庫中獲取域對象)。 最后, FooController
只負責從FooRepository
獲取域對象(即運行時的DatabaseFooRepository
)並提供必要的 REST API 元數據(即OK
)
請注意,在這種情況下, Foo
和FooDto
對象是相同的,沒有太多理由將Foo
和FooDto
對象分開(即,為什么不將Foo
對象而不是FooDto
對象存儲在數據庫中?),但是並非總是如此。 通常,域 object 和 DTO 會有所不同。 例如,域 object 可能具有必須轉換為String
或其他可以存儲在數據庫中的數據結構的貨幣金額或日期(DTO 將具有此String
字段,而域 object 將具有實際字段,例如作為貨幣或日期)。 在這種情況下,為簡單起見,我將域 object 和 DTO 設為相同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.