我通常在DTO中实现方法以将它们转换为实体.我这样做是因为我的目标是尽可能保持实体代码的整洁.然而,我收到的反馈建议,对于实体来说,接受DTO作为参数并创建实体更自然.我读了how to convert DTO to/from Entity号文章,但我读的时候也不是很理解.

DTO

public record MemberRegistRequestDto(
@NotBlank String oauthId,
@NotBlank String oauthPlatform,
@NotBlank String name,
@NotBlank String profileImg,
@NotBlank String nickname,
@NotNull int birth,
@NotBlank String gender,
@NotBlank String profession,
@NotBlank String signatureColor,
@NotBlank String contentType
) {

    public Member of() {
        return Member.builder()
                .oauthId(oauthId)
                .oauthPlatform(getOAuthProviderFromString(oauthPlatform))
                .name(name)
                .profileImg(profileImg)
                .nickname(nickname)
                .birth(birth)
                .gender(gender)
                .profession(profession)
                .signatureColor(signatureColor)
                .profileImg(profileImg)
                .build();
    }

...

}

实体


@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@Table(indexes = @Index(name = "oauth_id", columnList = "oauthId", unique = true))
public class Member extends BaseTimeEntity implements UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.ID实体)
    private Long id;
    @Column(nullable = false)
    private String oauthId;
    @Enumerated(EnumType.STRING)
    private OAuthProvider oauthPlatform;
    @Column(nullable = false)
    private String name;
    private String profileImg;
    @Column(nullable = false)
    private String nickname;
    private Integer birth;
    private String gender;
    private String profession;
    @Column(nullable = false)
    private String signatureColor;
    // 로그인 정보 식별 값, 프로필 사진, 필명, 이름, 성별, 생년월일, 이메일
    
    @OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
    private List<Adate> adates;

...

}

将DTO转换为实体(服务层)


    @Transactional
    public void registMember(MemberRegistRequestDto memberRegistRequestDto) {
        Member member = memberRegistRequestDto.of();
        memberRepository.save(member);
    }

建议让实体接受DTO作为参数.

var member = Member.of(memberRegistRequestDto);
  1. 哪一层最好?控制器或服务我实现了控制器将DTO传递给服务并将其接收回来的模式.这是因为我将控制器视为接收来自用户的输入并将其传递给服务的层.

我读了很多关于Stack Overflow的文章,但我还不能很好地理解它们.

我读过的文章:

推荐答案

解决问题的一种方法是通过映射器类.

在DTO模式中,您有域模型和DTO,前者包含所有业务逻辑类,后者是简单的POJO,只允许您在单点公开所需内容.此模式具有许多优势,例如:减少到服务器的往返行程、最大限度地减少网络开销,以及将域模型与表示层分离.

但是,要将域模型的对象转换为DTO,您应该使用映射器类.这种方法允许您将实体与DTO分离,因为实体不知道(也不应该知道)DTO的内部实现,反之亦然.这种设计也遵循得墨特尔定律(或最少知识原则),即一个阶级应该只知道它需要知道的东西.

此外,转换过程通常通过映射类在表示层进行.不过,有些人可能会争辩说,在某些场景中,控制器层仍然是实体-DTO转换的有效点.

在您的例子中,您应该有一个MemberMapper类,其中包含一个将Member实体映射到MemberRegistRequestDto DTO的服务,以及一个从MemberRegistRequestDto重新构造Member的方法.

public class MemberMapper {
    public static MemberRegistRequestDto toMemberRegistRequestDto(Member m) {
        MemberRegistRequestDto dto = new MemberRegistRequestDto();
        /* mapping logic */
        return dto;
    }

    public static Member toMember(MemberRegistRequestDto dto) {
        Member m = new Member();
        /* mapping logic */
        return m;
    }
}

这里有一篇来自Baeldung的文章,我认为它可能非常有用.它介绍了DTO模式,并提供了一个使用映射器服务的示例:https://www.baeldung.com/java-dto-pattern

Java相关问答推荐

在URL类图中表示Java swing类

如何为具有多对多关系的实体的给定SQL查询构建JPA规范?

在spring—data中自动发现native—sql查询期间遇到重复的SQL别名[id]

Exe4j创建的应用程序无法再固定在任务栏Windows 11上

DTO到实体,反之亦然,控制器和服务之间的哪一层应该处理转换?

Spring Boot 3.2.2中的@Inject和@Resource Remove

Mapstruct不能正确/完全映射属性

Jakarta CDI强制bean构造/注册遗留事件侦听器

将Spring Boot 3.2.0升级到3.2.1后查询执行错误

为什么同步数据块无效?

在学习Spring时,通过构造函数参数0表达了不满意的依赖关系

Spring Boot&;Docker:无法执行目标org.springframework.boot:spring-boot-maven-plugin:3.2.0:build-image

深度优先搜索实现:算法只向右搜索

插入中的JOOQ序列,设置为VS值

对角线填充二维数组

何时调用密封层次 struct 的switch 中的默认情况

为什么没有加载java.se模块?

Kotlin-仅替换字符串中最后一个给定的字符串

如何使用外部函数从Java中获取C++ struct 的返回值&;内存API

Eureka客户端无法使用用户/通行证注册到Eureka服务器