同一实体需要多个数据传输对象(DTO)

3

我为同一个实体使用多个数据传输对象(DTO)。
例如,我的实体:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity(name = "users")
public class User {
    @Id //(with uuid generator)
    private UUID id;
    private String firstName;
    private String lastName;
    private String password;
    private String phoneNumber;
    private Attachment photo;
}

问题在于请求和响应不同。例如,要注册,用户必须输入firstNamelastNamepasswordphoneNumber,但不包括idphoto(文件)。我写了另一个处理附件的API。

我以以下方式返回用户:
{
    "id": "c37f5b13-0698-41c8-a439-212484935567",
    "firstName": "John",
    "lastName": "Doe",
    "phoneNumber": "123456789",
    "photoUrl": "/api/attachment/3ac27460-1c60-11ec-9621-0242ac130002"
}



我的DTO:

public class UserDto {
    @Data
    public static class SignUpParams {
        private String firstName;
        private String lastName;
        private String password;
        private String phoneNumber;
    }

    @Data
    public static class SignInParams {
        private String password;
        private String phoneNumber;
    }

    @Data
    public static class ResponseParams {
        private UUID id;
        private String firstName;
        private String lastName;
        private String phoneNumber;
        private String photoUrl;
    }

    @Data
    public static class BlaParams {
        // Just the fields I want
    }
}

我认为这种方法不会返回不必要的null值,并且不会显示在Swagger Api文档中。
使用嵌套类作为DTO的做法是否正确并符合最佳实践?还是存在其他更好的选择?


2
这可能有点基于个人观点,但是在我看来,根据具体用途为同一实体使用不同的DTO是一个好主意。确切的实现方式(即独立类或静态内部类)又是另一回事,同样基于我的需求而定! - Nikos Paraskevopoulos
拥有多个DTO并没有什么问题:这既是语义化的(您的端点只知道来自原始对象的_有限数据集_,并且保持专注于有限的范围),也是类型安全的。至少对我来说,这两个点是优点。当然还有更多。顺便说一下,@Entity实际上也是一个DTO,但仅适用于JPA范围。 - terrorrussia-keeps-killing
我同意你的方法没有问题。只是想补充一下,另一个选择是使用Jackson的JSON视图 - slauth
1个回答

0

总的来说,如果你遵循面向对象编程范式,继承通常是一个不好的选择。然而,因为我们谈论的是DTOs,它们在第一位上几乎不能被视为类(相反,它们通常是没有逻辑的结构),我会放松要求。毕竟,我们很少编写只遵循一个范式的代码。

话虽如此,使用Jackson的@JsonUnwrapped可以用组合替换继承:

class UserReqDto {...}

class UserResponseDto {
   @JsonUnwrapped 
   UserReqDto submittedData;
   ...
}

@JsonUnwrapped 将封闭对象的字段嵌入到外部 JSON 中。

PS:你几乎永远不应该使用 @Data - 它实现了 hashCode()equals(),并且它使用所有字段进行比较。你在生产代码中比较 DTO 吗?如果不是,为什么需要首先实现 equals()?大多数开发人员之所以使用此注释,只是因为他们懒惰,并且对平庸的代码感到满意。


为什么继承通常是一个糟糕的选择?您能详细说明一下吗?与UserResponseDto extends UserReqDTO有什么区别? - ch1ll
1
在面向对象编程中,继承被认为是一种不良的实践。但我无法在一个段落中涵盖它,你可以查找“继承vs.组合”-关于这个主题有很多资源。 - Stanislav Bashkyrtsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接