JerseyでのJSONサービス
JerseyでのJSONサービスの作り方に関して、
Jerseyでレスポンスとして、JSONを戻す場合、JerseyのJSONライブラリとJAXBを使います。
例えば、下のようなJSONを戻すと場合は、JAXBのクラスに構造をマッピングします。
{'category' : [{'key' : '1000', 'value' : 'AAAAA'}, {'key' : '2000', 'value' : 'BBBBB'}]}
JAXBのクラスの作成方法は、下記に記載した方法で、作成します。
JAXBに関して - クロノスの技術系ブログ
また、今回の場合、Apache Mavenのpom.xmlは、下記のようにライブラリを指定しています。
<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.18</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> <version>1.18</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-json</artifactId> <version>1.18</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-bundle</artifactId> <version>1.18</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-xjc</artifactId> <version>2.2.7</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.2.7</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-osgi</artifactId> <version>2.2.7</version> </dependency>
また、JAXBのクラスは、以前、作成したものを使います。
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"category"}) @XmlRootElement(name = "categoryResouce") public class CategoryResouce { protected List<CategoryList.Category> category; public List<CategoryList.Category> getCategory() { if (category == null) { category = new ArrayList<CategoryList.Category>(); } return this.category; } @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"key","value"}) public static class Category { protected String key; protected String value; public String getKey() { return key; } public void setKey(String value) { this.key = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } }
サービスクラスは、通常と同じく普通のクラスを作成し、Jerseyのアノテーションの@Pathを付加します。
作成したクラスへアクセスするURLがhttp://localhost:8080/rest/service/〜だとすると、
クラス名の上に、@Path("service")と下の様に定義することになります。
@Path("/service") public class JsonService { }
次にメソッドを定義します。
CategoryResouceを取得するメソッドのgetメソッドを作成する場合、
Jerseyのアノテーションの@GETと@Pathをメソッドの前に付加します。
@GETは、HTTPのGETでアクセスされることを意味し、@Pathで、URLの指定をします。
http://localhost:8080/rest/service/getで、そのメソッドへアクセスさせたいなら、
@Path("/get")と定義します。
実際の実装は、下の様な実装になります。
@Path("/service") public class JsonService { @GET @Path("/get") public CategoryResouce get() { CategoryResouce resouce = ObjectFactory().createCategoryResouce(); List<CategoryList.Category> categoryList = resouce.getCategory(); CategoryList.Category category1 = new CategoryList.Category(); category1.setKey("1000"); category1.setValue("AAAAA"); categoryList.add(category1); CategoryList.Category category2 = new CategoryList.Category(); category2.setKey("1000"); category2.setValue("AAAAA"); categoryList.add(category2); return resource; }
また、JSONPにも対応したい場合は、 JSONWithPaddingを使う必要があり、
JAXBとcallback名を JSONWithPaddingクラスで、ラップします。
@Path("/service") public class JsonService { @GET @Path("/get") public JSONWithPadding get( @QueryParam("callback") @DefaultValue("callback") String callback) { CategoryResouce resouce = ObjectFactory().createCategoryResouce(); List<CategoryList.Category> categoryList = resouce.getCategory(); CategoryList.Category category1 = new CategoryList.Category(); category1.setKey("1000"); category1.setValue("AAAAA"); categoryList.add(category1); CategoryList.Category category2 = new CategoryList.Category(); category2.setKey("1000"); category2.setValue("AAAAA"); categoryList.add(category2); return new JSONWithPadding(resource, callback); }
これで、JSONとJSONP両方に対応することができます。
ちなみに、リクエストに対して、どうちらになるかは、リクエストヘッダにより自動的に決まります。
なので、下のリクエストヘッダの場合、JSON形式で、レスポンスが戻ります。
Accept : application/json
JSONPは、下のリクエストヘッダだったら、JSONP形式で、レスポンスが戻ります。
Accept : application/javascript
それと、JSONPですが、ブラウザにより、うまくいかない場合があります。
それは、ブラウザが、クロスドメインでのアクセスに制限が掛かっているものがあり、
Access-Control-Allow-Originで、クロスドメインでのアクセスが許されていないことがあるので、
その時は、レスポンスヘッダにAccess-Control-Allow-Originを付加する必要があります。
その場合のアクセスするメソッドにHttpServletResponseを引数として、渡す必要があり、
Jerseyのアノテーションの@Contextを付加して、HttpServletResponseを渡せるようにします。
@Path("/service") public class JsonService { @GET @Path("/get") public JSONWithPadding get( @QueryParam("callback") @DefaultValue("callback") String callback, @Context HttpServletResponse response) { response.addHeader(Access-Control-Allow-Origin, "*"); ..... } }
それで、下の様な設定の意味は、Access-Control-Allow-Originに*を設定することで、
無条件で、許可される設定になります。
response.addHeader(Access-Control-Allow-Origin, "*");
あとは、アプリケーションの web.xml ファイルにサーブレット・ディスパッチャー
を下のに定義して完了です。
<servlet> <servlet-name> Jersey Service </servlet-name> <servlet-class> com.sun.jersey.spi.container.servlet.ServletContainer </servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>chronos.service.resouce</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Jersey Service</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping>