【问题标题】:How to create xml webservice DTOs depending on conditions?如何根据条件创建 xml webservice DTO?
【发布时间】:2016-07-14 09:13:42
【问题描述】:

是否可以为 xml 网络服务创建一个全局 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() {

    }
}

【问题讨论】:

    标签: java xml spring web-services


    【解决方案1】:

    我更愿意为每个 API 版本使用定制的 DTO。为避免在将实体映射到 DTO 时使用样板代码,您可以考虑使用映射框架,例如 MapStruct

    如果您使用的是 Jackson,您可以考虑使用 JSON 视图(它们也适用于 XML)。引用Latest Jackson integration improvements in Spring 文章:

    JSON Views

    过滤序列化到 HTTP 响应正文的上下文对象有时会很有用。为了提供这样的功能,Spring MVC 现在内置了对 Jackson’s Serialization Views 的支持(从 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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-07
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多