是否可以为 xml Web 服务创建全局DTO
,但其中包含条件字段?
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class MyDTO {
...
@XmlElementWrapper
@XmlElement(name = "somename")
private List<String> list;
}
现在,如果我想发布另一个版本的 Web 服务,并因此重命名@XmlElement
字段(或引入其他字段、删除一些字段等),该怎么办?
以便保留向后兼容性,但相同的对象用于"新"版本。
我也许可以这样做,我可以使用/v1
、/v2
等添加请求路径方法。但是,我如何维护单个 DTO 类,但字段以版本路径为条件呢?
还是我总是必须复制这些DTO
类并完全根据版本的需要进行修改?
@RestController
public void MyServlet {
@RequestMapping("/v1")
public MyDTO1 request1() {
}
@RequestMapping("/v2")
public MyDTO2 request2() {
}
}
我更喜欢为每个版本的API使用定制的DTO。若要在将实体映射到 DTO 时避免使用样板代码,可以考虑使用 MapStruct 等映射框架。
如果你使用的是Jackson,你可以考虑使用JSON视图(它们也可以使用XML)。引用最新的 Jackson 集成改进 in Spring 文章:
JSON 视图
有时,筛选序列化为 HTTP 响应正文的上下文对象可能很有用。为了提供这样的功能,Spring MVC 现在内置了对 Jackson 的序列化视图的支持(从 Spring Framework 4.2 开始,
@MessageMapping
处理程序方法也支持 JSON 视图)。以下示例说明了如何使用
@JsonView
根据序列化的上下文筛选字段 - 例如,在处理集合时获取"摘要"视图,以及在处理单个资源时获取完整表示形式:public class View { interface Summary {} }
public class User { @JsonView(View.Summary.class) private Long id; @JsonView(View.Summary.class) private String firstname; @JsonView(View.Summary.class) private String lastname; private String email; private String address; private String postalCode; private String city; private String country; }
public class Message { @JsonView(View.Summary.class) private Long id; @JsonView(View.Summary.class) private LocalDate created; @JsonView(View.Summary.class) private String title; @JsonView(View.Summary.class) private User author; private List<User> recipients; private String body; }
由于 Spring MVC
@JsonView
的支持,可以基于每个处理程序方法选择应该序列化的字段:@RestController public class MessageController { @Autowired private MessageService messageService; @JsonView(View.Summary.class) @RequestMapping("/") public List<Message> getAllMessages() { return messageService.getAll(); } @RequestMapping("/{id}") public Message getMessage(@PathVariable Long id) { return messageService.get(id); } }
在此示例中,如果检索所有消息,则由于使用
@JsonView(View.Summary.class)
注释的getAllMessages()
方法,仅序列化最重要的字段:[ { "id" : 1, "created" : "2014-11-14", "title" : "Info", "author" : { "id" : 1, "firstname" : "Brian", "lastname" : "Clozel" } }, { "id" : 2, "created" : "2014-11-14", "title" : "Warning", "author" : { "id" : 2, "firstname" : "Stéphane", "lastname" : "Nicoll" } }, { "id" : 3, "created" : "2014-11-14", "title" : "Alert", "author" : { "id" : 3, "firstname" : "Rossen", "lastname" : "Stoyanchev" } } ]
在Spring MVC默认配置中,
MapperFeature.DEFAULT_VIEW_INCLUSION
设置为false
。这意味着在启用 JSON 视图时,不会序列化未批注的字段或属性(如正文或收件人)。使用
getMessage()
处理程序方法(未指定 JSON 视图)检索特定Message
时,所有字段都将按预期序列化:{ "id" : 1, "created" : "2014-11-14", "title" : "Info", "body" : "This is an information message", "author" : { "id" : 1, "firstname" : "Brian", "lastname" : "Clozel", "email" : "bclozel@pivotal.io", "address" : "1 Jaures street", "postalCode" : "69003", "city" : "Lyon", "country" : "France" }, "recipients" : [ { "id" : 2, "firstname" : "Stéphane", "lastname" : "Nicoll", "email" : "snicoll@pivotal.io", "address" : "42 Obama street", "postalCode" : "1000", "city" : "Brussel", "country" : "Belgium" }, { "id" : 3, "firstname" : "Rossen", "lastname" : "Stoyanchev", "email" : "rstoyanchev@pivotal.io", "address" : "3 Warren street", "postalCode" : "10011", "city" : "New York", "country" : "USA" } ] }
只能使用
@JsonView
注释指定一个类或接口,但您可以使用继承来表示 JSON 视图层次结构(如果字段是 JSON 视图的一部分,则它也将是父视图的一部分)。例如,此处理程序方法将序列化用@JsonView(View.Summary.class)
和@JsonView(View.SummaryWithRecipients.class)
注释的字段:public class View { interface Summary {} interface SummaryWithRecipients extends Summary {} }
public class Message { @JsonView(View.Summary.class) private Long id; @JsonView(View.Summary.class) private LocalDate created; @JsonView(View.Summary.class) private String title; @JsonView(View.Summary.class) private User author; @JsonView(View.SummaryWithRecipients.class) private List<User> recipients; private String body; }
@RestController public class MessageController { @Autowired private MessageService messageService; @JsonView(View.SummaryWithRecipients.class) @RequestMapping("/with-recipients") public List<Message> getAllMessagesWithRecipients() { return messageService.getAll(); } }