有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

REST java中的通用响应处理

我已经创建了如下的REST响应

@XmlRootElement(name = "customer_info")
@JsonIgnoreProperties(value = { "map" })
public class Customer {
private String name;
private Integer id;
private long time;
private Map<String, Object> map = new TreeMap<>(); 
@JsonAnyGetter 
public Map<String, Object> getMap() {
    return map;
}

@JsonAnySetter
public void setMap(String name, Object values) { 
    this.map.put(name, values); 
    }
}

我想用附加参数动态创建这个响应。后端返回一个映射,该映射将包含该属性的附加属性

<customer_info>
<name></name>
<id></id>
<!--The below will have dynamic prop based on key-->
<dynamic1></dynamic1>
<dynamic2></dynamic2>
</customer_info>

应用程序配置

ResourceConfig config = new DefaultResourceConfig();               
 config.add(resources);
 Map<String, MediaType> type = config.getMediaTypeMappings()                
 type.put("json", MediaType.APPLICATION_JSON_TYPE);
 type.put("xml", MediaType.APPLICATION_XML_TYPE);
 servletHandler.addServlet(new ServletHolder(new ServletContainer(config)), "/*");

当我添加地图时,xml结构如下所示,这是不正确的。我需要上面的xml结构。有人能指导我如何实现这一点吗

此外,XML元素的名称应与映射中的键相同。JSON响应工作正常,但xml结构不正确

   <customer_info>
    <name></name>
    <id></id>
    <!--The below will have dynamic prop based on key-->

    <map>
        <entry>
           <key>dummy_param1</key>
           <value>11</value>
        </entry>
        <entry>
            <key>dummy_param2</key>
            <value>10</value>
        </entry>
    <map>
 </customer_info>

我使用Jersey作为REST框架,并在Jetty服务器上运行。 我正在使用该提供商,并使用springs和REST服务注册它

<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/>
<bean class="com.dummy.CustomerService"/>
<bean class="com.dummy.Service2"/>
<bean class="com.dummy.Service3"/>

库gradle配置如下所示:

 "org.codehaus.jackson:jackson-core-asl:1.9.2",
    "org.codehaus.jackson:jackson-jaxrs:1.9.2",
    "org.codehaus.jackson:jackson-mapper-asl:1.9.2", 
    "org.codehaus.jackson:jackson-xc:1.9.2",
    "com.sun.jersey:jersey-client:1.12",
    "com.sun.jersey:jersey-core:1.12",
    "com.sun.jersey:jersey-json:1.12",
    "com.sun.jersey:jersey-server:1.12",
    "com.sun.jersey:jersey-servlet:1.12",
    "org.codehaus.jettison:jettison:1.1",
    "javax.ws.rs:jsr311-api:1.1.1",
    "com.sun.jersey.contribs:jersey-apache-client:1.12",
    "com.sun.jersey.contribs:jersey-apache-client4:1.12",
    "com.sun.jersey.contribs:jersey-multipart:1.12",
    "com.sun.jersey:jersey-client:1.12",
    "com.sun.jersey:jersey-core:1.12",
    "com.sun.jersey:jersey-json:1.12",
    "javax.ws.rs:jsr311-api:1.1.1",
    "org.codehaus.jackson:jackson-core-asl:1.9.2",
    "org.codehaus.jackson:jackson-jaxrs:1.9.2",
    "org.codehaus.jackson:jackson-mapper-asl:1.9.2",
    "org.codehaus.jackson:jackson-xc:1.9.2",
    "javax.servlet:javax.servlet-api:3.1.0",
   "org.eclipse.jetty:ecs-jetty-server:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-util:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-servlet:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-servlets:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-http:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-security:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-io:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-continuation:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-deploy:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-webapp:9.4.0.v20161208",
   "org.eclipse.jetty:jetty-xml:9.4.0.v20161208"

还有人可以建议如何修复上述问题吗? 提前谢谢


共 (1) 个答案

  1. # 1 楼答案

    使用JAXB是不可能的,但是如果您想切换到使用Jackson for XML,那么您很容易实现这一点。你需要做的就是用@JsonAnyGetter注释bean中的Mapgetter。这将导致Jackson将映射键序列化为XML中的普通元素。这是一个测试

    @Path("jackson-xml")
    public class JacksonXmlResource {
    
        @GET
        @Produces("application/xml")
        public Response get() {
            Model model = new Model();
            model.setProp("foo", "bar");
            model.setProp("name", "Paul");
            return Response.ok(model).build();
        }
    
    
        public static class Model {
            private Map<String, Object> props = new HashMap<>();
    
            @JsonAnyGetter
            public Map<String, Object> getProps() {
                return this.props;
            }
    
            @JsonAnySetter
            public void setProp(String key, Object value) {
                this.props.put(key, value);
            }
        }
    } 
    

    这将产生以下XML

    <Model>
      <foo>bar</foo>
      <name>Paul</name>
    </Model>
    

    要使用Jackson for XML,需要执行以下操作:

    1. 添加Jackson依赖项并删除(排除)JAXB提供程序

      <dependency>
          <groupId>org.glassfish.jersey.containers</groupId>
          <artifactId>jersey-container-servlet</artifactId>
          <exclusions>
              <exclusion>
                  <groupId>org.glassfish.jersey.media</groupId>
                  <artifactId>jersey-media-jaxb</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      <dependency>
          <groupId>com.fasterxml.jackson.jaxrs</groupId>
          <artifactId>jackson-jaxrs-xml-provider</artifactId>
          <version>${jackson2.version}</version>
      </dependency>
      

      您应该将JAXB提供程序从jersey-container-servlet依赖项中排除,该依赖项应该已经存在于您的项目中。这个${jackson2.version}应该是您当前在项目中使用的任何版本的Jackson。如果你对Jackson没有任何明确的依赖关系,但是正在使用jersey-media-json-jackson,那么找出吸引你的是什么版本的Jackson。您要确保没有任何冲突的版本

    2. 您需要向Jersey注册JacksonJaxbXMLProvider

      public AppConfig extends ResourceConfig {
          public AppConfig() {
              register(JacksonJaxbXMLProvider,class);
          }
      }
      

    完成这两件事后,它应该会起作用

    使用Jackson for XML最酷的一点是,用于JSON的Jackson注释也可以用于XML,比如@JsonProperty。Jackson也理解JAXB注释(大多数)。因此,当您从JAXB迁移到Jackson时,您可能只需要保持JAXB注释不变。就道具顺序而言,它将不适用于动态属性,仅适用于已定义的属性

    另见

    • 如果您想为XML配置Jackson,请看一下this post,在这里我提到使用ContextResolver<XmlMapper>

    更新

    如果无法向项目中添加任何新的依赖项,那么另一种方法就是使用org.w3c.domapi(标准Java类)动态创建XML。这将是更冗长和更多的工作,但它会让你得到你想要的。参见this post了解一些解释。下面是一个例子。添加评论应该很容易理解

    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.WebApplicationException;
    import javax.ws.rs.core.Response;
    import javax.ws.rs.core.StreamingOutput;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.transform.OutputKeys;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    
    @Path("dom-api")
    public class DomXmlResource {
    
        @GET
        @Produces("application/xml")
        public Response getXml() throws Exception {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
    
            Document doc = docBuilder.newDocument();
    
            // create root element
            Element rootEl = doc.createElement("Model");
            doc.appendChild(rootEl);
    
            Model model = new Model();
            model.setProp("foo", "bar");
            model.setProp("name", "Paul");
            model.setValue("FooBar");
    
            // set static defined properties
            Element valueEl = doc.createElement("value");
            valueEl.appendChild(doc.createTextNode(model.getValue()));
            rootEl.appendChild(valueEl);
    
            // set dynamic properties
            for (Map.Entry<String, Object> entry: model.getProps().entrySet()) {
                Element dynamicEl = doc.createElement(entry.getKey());
                dynamicEl.appendChild(doc.createTextNode(String.valueOf(entry.getValue())));
                rootEl.appendChild(dynamicEl);
            }
    
            // return StreamingOutput so we can just stream the
            // XML results without having to store the String into memory.
            StreamingOutput entity = new StreamingOutput() {
                @Override
                public void write(OutputStream out)
                        throws IOException, WebApplicationException {
                    try {
                        // write the XML structure to the output stream.
                        Transformer transformer = TransformerFactory.newInstance()
                                .newTransformer();
                        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
                        StreamResult result = new StreamResult(out);
                        DOMSource source = new DOMSource(doc);
                        transformer.transform(source, result);
                        out.flush();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
    
            return Response.ok(entity).build();
        }
    
        public static class Model {
            private String value;
            private Map<String, Object> props = new HashMap<>();
    
            public String getValue() {
                return this.value;
            }
    
            public void setValue(String value) {
                this.value = value;
            }
    
            public Map<String, Object> getProps() {
                return this.props;
            }
    
            public void setProp(String key, Object value) {
                this.props.put(key, value);
            }
        }
    }