レベル: 中級 Rajeev Hathi, Senior Software Consultant Naveen Balani, Software Architect,
IBM
2008年 09月 25日 オープンソースの Web サービス・フレームワーク、Apache CXF を使って、Spring Bean として定義した RESTful な Web サービスを作成してください。この記事では、REST (Representational State Transfer) アーキテクチャーの機能とこのアーキテクチャーを使用した場合の利点を探り、CXF の REST API を使うと簡単に RESTful なサービスを開発できることを説明します。
はじめに
この記事で構築するのは注文用アプリケーションで、アプリケーションの機能は CXF と Spring を使用した RESTful な Web サービスとして公開します。この Web サービスは注文リソースに対して read 操作と add 操作を行います。この記事を最後まで読めば、REST アーキテクチャー・スタイルの概念と機能を適用して、CXF ベースの REST API を使って RESTful な Web サービスを構築および開発できるようになっているはずです。
システム要件
この記事のサンプル・コードを実行するには、お使いのマシンに必ず以下のソフトウェアをインストールして、セットアップしてください。
- Java™ 5 以降
- Tomcat 5 以降
- Ant ビルド・ツール
- CXF バイナリー・ディストリビューション 2.1
上記のディストリビューションをインストールしたら、以下の環境変数を設定します。
- JAVA_HOME (Java 用)
- CATALINA_HOME (Tomcat 用)
- ANT_HOME (Ant 用)
- CXF_HOME (CXF 用)
一例として、CXF_HOME=C:\apache-cxf-2.1 と設定し、PATH 環境変数に以下の内容を追加します。
- JAVA_HOME\bin
- CATALINA_HOME\bin
- ANT_HOME\bin
REST -- Web アーキテクチャー
Web サービスは極めて複雑になり得ます。それは、Web サービスの開発に伴って実装しなければならない WSDL (Web Services Description Language) や SOAP などといった各種のインフラストラクチャー・コンポーネントは、さらに他のさまざまな標準に結び付けられているためです。Web サービス・ソリューションを提供するすべての Web サーバーには、堅牢な Web サービス・インフラストラクチャー・モデルを作成するという点から多大な投資が必要になってきます。また、開発者の立場からすると、技術を習得するのがますます難しくなってきています。しかし恐れることはありません。REST が救いの手を差し伸べてくれます。
RESTful な Web サービスは単純な XML-over-HTTP サービスです。通常の Web サービスではプロバイダーとコンシューマーの間で定義し、交渉しなければならない契約がさまざまにあります。しかし RESTful なサービスはそれとは異なり、データを単純な XML フォームにカプセル化して、まさに Web サーバーに対して Web ページをリクエストするのと同じように HTTP で転送します。
REST は実装や標準というよりはむしろアーキテクチャーです。REST アーキテクチャー・スタイルは Web リソースに関連付けられます。Web リソースとはつまり、URI (Uniform Resource Indicator) で識別される表現 (例えば、http://myweb.com/myresource) で、注文、顧客、従業員などの永続エンティティーにすることもできます。クライアントは URI を使用してリソースに問い合わせを行ったり、リソースを更新したりするため、クライアントによってそのリソース表現の状態は変化します。簡単に言うと、クライアント・プログラムはさまざまな HTTP メソッドと URI により Web リソースにアクセスしたり、Web リソースを更新、追加、または削除したりすることができるため、それによってリソース表現の状態も変わるということです。使用する HTTP メソッドには、GET、POST、PUT、および DELETEがあります。
要するに REST は、ユーザーが Web リソースでの操作を Web サービス・スタイルで HTTP リクエスト・メソッドを使って起動するための標準的な方法を規定する 1 つの仕様に過ぎません。REST は HTTP と密接に関連し、メソッド、ヘッダー、タイプをはじめとする HTTP 機能のすべてを利用します。
REST と CXF
CXF は、Web サービスを手軽に構築および開発できるようにする単純な API を提供するオープンソースの Web サービス・フレームワークです。この連載の第 1 回では、Spring ベースの CXF 構成を使用すると簡単に Web サービスを開発できることを説明しました。この連載第 2 回では、RESTful なサービスを開発するのも同じく簡単だということを説明します。
CXF が提供する RESTful なスタイルの Web サービス実装では、以下の 3 つを利用することができます。
- JAX-RS (JSR-311)
- HTTP バインディング
- JAX-WS (Java API for XML Web Services) の
Provider および Dispatch API
注文用アプリケーション
ここからは、ユーザーが注文を作成し、その詳細を読み取ったり、表示したりできる注文用アプリケーションを作成します。これらの関数を呼び出し、注文用アプリケーションを管理するために使用するのは、CXF による RESTful なアーキテクチャー・スタイルです。アプリケーションを開発する前に、以下のユースケースを定義しておきます。
- ユーザーが注文を作成する (固有の注文 ID を生成)。
- ユーザーが注文の詳細内容を (注文 ID をベースに) 照会する。
- ユーザーがすべての注文を照会する。
それぞれの操作は、Web サービスを呼び出す一般的な方法として、URI を使用して呼び出されます。各操作は GET、POST、PUT、DELETE のうち、いずれかの HTTP リクエスト・メソッドに関連付けられます。この API は JRA (Java Rest Annotation) を使用して、操作と HTTP/URI 動詞の組み合わせをマッピングします。JRA/動詞の組み合わせは、表 1 のとおりです。
表 1. JRA/動詞のマッピング・テーブル
| JRA | HTTP リクエスト・メソッド | 動詞 |
|---|
| @Get | GET | 取得 | | @Post | POST | 追加/作成 | | @Put | PUT | 更新 | | @Delete | DELETE | 削除 |
RESTful なサービスを開発する
RESTful な Web サービスを開発するには、まず SEI (Service Endpoint Interface) と実装クラスを作成し、続いてこの 2 つを Spring ベースの CXF 構成ファイルを使用して接続します。実行するステップは以下のとおりです。
- SEI を作成して REST アノテーションを付けます。
- 実装クラスを作成します。
- beans.xml を作成し、HTTP バインディングを使用してサービス・クラスを Spring Bean として定義した後、JAX-WS エンドポイントとして公開します。
- web.xml を作成します。
ここで作成するのは OrderProcess という名前の SEI で、この SEI がリソース表現インターフェースとして機能します。Order クラスは、リソース・クラスの 1 つです。リスト 1 に、OrderProcess SEI を記載します。
リスト 1. OrderProcess SEI
@WebService(targetNamespace = "http://demo.order")
public interface OrderProcess {
// Get all the orders
@Get
@HttpResource(location = "/orders")
@WebResult(name = "Orders")
public Orders getOrders();
// Get order data based on the specified order ID
@Get
@HttpResource(location = "/orders/{id}")
public Order getOrder(@WebParam(name = "GetOrder") GetOrder getOrder);
// Add an order
@Post
@HttpResource(location = "/orders")
public void addOrder(@WebParam(name = "Order") Order order);
}
|
OrderProcess SEI には以下の 3 つのメソッドがあります。
getOrder は、指定された注文 ID をベースに単一の注文データを返します。
getOrders は、すべての注文を返します。
addOrder は、注文を追加するために使用します。このメソッドは Order Bean を引数に取ります。
上記の 3 つのメソッドは REST アノテーションを使用して定義し、URI で識別してください。getOrder メソッドと getOrders メソッドには @GET アノテーションを使用し、addOrder メソッドには @POST を使用します。メソッドのそれぞれを識別する手段は、@HttpResource アノテーションによって定義した URI です。URI のマッピングは表 2 のようになります。
表 2. メソッド/URI マッピング・テーブル
| メソッド | URI |
|---|
getOrder | /orders/{id} | getOrders | /orders | addOrder | /orders |
これで、OrderProcessImpl 実装クラスを作成する準備が整いました (リスト 2 を参照)。
リスト 2. OrderProcessImpl サービスの実装
@WebService(endpointInterface = "demo.order.OrderProcess")
public class OrderProcessImpl implements OrderProcess {
Map<String, Order> orders = new HashMap<String, Order>();
private int i;
public Orders getOrders() {
Orders o = new Orders();
o.setOrder(orders.values());
return o;
}
public Order getOrder(GetOrder order) {
String orderID = order.getId();
return orders.get(orderID);
}
public void addOrder(Order order) {
String orderID = "ORD0" + (++i);
// Added as a POST request
String customerName = order.getName();
Order newOrder = new Order();
newOrder.setOrderID(orderID);
newOrder.setName(customerName);
orders.put(orderID, newOrder);
System.out.println("Order added successfully");
}
}
|
REST インターフェースが用意できたので、その実装内容を見ていきましょう。OrderProcessImpl クラスは SEI を実装するため、それによって SEI のメソッドも実装されることになります。addOrder メソッドは注文の詳細を、注文 ID と Order インスタンスがそれぞれキーとその値として設定されたハッシュマップに取り込みます。Order Bean が持つプロパティーは、注文 ID と顧客名の 2 つです。顧客名が POST リクエスト・メソッドによって追加されると、注文 ID が生成されます。getOrder メソッドは注文 ID を引数として取り、対応する注文をハッシュマップから取得してそのまま返します。一方、getOrders メソッドはハッシュマップにあるすべての注文を返します。
次のステップは、beans.xml 構成ファイルを作成することです (リスト 3 を参照)。
リスト 3. beans.xml 構成ファイル
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-http-binding.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint
id="orderProcess"
implementor="demo.order.OrderProcessImpl"
address="/"
bindingUri="http://apache.org/cxf/binding/http" >
<jaxws:serviceFactory >
<bean class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean">
<property name="wrapped" value="false" />
</bean>
</jaxws:serviceFactory >
</jaxws:endpoint >
</beans>
|
OrderProcessImpl の Bean 定義は、JAX-WS エンドポイントとしてラップされ、バインディング URI は http://apache.org/cxf/binding/http に設定されます。このバインディング URI は、サービスが HTTP バインディング・メソッドによってリソースにバインドされていることを示します。アドレスは / で、これは Web コンテキストとの相対アドレスです。JaxWsServiceFactoryBean は wrapped 属性を false に設定するように指定します。これはつまり、この Bean のリクエスト/レスポンスの XML ベースのデータの操作名は、ルート要素でラップされないことを意味します。
リスト 4. web.xml Web 構成ファイル
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
|
最後に作成するのは、CXF 構成ファイルをロードする web.xml ファイルです。このファイルを作成したら、Spring コンテキスト・ローダーを使用して構成ファイルをロードしてください。また、クライアント・プログラムからのすべてのリクエストを処理する CXFServlet を登録する必要もあります。
クライアントを開発する
POST リクエストには、クライアント・クラス Client を作成します。リスト 5 の Client クラスが、新しい注文を追加します。
リスト 5. POST リクエストを処理する Client クラス
public final class Client {
public static void main(String[] args) throws Exception {
String xml = null;
try {
// Make an HTTP connection to the server
URL u = new URL("http://localhost:8080/orderapp_rest/orders");
HttpURLConnection httpCon = (HttpURLConnection)
u.openConnection();
// Set the request method as POST
httpCon.setRequestMethod("POST");
httpCon.setDoOutput(true);
OutputStream os = httpCon.getOutputStream();
// XML encoded in UTF-8 format
OutputStreamWriter wout = new OutputStreamWriter(os, "UTF-8");
wout.write("<?xml version=\"1.0\"?>\r\n");
// Add customer name as XML fragment
wout.write("<order xmlns=\"http://demo.order\">
<name>Rajeev</name></order>r\n");
wout.flush();
// Make implicit connection to the server
httpCon.getContentLength();
httpCon.disconnect();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
|
上記のクラスは http://localhost:8080/orderapp_rest/orders に HTTP で接続し、XML データを POST リクエストとして送信します。この XML は、追加される注文の詳細で構成されます。追加されるのは顧客名で、注文 ID は自動的に生成されます。URL が呼び出されると、注文 ID と顧客名が Map コレクションに追加されます。
GET リクエストの場合は、ブラウザーで http://localhost:8080/orderapp_rest/orders/ORD01 にナビゲートするだけで注文詳細を取得することができます。すると、注文 ID ORD01 の注文データが含まれる XML 要素が表示されます。顧客が行ったすべての注文を表示する場合も、同様にブラウザーで http://localhost:8080/orderapp_rest/orders にナビゲートするだけです。
図 1 は、ブラウザーに URL として http://localhost:8080/orderapp_rest/orders/ORD01 と指定した場合の出力です。
図 1. GET リクエストの場合のブラウザー出力
まとめ
この記事では GET メソッドと POST メソッドの使用例を紹介し、REST アーキテクチャー・スタイルの機能と概念、そして CXF でこのアーキテクチャーを使用して RESTful なサービスを開発する方法を説明しました。
RESTful な HTTP は、リソースにアクセスして操作する方法に独特の概念をもたらし、Web サービス開発にまったく新しい側面を与えます。Web ベースの開発がますます一般的に使われるようになるにつれ、REST 技術は改善の一途を辿っています。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Order application | orderapp_rest.zip | 12KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
- IBM 製品の評価版をダウンロードして、DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® のアプリケーション開発ツールとミドルウェア製品を使ってみてください。
議論するために
著者について  | 
|  | Rajeev Hathi は、J2EE プラットフォームのソフトウェア・コンサルタントです。J2EE をベースとしたアプリケーションの設計を専門とする彼は、Java および J2EE 技術分野 (Web、EJB、Architect) での SUN 認証を獲得しています。IBM developerWorks には Ajax、Web サービス、DB2、XML 関連の記事で貢献しています。さらに、Java 6 の適用方法に関する本『Hands on Web Services』の共著者でもあります。彼が拠点とするのはインドのムンバイで、スポーツ観戦とロックを聴くことを趣味としています。 |
 | 
|  | Naveen Balani は、IBM India Software Labs (ISL) のアーキテクトで、ISLでは WebSphere Business Services Fabric の設計および開発作業のリーダーを務めています。新しい技術の調査に積極的な彼は、IBM developerWorks ではお馴染みの寄稿者でもあり、今まで Web サービス、ESB、JMS、SOA、アーキテクチャー、オープンソース・フレームワーク、セマンティック Web、J2ME、パーベイシブ・コンピューティング、Spring、Ajax、そしてさまざまな IBM 製品についての記事を書いています。また、『Beginning Spring Framework 2』、『Getting Started with IBM WebSphere Business Services Fabric V6.1』の共著者でもあります。 |
記事の評価
|