web-dev-qa-db-ja.com

XML / JSONリクエストとレスポンスの受け入れ/返却-Spring MVC

XML/JSONを入力(POSTメソッド)として受け入れ、XML/JSONを(入力形式に基づいて)出力として受け入れるRESTサービスを作成する必要があります。私はこれを達成するために以下のアプローチを試みましたが、助けにはなりませんでした。 。

私のエンドポイントメソッド:

@RequestMapping(value = "/getxmljson", method = RequestMethod.POST,produces={"application/json","application/xml"},
        consumes={"application/json", "application/xml"})
public @ResponseBody Student processXMLJsonRequest(@RequestBody Student student)
        throws Exception {
    System.out.println("*************Inside Controller");
    return student;
}

POJOクラス:Student.Java

import Java.io.Serializable;
import Java.util.ArrayList;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@XmlRootElement(name = "student")
@XmlType(propOrder = {"id", "name", "graduationTime", "courses"})
@JsonPropertyOrder({"id", "name", "graduationTime", "courses"})
public class Student implements Serializable {
    private static final long serialVersionUID = 1L;

    private int id;
    private String name;
    private String graduationTime;
    private ArrayList<Course> courses = new ArrayList<Course>();

    @XmlElement
    public int getId() { return id; }
    @XmlElement
    public String getName() { return name; }
    @XmlElement
    public String getGraduationTime() { return graduationTime; }
    @XmlElement
    public ArrayList<Course> getCourses() { return courses; }

    public void setId(int value) { this.id = value; }
    public void setName(String value) { this.name = value; }
    public void setGraduationTime(String value) { this.graduationTime = value; }
    public void setCourses(ArrayList<Course> value) { this.courses = value; }

    @JsonIgnore
    public String toString() {
        return this.name + " - "
                + graduationTime == null? "Unknown" : graduationTime.toString();
    }

    public Student() {}
    public Student(int id, String name, String graduationTime) {
        this.id = id;
        this.name = name;
        this.graduationTime = graduationTime;
    }
}

POJOクラス:Course.Java

import Java.io.Serializable;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@XmlRootElement(name = "course")
@XmlType(propOrder = {"courseName", "score"})
@JsonPropertyOrder({"courseName", "score"})
public class Course implements Serializable {
    private static final long serialVersionUID = 1L;

    private String courseName;
    private Integer score;

    public @XmlElement String getCourseName() { return courseName; }
    public @XmlElement Integer getScore() { return score; }

    public void setCourseName(String value) { courseName = value; }
    public void setScore(Integer value) { score = value; }

    public Course() {}
    public Course(String courseName, Integer score) {
        this.courseName = courseName;
        this.score = score;
    }
}

spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:sws="http://www.springframework.org/schema/web-services"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:oxm="http://www.springframework.org/schema/oxm"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/web-services
        http://www.springframework.org/schema/web-services/web-services-2.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
       http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-4.0.xsd
       http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util-2.5.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing 
        infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Configure to plugin JSON as request and response in method handler -->
    <beans:bean
        class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <beans:property name="messageConverters">
            <beans:list>
                <beans:ref bean="jsonMessageConverter" />
                <beans:ref bean="xmlMessageConverter" />
            </beans:list>
        </beans:property>
    </beans:bean>

    <!-- Configure bean to convert JSON to POJO and vice versa -->
    <beans:bean id="jsonMessageConverter"
        class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    </beans:bean>

    <beans:bean id="xmlMessageConverter"
        class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter">
    </beans:bean>

    <beans:bean id="restTemplate" class="org.springframework.web.client.RestTemplate">

    </beans:bean>

    <beans:bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" />
    <context:component-scan base-package="com.test" />

</beans:beans>

Json入力:

{
"id":2014,
"name":"test",
"graduationtime":"09/05/2014",
"courses":[
{
"courseName":"Math",
"score":150
},
{
"courseName":"Che",
"score":150
}
]
}

XML入力:

<?xml version="1.0" encoding="UTF-8" ?>
<student>
<id>2014</id>
<name>test</name>
<graduationTime>09/05/2014</graduationTime>
<courses>
    <courseName>Math</courseName>
    <score>150</score>
</courses>
<courses>
    <courseName>Che</courseName>
    <score>150</score>
</courses>
</student>
11
Mohan

同じコントローラで異なるデータ形式を処理するためのベストプラクティスは、フレームワークにマーシャリングとアンマーシャリングのメカニズムを把握するすべての作業を行わせることです。

ステップ1:最小限のコントローラー構成を使用

@RequestMapping(value = "/getxmljson", method = RequestMethod.POST)
@ResponseBody
public Student processXMLJsonRequest(@RequestBody Student student) {
  return student;
}

ここでconsumesproducesを指定する必要はありません。例として、この同じメソッドで将来Googleプロトコルバッファー、EDIなどの他の形式を処理したい場合があります。コントローラーをconsumesおよびproducesから解放することで、グローバル構成によりコントローラコードを変更します。

ステップ2ContentNegotiatingViewResolverの代わりにRequestMappingHandlerAdapterを使用します

  <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="defaultViews">
      <list>
        <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
      </list>
    </property>
  </bean>

ビューリゾルバに着信データの読み取り方法と書き戻し方法を決定させます。

ステップ3AcceptsおよびContent-Type HTTPヘッダーを使用

正しいHTTPヘッダー値でコントローラーを押すと、ContentNegotiatingViewResolverが適切なデータ表現を使用してデータを自動的にマーシャリングおよびアンマーシャリングします。

JSON形式でデータを交換する場合は、両方のヘッダーをapplication/jsonに設定します。代わりにXMLが必要な場合は、両方をapplication/xmlに設定します。

HTTPヘッダーを使用したくない場合(理想的です)、.jsonまたは.xmlをURLに追加するだけで、ContentNegotiatingViewResolverが残りを実行します。


私のサンプルアプリ JSONとXMLで正常に動作するコードスニペットを使用して作成したことを確認できます。

20
manish

上記のManishの答えに加えて、xmlベースの構成を使用したくない場合は、代わりにthis Java based configuration

@Bean
public ViewResolver contentNegotiatingViewResolver() {
    ContentNegotiatingViewResolver resolver =
            new ContentNegotiatingViewResolver();

    List<View> views = new ArrayList<>();
    views.add(new MappingJackson2XmlView());
    views.add(new MappingJackson2JsonView());

    resolver.setDefaultViews(views);
    return resolver;
}
9
Gagandeep Kalra

私はあなたと同じ問題に直面していました。以下は私のソリューションとサンプルです。

以下に含める必要があるMaven依存関係を示します。

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.4.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.4.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.4.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>2.4.3</version>
        </dependency>

dispatcher-servlet.xml

<mvc:annotation-driven
        content-negotiation-manager="contentManager" />

<bean id="contentManager"
        class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="favorPathExtension" value="false" />
        <property name="ignoreAcceptHeader" value="false" />
        <property name="defaultContentType" value="application/json" />
        <property name="useJaf" value="false" />
    </bean>

と私の@RequestMapping(独自のリクエストマッピングを使用できます)

@RequestMapping(value = "/testXMLJSON",
            method = RequestMethod.GET, produces = {
                    MediaType.APPLICATION_XML_VALUE,
                    MediaType.APPLICATION_JSON_VALUE })
    @ResponseBody
    public ArtworkContentMessageType testXMLJSON()
    {
        //this is GS1 xml standard mapping.
        ArtworkContentMessageType resp = new ArtworkContentMessageType();
        StandardBusinessDocumentHeader standarBusinessDocumentHeader = new StandardBusinessDocumentHeader();
        resp.setStandardBusinessDocumentHeader(standarBusinessDocumentHeader );
        ArtworkContentType artWorkContent = new ArtworkContentType();
        resp.getArtworkContent().add(artWorkContent);

        return resp ;
    }

application/xmlは必須です。以下のヘッダーが必要です

Content-Type:application/xml
Accept:application/xml
0
Sh4m

各リクエストをインターセプトするフィルターを登録し、HttpServletRequestHttpServletRequestWrapperの実装にワープし、AcceptヘッダーのContent-Type値を返します。たとえば、次のようにSameInSameOutFilterという名前のフィルターを登録できます。

@Component
public class SameInSameOutFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        SameInSameOutRequest wrappedRequest = new SameInSameOutRequest((HttpServletRequest) request);
        chain.doFilter(wrappedRequest, response);
    }
}

現在のリクエストをSameInSameOutRequestでラップします:

public class SameInSameOutRequest extends HttpServletRequestWrapper {
    public SameInSameOutRequest(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getHeader(String name) {
        if (name.equalsIgnoreCase("accept")) {
            return getContentType();
        }

        return super.getHeader(name);
    }
}

このラッパーは、リクエストのContent-Type値に基づいてHttpMessageConverterを選択するようにSpring MVCに指示します。要求本文のContent-Typeapplication/xmlの場合、応答はXMLになります。それ以外の場合、応答はJSONになります。

もう1つの解決策は、各リクエストでAcceptヘッダーとContent-Typeを手動で設定し、これらのハッキングをすべて回避することです。

0
Ali Dehghani

リソースが以下のように定義されている場合

@GET
@Path("/{id}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Student getStudent(@PathParam("id") String  id) {
 return student(); // logic to retunrs student object
}

次に、リクエストには「accept」ヘッダー(「application/json」またはapplication/xml)が含まれている必要があります。
その後、jsonまたはxml形式で応答を返します。

サンプルリクエスト:

curl -k -X GET -H "accept: application/json" "https://172.17.0.5:8243/service/1.0/222"

サンプル学生クラス

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;


@XmlRootElement(name = "student")
public class Student {
    private int id;
    private String name;
    private String collegeName;
    private int age;
    @XmlAttribute
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @XmlElement
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @XmlElement
    public String getCollegeName() {
        return collegeName;
    }

    public void setCollegeName(String collegeName) {
        this.collegeName = collegeName;
    }

    public int getAge() {
        return age;
    }
    @XmlElement
    public void setAge(int age) {
        this.age = age;
    }

}