为 REST 请求和响应创建不同的类不好吗?

2022-09-03 05:55:22

我正在一个Spring Boot项目中工作,作为我目前的实现,几乎对于每个API,我都有请求响应类。

例如:

@RequestMapping(value = "/notice", method = RequestMethod.POST)
public AddNoticeResponse addNotice(@Valid @RequestBody AddNoticeRequest){
    Notice notice = ... // creating new notice from AddNoticeRequest
    noticeRepository.save(notice);
    AddNoticeResponse response = ... // creating new response instance from Notice
    return response;
} 

请求和响应类如下所示:

@Data
@AllArgsConstructor
public class AddNoticeRequest{
    private String subject;
    private String message;
    private Long timeToLive;
}
// Ommiting some annotations for brevity
public class AddNoticeResponse{
    private String subject;
    private String message;
    private Long timeToLive;
    private Date createTime;
    private String creator;
} 

我有两个问题。

  • 创建太多的类并有时命名它们让我发疯。
  • 某些请求和响应具有公共字段。

例如:有两种 : 和 :NoticeEmailNotification

public class Email {
    private String subject;
    private String message;
    private String receiver;
}

那么,我应该使用扩展公共类的内部类,还是将所有字段放入一个类中?哪个更好?

public class AddNoticeRequest {

    private String subject;
    private String message;

    class Email extends AddNoticeRequest{
        private String receiver;
    }
}
public class AddNoticeRequest{
    private String subject;
    private String message;
    private Long timeToLive;
    private String receiver;
}

然后,当客户端执行添加通知的请求时,某些字段是否为 null?Email


答案 1

从长远来看,对请求和响应使用定制的 DTO 将为您提供更大的灵活性。实际上,没有什么可以阻止你使用继承和内部类,但我只是避免它。

我在这里已经回答了一个类似的问题,强调了在 REST API 中使用 DTO 相对于持久性实体的好处。您将在下面找到此方法的一些优点:

  • DTO 可以根据您的需求进行定制,并且在仅公开持久性实体的一组属性时非常有用。您不需要@XmlTransient@JsonIgnore等批注来避免某些属性的序列化。
  • 通过使用DTO,您将避免持久性实体中的大量注释,也就是说,您的持久性实体不会因与持久性相关的注释而膨胀;
  • 您将完全控制在创建或更新资源时收到的属性;
  • 如果您使用Swagger来记录您的REST API,则可以使用@ApiModel@ApiModelProperty注释来记录您的API模型,而不会弄乱您的持久性实体;
  • 您可以为 API 的每个版本设置不同的 DTO;
  • 在映射关系时,您将拥有更大的灵活性;
  • 您的 DTO 可以包含 HATEOAS 的链接列表。这是不应该添加到持久性对象中的那种东西。
  • 您可以使用 MapStruct 等映射框架将 REST API DTO 与持久性对象进行映射。

答案 2

不要对 req/resp 对象进行子类化。

在帧工作中使用像 Jackson 这样的自动反序列化程序,将消息负载转换为业务对象。

但是,您最终仍将得到大量的业务对象。