为REST请求和响应创建不同的类是不是很糟糕?

我正在使用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; } 

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

从长远来看,使用定制的DTO进行请求和响应将为您提供更大的灵活性。 实际上,没有什么能阻止你使用inheritance和内部类,但我会避免它。

我在这里已经回答了类似的问题,强调了在REST API中使用DTO而不是持久性实体的好处。 下面你会发现这种方法的一些好处:

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

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

在框架工作中使用像Jackson这样的auto de / serialiser将消息有效负载转换为业务对象。

但是,您仍将使用大量业务对象。

我建议你使用JSON格式,而不是每次都创建类并返回它的实例。 但是如果你需要一个类层次结构,你可以创建一个类并放置一个存储JSON的变量。