Spring 3 を使って RESTful な Web サービスを作成する

Java™ の世界では、さまざまな方法で RESTful な Web サービスを作成することができます。JSR 311(JAX-RS) とそのリファレンス実装である Jersey を使用する人もいれば、Restlet フレームワークを使用する人、さらにはゼロの状態から実装する人もいるかもしれません。Java EE アプリケーションを作成するためのフレームワークとしてよく知られた Spring は、今や MVC レイヤーで REST をサポートしています。この記事では、RESTful な Web サービスを Spring を使って作成する方法について紹介します。Spring の API とアノテーションを使用して RESTful な Web サービスを作成する方法について、また Spring がどのような形でこの新機能を元の Spring フレームワークにシームレスに統合しているかについて学びましょう。

Yi Ming Huang, Software Engineer, IBM  

Yi Ming Huang photoYi Ming Huang は、China Development Lab で Lotus Mashups に取り組んでいるソフトウェア・エンジニアです。ポートレット/ウィジェット関連の Web 開発で経験を積んだ彼は、REST、OSGi、および Spring 技術に興味を持っています。



Dong Fei Wu, Software Engineer, IBM

Dong Fei Wu photoDong Fei Wu は China Development Lab のソフトウェア技術者であり、Lotus Mashups に関する業務を行っています。彼はポートレットやウィジェット関連の Web 開発を幅広く経験してきています。彼は WebSphere Dashboard Framework の中心的開発者でもあります。



2010年 7月 27日

はじめに

HTTP 仕様のバージョン 1.0 と 1.1 の主要な作成者の 1 人である Roy Fielding は、2000年に彼が書いた博士論文の中で REST を紹介しています。

REST (REpresentational State Transfer) スタイルのアーキテクチャーでは、リソースの表現を転送するためにリクエストとレスポンスが作成されます。リソースはグローバル ID によって識別され、この ID には通常、URI (Uniform Resource Identifier) が使われます。クライアント・アプリケーションは、HTTP メソッド (GET、POST、PUT、DELETE など) を使ってリソースまたはリソースの集合を操作します。一般的に、GET メソッドはリソースまたはリソースの集合を取得または一覧表示するために使われ、POST はリソースの作成に、PUT はリソースの更新または置換に、DELETE はリソースの削除に使われます。

例えば GET http://host/context/employees/12345 を実行した場合には、ID が 12345 の従業員の表現が取得されます。レスポンスの表現は、その従業員の詳細情報を含む XML または ATOM の場合もあり、より適切な UI を提供するための JSP/HTML ページの場合もあります。どちらの表現が表示されるかは、サーバー・サイドの実装と、クライアントが要求する MIME タイプに依存します。

RESTful な Web サービスというのは、REST の原則と HTTP を使用して実装される Web サービスです。一般的に、RESTful な Web サービスでは、ベースとなるリソースの URI、そのサービスでサポートされる表現やレスポンスの MIME タイプ、そのサービスでサポートされる操作を定義します。

この記事では、Java によるサーバー・サイドの RESTful な Web サービスを、Spring を使用して作成する方法を学びます。この記事の例で使用するものは、ブラウザー、curl、そしてリクエストを行うクライアントのための、RESTClient というFirefox プラグインです。この記事で使われているソース・コードはダウンロードすることができます。

この記事では、読者が REST の基本を理解しているものとします。REST に関する詳細については「参考文献」を参照してください。


Spring 3 での REST のサポート

Spring フレームワークで REST がサポートされる以前は、他のいくつかの実装 (Restlet、RestEasy、Jersey など) を使って Java の世界における RESTful な Web サービスを作成していました。それらの中で最も重要なものである Jersey は、JAX-RS (JSR 311) のリファレンス実装です。JSR 311 と Jersey について詳しくは「参考文献」を参照してください。

Java EE フレームワークとして広く使われている Spring では、RESTful な Web サービスを作成するためのサポートがリリース 3 で追加されました。Spring 3 での REST サポートは JAX-RS の実装ではありませんが、JAX-RS の仕様で定義されている以上の機能を持っています。この REST サポートは Spring の MVC レイヤーにシームレスに統合されており、Spring を使って作成されるアプリケーションの中に容易に取り入れることができます。

Spring での REST サポートの主な機能には、以下のようなものがあります。

  • アノテーション (@RequestMapping@PathVariable など) により、リソースの特定や URI マッピングをサポートすることができます。
  • ContentNegotiatingViewResolver により、多様な MIME タイプやコンテンツ・タイプの多様な表現をサポートすることができます。
  • 元の MVC レイヤーにシームレスに統合されており、従来と同様のプログラミング・モデルを使用することができます。

RESTful な Web サービスのサンプルを作成する

このセクションの例では、Spring 3 環境のセットアップと、Tomcat に統合可能な「Hello world」アプリケーションの作成について、順を追って説明します。次に、もっと複雑なアプリケーションを使用して、複数の MIME タイプの表現のサポートや JAXB のサポートなど、Spring 3 による REST サポートの最重要事項を紹介します。そうした概念の説明では、理解の助けとなるようにコード・スニペットを記載します。この記事のサンプル・コードはすべてダウンロードすることができます。

この記事では、読者が Spring フレームワークと Spring の MVC を理解しているものとします。

Hello World: Spring 3 の REST サポートを使う

この例の手順を追えるように開発環境をセットアップするためには、以下のものが必要です。

  • IDE: Eclipse IDE for JEE (v3.4 またはそれ以降のバージョン)
  • Java SE5 またはそれ以降のバージョン
  • Web コンテナー: Apache Tomcat 6.0 (Jetty やその他のものでも構いません)
  • Spring 3 フレームワーク (この記事の執筆時点では v3.0.3 が最新です)
  • その他のライブラリー: JAXB 2、JSTL、commons-logging

Eclipse で動的な Web アプリケーションを作成し、そのランタイムとして Tomcat 6 を設定します。次に web.xml ファイルの内容を適切なものにし、Spring の WebApplicationContext を有効にします。この例では、Spring Bean の構成を 2 つのファイルに分散しており、rest-servlet.xml は MVC/REST 関連の構成を処理し、rest-context.xml はサービス・レベルの構成 (データ・ソース Bean など) を処理します。リスト 1 は web.xml のうち、Spring を構成する部分のスニペットです。

リスト 1. web.xml で Spring の WebApplicationContext を有効にする
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
	/WEB-INF/rest-context.xml
</param-value>
</context-param>
	
<!-- This listener will load other application context file in addition to 
            rest-servlet.xml -->
<listener>
<listener-class>
	org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
	
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>
	org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>

rest-servlet.xml ファイルの中で、MVC に関連する Spring の構成 (コントローラー、ビュー、ビュー・リゾルバー) を設定します。リスト 2 に最も重要なスニペットを示します。

リスト 2. rest-servlet.xml の中で Spring の MVC 構成を設定する
<context:component-scan base-package="dw.spring3.rest.controller" />

<!--To enable @RequestMapping process on type level and method level-->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

<!--Use JAXB OXM marshaller to marshall/unmarshall following class-->
<bean id="jaxbMarshaller"
class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
	<list>
	    <value>dw.spring3.rest.bean.Employee</value>
	    <value>dw.spring3.rest.bean.EmployeeList</value>
	</list>
</property>
</bean>

<bean id="employees" class=
"org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg ref="jaxbMarshaller" />
</bean>

<bean id="viewResolver" class=
"org.springframework.web.servlet.view.BeanNameViewResolver" />

以下は上記コードの各部分の説明です。

component-scan
Spring のアノテーションを持つクラスに対する自動スキャンを有効にします。
実際には、component-scan はコントローラー・クラスで定義された @Controller アノテーションを検出するために使われます。
DefaultAnnotationHanlderMappingAnnotationMethodHandlerAdapter
クラスやメソッドの @ReqeustMapping アノテーションを Spring で処理させるための Bean です。
このアノテーションについては次のセクションで詳しく説明します。
Jaxb2Mashaller
JAXB 2 を使って OXM (Object XML Mapping) を行うマーシャラーとアンマーシャラーを定義します。
MashallingView
Jaxb2Mashaller を利用する XML 表現のビューを定義します。
BeanNameViewResolver
ユーザーが指定する Bean の名前を使ってビュー・リゾルバーを定義します。
この例では「employees」という名前の MarshallingView を使います。

これで Spring 関係の構成は終わりです。次のステップでは、ユーザー・リクエストを処理するコントローラーを作成します。リスト 3 はコントローラー・クラスを示しています。

リスト 3. dw.spring3.rest.controller パッケージの EmployeeController
@Controller
publicclass EmployeeController {
@RequestMapping(method=RequestMethod.GET, value="/employee/{id}")
public ModelAndView getEmployee(@PathVariable String id) {
	Employee e = employeeDS.get(Long.parseLong(id));
returnnew ModelAndView(XML_VIEW_NAME, "object", e);
}
}

@RequestMapping アノテーションは Spring の REST 機能にとっての鍵です。@RequestMapping アノテーションは、アノテーションが付けられたメソッドによって、どの HTTP メソッド (RequestMethod.GET) と、どの URI (/employee/{id}) を処理するのかを指定します。以下の点に注意してください。

  • {id} というプレースホルダーの場合、{} の中の値は @PathVariable アノテーションを使ってメソッド・パラメーターの中に注入されます。
  • XML_VIEW_NAME は employees です。これは rest-servlet.xml の中で定義されたビューの名前です。
  • employeeDS は単純なメモリー・ベースのデータ・ソースですが、この実装についてはこの記事では説明しません。

この Web アプリケーションを Tomcat に公開します。この時点でブラウザーを開き、URL として http://<host>:<port>/<appcontext>/service/employee/1 を入力します。ブラウザーには、ID が 1 の従業員の XML ビューが表示されるはずです。

先に進み、Spring の REST サポートに関する機能についてさらに学びましょう。

メソッド

リソースの操作には、GET、POST、PUT、DELETE などの HTTP メソッドを使います。先ほど、GET メソッドを使って従業員情報を取得する方法を学びました。今度は POST、PUT、DELETE について学びます。

@RequestMapping アノテーションの機能を使うと、さまざまなメソッドを処理するコードは非常に似たものになります。リスト 4 は EmployeeController クラスのコード・スニペットを示しています。

リスト 4. dw.spring3.rest.controller の EmployeeController
@RequestMapping(method=RequestMethod.POST, value="/employee")
public ModelAndView addEmployee(@RequestBody String body) {
	Source source = new StreamSource(new StringReader(body));
	Employee e = (Employee) jaxb2Mashaller.unmarshal(source);
	employeeDS.add(e);
returnnew ModelAndView(XML_VIEW_NAME, "object", e);
}

@RequestMapping(method=RequestMethod.PUT, value="/employee/{id}")
public ModelAndView updateEmployee(@RequestBody String body) {
	Source source = new StreamSource(new StringReader(body));
	Employee e = (Employee) jaxb2Mashaller.unmarshal(source);
	employeeDS.update(e);
returnnew ModelAndView(XML_VIEW_NAME, "object", e);
}

@RequestMapping(method=RequestMethod.DELETE, value="/employee/{id}")
public ModelAndView removeEmployee(@PathVariable String id) {
	employeeDS.remove(Long.parseLong(id));
	List<Employee> employees = employeeDS.getAll();
	EmployeeList list = new EmployeeList(employees);
returnnew ModelAndView(XML_VIEW_NAME, "employees", list);
}

以下は上記コードの各部分の説明です。

  • RequestMethod.<HTTP メソッド> の値は、アノテーションが付けられたメソッドによって、どの HTTP メソッドを処理するのかを指定します。
  • @RequestBody によって、HTTP リクエストの本体の内容がパラメーターとして注入されます。

    この例では、HTTP リクエストの本体は従業員を表現する XML データです。ここでは JAXB 2 を使って XML を Java Bean にアンマーシャリングし、その Bean を永続化します。リクエストの本体のサンプルは以下のようなものです。

    <employee><id>3</id><name>guest</name></employee>
  • メソッド・パラメーターに注入可能な他の有用なアノテーションには、@PathVariable@RequestParm などがあります。Spring のドキュメントにはアノテーションの完全なリストがあります (「参考文献」を参照)。

リソースの集合

通常はリソースの集合も操作する必要があります。例えば、単に 1 人の情報だけではなく、すべての従業員の情報を取得する必要があるかもしれません。この実装方法は先ほどのケースと同様です。必要なことは URI を /employee から /employees に変更することだけです。employee を複数形にすることで、集合というセマンティクスが見事に表現されます。リスト 5 はその実装方法を示しています。

リスト 5. EmployeeController の getAllEmployees
@RequestMapping(method=RequestMethod.GET, value="/employees")
public ModelAndView getEmployees() {
	List<Employee> employees = employeeDS.getAll();
	EmployeeList list = new EmployeeList(employees);
returnnew ModelAndView(XML_VIEW_NAME, "employees", list);
}

Employee 集合のラッパー・クラスを宣言する必要があります。このラッパー・クラスは JAXB 2 にとって必要なクラスです。JAXB 2 はラッパー・クラスがないと java.util.List クラスを適切にマーシャリングすることができないからです。リスト 6 は EmployeeList クラスを示しています。

リスト 6. dw.spring3.rest.bean の EmployeeList クラス
@XmlRootElement(name="employees")
publicclass EmployeeList {
privateint count;
private List<Employee> employees;

public EmployeeList() {}
	
public EmployeeList(List<Employee> employees) {
this.employees = employees;
this.count = employees.size();
	}

publicint getCount() {
return count;
	}
publicvoid setCount(int count) {
this.count = count;
	}
	
	@XmlElement(name="employee")
public List<Employee> getEmployees() {
return employees;
	}
publicvoid setEmployees(List<Employee> employees) {
this.employees = employees;
	}
	
}

コンテンツ・ネゴシエーション

REST サービスのもう 1 つの共通機能として、REST サービスでは、リクエストに従ってさまざまな表現を生成することができます。例えば、クライアントが全従業員の HTML 表現またはテキスト表現を要求した場合、サーバーはユーザーに対して整形式の HTML ページを生成する必要があります。クライアントが従業員のアプリケーション表現または XML 表現を要求した場合、サーバーは XML による結果を生成する必要があります。その他、よく使われる表現形式には ATOM や PDF があります。

Spring 3 には、ContentNegotiatingViewResolver という新しいビュー・リゾルバーが導入されています。このリゾルバーは、リクエストのコンテンツ・タイプ (リクエスト・ヘッダーの Accept プロパティー) または URI 接尾辞に従ってビュー・リゾルバーを切り替えることができます。下記の例では ContentNegotiatingViewResolver を使って複数の表現のサポートを実装しています。

rest-servlet.xml ファイルの中で、元々定義されている viewResolver をコメントアウトし、代わりに ContentNegotiatingViewResolver を使用します (リスト 7)。

リスト 7. コンテンツ・ネゴシエーションを定義する
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
	<map>
	<entry key="xml" value="application/xml"/>
	<entry key="html" value="text/html"/>
	</map>
</property>
<property name="viewResolvers">
	<list>
	<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
	<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<property name="viewClass" value=
"org.springframework.web.servlet.view.JstlView"/>
		<property name="prefix" value="/WEB-INF/jsp/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
	</list>
</property>
</bean>

この定義は、リクエストのコンテンツ・タイプとして application/xmltext/html の 2 つを処理できることを示しています。またこのコードは 2 つのビュー・リゾルバーを定義しており、BeanNameViewResolver は application/xml を処理し、UrlBasedViewResolver は text/html を処理します。

実際には、ブラウザーに http://<host>:<port>/<appcontext>/service/employees が入力されると、ブラウザーは従業員の text/html 表現を要求します。すると UrlBasedViewResolver が有効になり、Spring はビューとして /WEB-INF/jsp/employees.jsp を選択します。リクエスト・ヘッダーに Accept:application/xml を追加してリクエストを呼び出すと、BeanNameViewResolver が有効になります。リスト 5 のコードの場合、employees という名前のビューを使って表現しますが、これは先ほど定義された JAXB 2 マーシャラーのビューです。

getAllEmployees() のコントローラー・コードは変わりません。employees.jsp ページは employees という名前のモデル・オブジェクトを使ってページのレンダリングを行います。リスト 8 は employees.jsp のコード・スニペットです。

リスト 8. /WEB-INF/jsp の employees.jsp
<table border=1>
	<thead><tr>
		<th>ID</th>
		<th>Name</th>
		<th>Email</th>
	</tr></thead>
	<c:forEach var="employee" items="${employees.employees}">
	<tr>
		<td>${employee.id}</td>
		<td>${employee.name}</td>
		<td>${employee.email}</td>
	</tr>
	</c:forEach>
</table>

REST サービスと通信するクライアント

ここまでの段階で作成したものは、従業員に対する CRUD (Create、Read、Update、Delete) 操作をサポートする単純で RESTful な Web サービスでした。このセクションでは、このサービスと通信する方法について説明します。ここでは curl を使って REST サービスをテストします。

RESTClient という Firefox プラグインを使って REST サービスをテストすることもできます。RESTClient には使いやすくて優れた UI があります。ダウンロードについては「参考文献」を参照してください。

curl を使う

curl は、HTTP/HTTPS プロトコルを使ってサーバーにリクエストを送信するためによく使われるコマンドライン・ツールです。curl は任意の HTTP メソッドを使ってコンテンツを送信できるため、RESTful な Web サービスと通信する上で便利なツールです。curl は Linux® と Mac® にユーティリティーとして組み込まれています。Windows® プラットフォームの場合には、curl をダウンロードすることができます (「参考文献」を参照)。

全従業員の情報が取得されるように、最初の curl コマンドを初期化するためには、以下の内容を入力します。

curl –HAccept:application/xml 

http://localhost:8080/rest/service/employees

このコマンドに対するレスポンスは XML であり、全従業員の情報が含まれています (図 1)。

図 1. 全従業員の情報の XML 表現
従業員の名前、ID、E メール・アドレスの XML 出力

また、上述の URL にブラウザーでアクセスすることもできます。その場合には、Accept ヘッダーで text/html が指定されるため、employees.jsp で定義された表が表示されます。図 2 はその例を示しています。

図 2. 全従業員の情報の HTML 表現
図 1 と同じデータを表形式で表現したもの

新しい従業員の情報をサーバーに POST するためには、下記のコードを使用します。リスト 4addEmployee() コードはリクエストの本体を使って新しい従業員の情報を Employee オブジェクトにアンマーシャリングしています。

curl -X POST -HContent-type:application/xml --data
"<employee><id>3</id><name>guest</name><email>guest@ibm.com</employee>"
http://localhost:8080/rest/service/employee

これにより、新しい従業員の情報が追加されます。最初の例を使用して従業員リストを検証することができます。

PUT メソッドは POST メソッドと同様です。

curl -X PUT -HContent-type:application/xml --data
"<employee><id>3</id><name>guest3</name><email>guest3@ibm.com</employee>" 
http://localhost:8080/rest/service/employee/3

上記のコードは ID が 3 の従業員のデータを更新します。


まとめ

Spring 3 は MVC レイヤーで REST をサポートするようになったため、Spring の API とアノテーションを使って RESTful な Web サービスを作成することができます。この記事では、例を使って Spring 3 の新機能の使い方をいくつか説明しました。これらの例と説明から、Java によるサーバー・サイドの RESTful な Web サービスを容易に作成できるはずです。


ダウンロード

内容ファイル名サイズ
Article source codesrc.zip9KB

参考文献

学ぶために

  • REST の紹介、その他関連のリンクをウィキペディアで見てください。
  • Spring 3 のすべてを学んでください。
  • Jersey のホームページには、ダウンロード・ファイル、サンプル・コードのアーカイブ、ユーザー・ガイド、JAX-RS の API のドキュメントなどが用意されています。Jersey は、(CDDL と GPL という 2 つのライセンスに従う) オープンソースで本番品質の JAX-RS (JSR 311) リファレンス実装であり、RESTful な Web サービスの構築に使用することができます。
  • Jersey と Apache Tomcat を使って RESTful な Web サービスを作成する」(developerWorks、2009年9月) は、この記事と同じ著者による記事です。この記事では、Jersey を Apache Tomcat に統合することで、サーブレット・スタイルのサービスを RESTful なサービスにスムーズに変換する方法を解説しています。
  • JAXB リファレンス実装プロジェクトに関する資料を読んでください。

製品や技術を入手するために

  • Spring 3 をダウンロードし、またドキュメントやチュートリアルを入手してください。
  • Windows 用の curl を入手してください。
  • Firefox の RESTClient 拡張機能を入手してください。この拡張機能を利用することで、RESTful/WebDav サービスを利用したりテストしたりすることができます。
  • IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2®、Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。プロフィールで選択した情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development, SOA and web services
ArticleID=513847
ArticleTitle=Spring 3 を使って RESTful な Web サービスを作成する
publish-date=07272010