如何根据条件创建 xml Web 服务 DTO



是否可以为 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();
    }
}

最新更新