同时使用 JSON 和 XML 的 Spring REST

问题描述 投票:0回答:4

我想提供one全面的REST API,同时支持

JSON
XML

领域模型是复杂类型,我们注意到,分别使用

JSON
XML
在同一模型上生成友好的
MappingJacksonHttpMessageConverter
JaxbMarshaller
往往会给出 可读的 XML 或可读的 JSON 1)

最好的方法是什么?

1) 由于地图、根标签和关系等对象在

json
中的建模方式与
xml
中不同,因此需要对要序列化的对象进行不同的设计,以获得整洁
json
和整洁
xml
。 jaxb 注释等实用程序只能做到这一点。


我能想到几个候选人

1)创建 json 和 xml 控制器/模型

public class Controller { 
   public Foo foo() { 
       return new Foo(); 
   } 
}

public class XmlController extends Controller {
   @Override
   public XmlFoo foo() { 
       return new new XmlFoo(super.foo()); 
   } 
}

public class JsonController extends Controller {
   @Override
   public JsonFoo foo() { 
       return new JsonFoo(super.foo()); 
   } 
}

给定一个模型对象

Foo
创建一个
JsonFoo
XmlFoo

2)编写自定义消息转换器

我尝试了这个,结果有点复杂,因为视图必须知道如何解析,例如,将

Foo
解析为
JsonFoo
才能将其序列化为可读格式。

3)让每个模型对象序列化自己,例如,

public class Foo {
    public String serialize(Serializer s) {
       return s.serialize(this);
    }
}

基于一些仲裁参数让控制器注入正确的串行器

new Foo(new FooJsonSerializer());
new Foo(new FooXmlSerializer());
java json spring rest spring-mvc
4个回答
6
投票

我正在当前项目中执行此操作,而没有使用

ContentNegotiatingViewResolver
。对于我的控制器中的one方法:

@RequestMapping(value = "/test", method = RequestMethod.GET)
@ResponseBody
public HttpEntity<BasicResponse> getBasicResponse() {
    return new HttpEntity<BasicResponse>(new BasicResponse());
}

我可以根据

Accept
请求标头接收以下输出。

接受:application/xml(类路径上需要 JAXB2)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<basicResponse>
    <errors>
        <message>test1</message>
        <message>test2</message>
    </errors>
</basicResponse>

接受:application/json(需要 Jackson 在类路径上)

{
    "errors" : ["test1", "test2"]
}

我的响应对象很简单并且使用普通注释:

package org.mypackage.response;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class BasicResponse {

    @XmlElementWrapper(name = "errors")
    @XmlElement(name = "message")
    private List<String> errors = new ArrayList<String>();

    public BasicResponse() {
        this.errors.add("test1");
        this.errors.add("test2");
    }

    public List<String> getErrors() {
        return errors;
    }

}

SpringSource spring-mvc-showcase 项目也是一个有用的资源。我认为他们将不同方法的转换分开,但我肯定是针对一种方法这样做的。

我不太清楚你的问题......但是如果你希望序列化输出不止于此,@chrylis 是正确的,因为自定义序列化器将是你的下一步。但我遇到的所有问题(可能会变得相当复杂,响应中包含嵌套对象)都可以完美转换为有效的 XML 或 JSON。


1
投票

您应该使用 ContentNegotiatingViewResolver

存在一个问题,即某些 XML 编组器无法正确映射 POJO 集合。 XStream 有解决方案(Moxy 也有吗?)。

从这里开始:

http://blog.springsource.org/2013/06/03/content-negotiation-using-views/

基本上,您使用 MappingJacksonView 和类似的 XML 视图,这是一种“假”视图,它使用 Jackson(或 XML 编组器)将 POJO 编组为正确的格式。

服务器将根据以下之一发回正确的类型:

  • HTTP Accept 标头
  • “文件类型扩展名”,例如“.json”
  • 查询字符串参数,例如“format=json”

0
投票

就省略字段而言,您可以使用注释 @JsonIgnore(对于 Jackson)和/或 @XStreamOmitField(对于 XStream)。

你尝试过这个吗:

@RequestMapping(value = "/{id}", 
method = RequestMethod.GET,
headers ={"Accept=application/json,application/xml"},
produces={"application/json", "application/xml"})

0
投票

或者,您可以在 Spring 中配置

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer
        .favorParameter(true)
        .defaultContentType(MediaType.APPLICATION_JSON) 
        .mediaType("json", MediaType.APPLICATION_JSON)
        .mediaType("xml", MediaType.APPLICATION_XML);
}

http://localhost:18050/api/ping/health?format=xml

http://localhost:18050/api/ping/health?format=json

© www.soinside.com 2019 - 2024. All rights reserved.