| Oracle® Fusion Middleware Oracle WebLogic Server RESTful Webサービスの開発と保護 12c (12.2.1) E69940-01 |
|
![]() 前 |
![]() 次 |
この章では、Java API for RESTful Web Services (JAX-RS)を使用して、Representational State Transfer (REST)アーキテクチャ・スタイルに従ったJava EE Webサービスを開発する方法について説明します。
この章の内容は次のとおりです:
JAX-RSは、アノテーションを使用して、RESTful Webサービスの開発を簡略化するJavaプログラミング言語APIです。JAX-RSアノテーションは実行時アノテーションです。JAX-RSリソース・クラスを含むJava EEアプリケーション・アーカイブをWebLogic Serverにデプロイする場合(第4章「RESTful Webサービス・アプリケーションの構築、パッケージ化およびデプロイ」を参照)、ランタイムによってリソースの構成、ヘルパー・クラスおよびアーティファクトの生成、クライアントへのリソースの公開が行われます。
次の各項で、RESTful Webサービスの開発について詳しく説明します。
Oracle JDeveloperを使用したRESTful Webサービスの開発の詳細は、『Oracle JDeveloperによるアプリケーションの開発』のRESTful Webサービスおよびクライアントの作成に関する項を参照してください。
表2-1に、JAX-RSアノテーションを使用してRESTful Webサービスを開発する場合に必要なタスクのサブセットの概要を示します。高度なタスクの詳細は、「高度なRESTful Webサービス・タスク」を参照してください。
|
注意: 表2-1で説明されている開発タスクに加えて、RESTful Webサービスの開発時にJersey 2.x (JAX-RS 2.0 RI)で使用できる機能の利用が必要になることもあります。主な機能のリストは、表1-2「Jersey 2.x (JAX-RS 2.0 RI)の主な機能」を参照してください。 |
表2-1 RESTful Webサービスを開発するタスクの概要
| タスク | 詳細情報 |
|---|---|
|
ルート・リソース・クラスを定義します。 |
|
|
変数を使用して |
|
|
|
|
|
必要に応じて、リクエストおよびレスポンス・メッセージをカスタマイズして、リソースが生成および消費できるMIMEメディア・タイプを指定します。 |
リクエスト・メッセージおよびレスポンス・メッセージのメディア・タイプのカスタマイズ |
|
リクエストから情報を抽出します。 |
|
|
レスポンス・コードをカスタマイズする、または追加メタデータを含めるためのカスタム・レスポンス・メッセージを構築します。 |
|
|
アプリケーション・デプロイメント・コンテキストまたは個別リクエストのコンテキストに関する情報にアクセスします。 |
|
|
新規のリソースURIを構築、または既存のリソースURIを拡張します。 |
|
|
GETリクエストの処理前に1つ以上の前条件を評価することで、潜在的に帯域幅を縮小し、サーバー・パフォーマンスを改善します。 |
|
|
WADLにアクセスします。 |
|
|
必要に応じて、 |
|
|
RESTful Webサービスを保護します。 |
第5章「RESTful Webサービスとクライアントの保護」 |
例2-1に、RESTful Webサービスの簡単な例を示します。この例の内容は次のとおりです。
helloWorldクラスは/helloworldとして定義された相対URIパスを含むリソースです。実行時に、WARファイルのコンテキスト・ルートがhttp://examples.comとして定義されている場合、リソースにアクセスするためのフルURIはhttp://examples.com/helloworldです。詳細は、「ルート・リソースおよびサブリソースの相対URIの定義」を参照してください。
sayHelloメソッドはHTTP GETメソッドをサポートします。詳細は、「受信HTTPリクエストのJavaメソッドへのマッピング」を参照してください。
sayHelloメソッドはMIMEメディア・タイプtext/plainのコンテンツを生成します。詳細は、「リクエスト・メッセージおよびレスポンス・メッセージのメディア・タイプのカスタマイズ」を参照してください。
追加の例を「RESTful Webサービスの詳細」に示します。
例2-1 簡単なRESTful Webサービスの例
package samples.helloworld;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
// Specifies the path to the RESTful service
@Path("/helloworld")
public class helloWorld {
// Specifies that the method processes HTTP GET requests
@GET
@Produces("text/plain")
public String sayHello() {
return "Hello World!";
}
}
ルート・リソース・クラスは、次の条件の1つまたは両方がtrueであるPlain Old Java Object (POJO)です。
@Pathでアノテーションが付けられている。詳細は、「ルート・リソースおよびサブリソースの相対URIの定義」を参照してください。
少なくとも1つのメソッドが@Path、または@GET、@POST、@PUT、@DELETEなどのリクエスト・メソッド指定子によりアノテーションが付けられている。リソース・メソッドはリクエスト・メソッド指定子を使用してアノテーションが付けられたリソース・クラスのメソッドです。詳細は、「受信HTTPリクエストのJavaメソッドへのマッピング」を参照してください。
リソースのクラス・レベルでjavax.ws.rs.Pathアノテーションを追加し、RESTful Webサービスの相対URIを定義します。このようなクラスはルート・リソース・クラスと呼ばれます。特定の機能をグループ化するためのサブリソースを定義するため、@Pathもルート・リソース・クラスのメソッドに追加できます。
次の項では、ルート・リソースおよびサブリソースの相対URIの定義方法について説明します。
@Pathアノテーションはリソースの相対URIを定義し、定数または変数(URIパス・テンプレートとして参照される)として定義できます。@Pathアノテーションをクラスまたはメソッド・レベルで追加できます。
URIを定数値として定義するには、定数値を@Pathアノテーションに渡します。先頭と末尾のスラッシュ(/)はオプションです。
例2-2では、リソース・クラスの相対URIが定数値/helloworldとして定義されます。
例2-2 相対URIの定数値としての定義
package samples.helloworld; import javax.ws.rs.Path; ... // Specifies the path to the RESTful service @Path("/helloworld") public class helloWorld {. . .}
URIをURIパス・テンプレートとして定義するには、1つまたは複数の変数値を@Pathアノテーションに中カッコで囲んで渡します。すると、javax.ws.rs.PathParamアノテーションを使用して、@Pathアノテーションで定義されたリクエストURIから変数情報を抽出でき、メソッド・パラメータの値を初期化できます(変数情報をリクエストURI (@PathParam)から抽出する方法を参照)。
例2-3では、リソース・クラスの相対URIが、中かっこで囲まれた変数を使用して定義されます。たとえば、/users/{username}です。
例2-3 相対URIの変数値としての定義
package samples.helloworld; import javax.ws.rs.Path; ... // Specifies the path to the RESTful service @Path("/users/{username}") public class helloWorld {. . .} }
変数をさらにカスタマイズするには、デフォルトの正規表現の"[^/]+?"を、変数定義の一部として必要な正規表現を指定することでオーバーライドできます。以下に例を示します。
@Path("users/{username: [a-zA-Z][a-zA-Z_0-9]}")
この例では、username変数は、1つの大文字または小文字で始まり、ゼロまたはそれ以上の英数字またはアンダースコア文字が続くユーザー名にのみ一致します。ユーザー名が要件に一致しない場合、404 (Not Found)レスポンスがクライアントに送信されます。
詳細は、Java EE 7 API仕様の@Pathアノテーションを参照してください。
javax.ws.rs.Pathアノテーションをリソースのメソッドに追加して、サブリソースを定義します。サブリソースによってユーザーは、リソースに対する特定の機能をグループ化できます。
例2-3で、URIのリクエスト・パスがusers/listの場合は、getUserListサブリソース・メソッドが照合され、ユーザーのリストが返されます。
基底URIは次のように構成されます。
http://myHostName/contextPath/servletURI/resourceURI
myHostName— Web サーバーにマップされるDNS名。これを、WebLogic Serverを実行しているマシン名とリクエストのリスニングに使用するポートを指定するhost:portで置き換えることができます。
contextPath—スタンドアロンWebアプリケーションの名前。Webアプリケーション名はEARファイル内のMETA-INF/application.xmlデプロイメント記述子またはWARファイルのweblogic.xmlデプロイメント記述子に指定されます。指定されない場合、デフォルトはWARファイルから.war拡張子を取り去った名前です。詳細は、『Oracle WebLogic Server Webアプリケーション、サーブレット、JSPの開発』のcontext-rootに関する項を参照してください。
servletURI—サーブレットのコンテキスト・パスの基底URIです。このパスは、表4-1で定義されているパッケージ化オプションの一部として構成されます。特に、次を実行して、サーブレットのコンテキスト・パスを定義できます。
web.xmlデプロイメント記述子を更新して、サーブレット・マッピングを定義します。
javax.ws.rs.ApplicationPathアノテーションをjavax.ws.rs.core.Applicationを拡張するクラスに追加します(定義されている場合)。
サーブレットのコンテキスト・パスが上記のオプションの両方を使用して構成されている場合、サーブレット・マッピングが優先されます。前述のオプションのいずれかを使用して、構成内にサーブレットのコンテキスト・パスを構成しない場合、WebLogic ServerによってデフォルトのRESTful Webサービス・アプリケーションのコンテキスト・パスresourcesが提供されます。詳細は、第4章「RESTful Webサービス・アプリケーションの構築、パッケージ化およびデプロイ」を参照してください。
resourceURI—リソースまたはサブリソースに対して指定された@Path値。このパスは、複数のリソースおよびサブリソースの@Path値で構成されることがあります。
例2-2では、WARファイルに対するコンテキスト・パスがrestとして定義されていて、サーブレットのデフォルトURI (resources)が有効な場合、実行時のリソースにアクセスする基底URIはhttp://myServer:7001/rest/resources/helloworldです。
例2-3では、実行時に、基底URIは変数に対して指定された値に基づき構成されます。たとえば、ユーザーがユーザー名としてjohnsmithを入力した場合、リソースにアクセスする基底URIはhttp://myServer:7001/rest/resources/users/johnsmithです。
JAX-RSはJavaアノテーションを使用して受信HTTPリクエストをJavaメソッドにマッピングします。表2-2に、同じような名前が付けられたHTTPメソッドにマッピングする、使用可能なアノテーションを示します。
表2-2 HTTPリクエストのJavaメソッドへのマッピング用javax.ws.rsアノテーション
| アノテーション | 説明 | 多重呼出し不変 |
|---|---|---|
|
|
URIにより識別されるリソースの表現をクライアントに送信します。フォーマットは、HTML、プレーン・テキスト、JPEGなどです。「リソースの表現の送信方法(@GET)」を参照してください。 |
はい |
|
|
URIで識別された特定のリソースの表現を作成または更新します。「リソースの表現の作成または更新方法(@PUT)」を参照してください。 |
はい |
|
|
URIで識別されたリソースの表現を削除します。「リソースの表現の削除方法(@DELETE)」を参照してください。 |
はい |
|
|
URIで識別された特定のリソースの表現でのアクションを作成、更新、または実行します。「リソースの表現でのアクションの作成、更新または実行方法(@POST)」を参照してください。 |
いいえ |
|
|
レスポンス・ヘッダーのみを戻し、実際のリソースは戻しません(つまり、メッセージ本文はありません)。これは、実際にダウンロードせずにリソースの特性を確認して、バンド幅を節約するのに役に立ちます。詳細は、Java EE 7 API仕様の
|
はい |
|
|
URIで識別された特定のリソースのリクエスト/レスポンス・チェーンで使用可能な通信オプションを戻します。
|
はい |
|
|
アノテーションの付けられたメソッドを使用してHTTPリクエストを処理する必要があることを示します。詳細は、Java EE 7 API仕様の |
該当なし |
次の項では、HTTPリクエストのJavaメソッドへのマッピングに使用されるJAX-RSアノテーションの詳細について説明します。
次の項に示す例は、Jersey 2.x (JAX-RS 2.0 RI)とともに提供されるブックマーク・サンプルからの抜粋です。ブックマーク・サンプルは、ユーザーやブラウザが設定したブックマークを保持するWebアプリケーションを提供します。
サンプル内のリソース・クラス、関連URIパス、各クラスにより実証されるHTTPメソッドについて、次の表にまとめます。
表2-3 Jerseyブックマーク・サンプルについて
| リソース・クラス | URIパス | 実証されるHTTPメソッド |
|---|---|---|
|
|
|
GET |
|
|
|
GET、PUT、DELETE |
|
|
|
GET、POST |
|
|
|
GET、PUT、DELETE |
ブックマーク・サンプルおよびその他のJerseyサンプルは、次のいずれかの方法でアクセスできます。
https://repo1.maven.org/maven2/org/glassfish/jersey/examples/bookmark/にあるブックマーク・サンプルにアクセスする
GitHub (https://github.com/jersey/jersey/tree/master/examples/bookmark)でブックマーク・サンプル・ソース・コードを参照する
https://repo1.maven.org/maven2/org/glassfish/jersey/bundles/jersey-examples/で、各バージョンのWebLogic Server固有のサンプル・バンドルを含め、すべてのJerseyサンプルのMavenリポジトリを参照する
javax.ws.rs.GETアノテーションは、URIにより識別されるリソースの表現をクライアントに送信します。レスポンスのエンティティ本文で戻される形式または表現は、HTML、プレーン・テキスト、JPEGなどです。詳細は、Java EE 7 API仕様の@GETアノテーションを参照してください。
例2-5では、Jerseyブックマーク・サンプルのBookmarksResourceクラスからの、アノテーションが付けられたJavaメソッドgetBookmarkAsJsonArrayが、HTTP GETリクエストを処理します。Jerseyブックマーク・サンプルの詳細は、「Jerseyブックマーク・サンプルについて」を参照してください。
例2-5 HTTP GETリクエストのJavaメソッドへのマッピング(BookmarksResourceクラス)
import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; ... public class BookmarksResource { ... @Path("{bmid: .+}") public BookmarkResource getBookmark(@PathParam("bmid") String bmid) { return new BookmarkResource(uriInfo, em, userResource.getUserEntity(), bmid); } @GET @Produces(MediaType.APPLICATION_JSON) public JSONArray getBookmarksAsJsonArray() { JSONArray uriArray = new JSONArray(); for (BookmarkEntity bookmarkEntity : getBookmarks()) { UriBuilder ub = uriInfo.getAbsolutePathBuilder(); URI bookmarkUri = ub. path(bookmarkEntity.getBookmarkEntityPK().getBmid()). build(); uriArray.put(bookmarkUri.toASCIIString()); } return uriArray; } ... }
例2-6では、Jerseyブックマーク・サンプルのBookmarkResourceクラスからの、アノテーションが付けられたJavaメソッドgetBookmarkが、HTTP GETリクエストを処理します。この例では、戻されたJSONオブジェクトの処理方法を示します。Jerseyブックマーク・サンプルの詳細は、「Jerseyブックマーク・サンプルについて」を参照してください。
例2-6 HTTP GETリクエストのJavaメソッドへのマッピング(BookmarkResourceクラス)
import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; ... public class BookmarkResource { ... @GET @Produces(MediaType.APPLICATION_JSON) public JSONObject getBookmark() { return asJson(); } ... public JSONObject asJson() { try { return new JSONObject() .put("userid", bookmarkEntity.getBookmarkEntityPK().getUserid()) .put("sdesc", bookmarkEntity.getSdesc()) .put("ldesc", bookmarkEntity.getLdesc()) .put("uri", bookmarkEntity.getUri()); } catch (JSONException je){ return null; } } }
javax.ws.rs.PUTアノテーションは、URIで識別された特定のリソースの表現を作成または更新します。詳細は、Java EE 7 API仕様の@PUTアノテーションを参照してください。
例2-7では、Jerseyブックマーク・サンプルのBookmarkResourceクラスからの、アノテーションが付けられたJavaメソッドputBookmarkが、HTTP PUTリクエストを処理し、指定したブックマークを更新します。Jerseyブックマーク・サンプルの詳細は、「Jerseyブックマーク・サンプルについて」を参照してください。
例2-7 HTTP PUTリクエストのJavaメソッドへのマッピング
import javax.ws.rs.PUT; import javax.ws.rs.Produces; import javax.ws.rs.Path; ... public class BookmarkResource { ... @PUT @Consumes(MediaType.APPLICATION_JSON) public void putBookmark(JSONObject jsonEntity) throws JSONException { bookmarkEntity.setLdesc(jsonEntity.getString("ldesc")); bookmarkEntity.setSdesc(jsonEntity.getString("sdesc")); bookmarkEntity.setUpdated(new Date()); TransactionManager.manage(new Transactional(em) { public void transact() { em.merge(bookmarkEntity); }}); } }
javax.ws.rs.DELETEアノテーションは、URIで識別された特定のリソースの表現を削除します。レスポンスのエンティティ本文ではステータス・メッセージが返されるか、または空の可能性があります。詳細は、Java EE 7 API仕様の@DELETEアノテーションを参照してください。
例2-8では、Jerseyブックマーク・サンプルのBookmarkResourceクラスからの、アノテーションが付けられたJavaメソッドdeleteBookmarkが、HTTP DELETEリクエストを処理し、指定したブックマークを削除します。Jerseyブックマーク・サンプルの詳細は、「Jerseyブックマーク・サンプルについて」を参照してください。
例2-8 HTTP DELETEリクエストのJavaメソッドへのマッピング
import javax.ws.rs.DELETE; import javax.ws.rs.Produces; import javax.ws.rs.Path; ... public class BookmarkResource { ... @DELETE public void deleteBookmark() { TransactionManager.manage(new Transactional(em) { public void transact() { UserEntity userEntity = bookmarkEntity.getUserEntity(); userEntity.getBookmarkEntityCollection().remove(bookmarkEntity); em.merge(userEntity); em.remove(bookmarkEntity); }}); } }
javax.ws.rs.POSTアノテーションは、URIで識別された特定のリソースの表現でのアクションを作成、更新、または実行します。詳細は、Java EE 7 API仕様の@POSTアノテーションを参照してください。
例2-9では、Jerseyブックマーク・サンプルのBookmarksResourceクラスからの、アノテーションが付けられたJavaメソッドpostFormが、HTTP POSTリクエストを処理し、指定した情報を更新します。Jerseyブックマーク・サンプルの詳細は、「Jerseyブックマーク・サンプルについて」を参照してください。
例2-9 HTTP POSTリクエストのJavaメソッドへのマッピング
import javax.ws.rs.POST; import javax.ws.rs.Produces; ... public class BookmarksResource { ... @POST @Consumes(MediaType.APPLICATION_JSON) public Response postForm(JSONObject bookmark) throws JSONException { final BookmarkEntity bookmarkEntity = new BookmarkEntity(getBookmarkId(bookmark.getString("uri")), userResource.getUserEntity().getUserid()); bookmarkEntity.setUri(bookmark.getString("uri")); bookmarkEntity.setUpdated(new Date()); bookmarkEntity.setSdesc(bookmark.getString("sdesc")); bookmarkEntity.setLdesc(bookmark.getString("ldesc")); userResource.getUserEntity().getBookmarkEntityCollection().add(bookmarkEntity); TransactionManager.manage(new Transactional(em) { public void transact() { em.merge(userResource.getUserEntity()); }}); URI bookmarkUri = uriInfo.getAbsolutePathBuilder(). path(bookmarkEntity.getBookmarkEntityPK().getBmid()). build(); return Response.created(bookmarkUri).build(); } }
リソースのクラス・レベルでjavax.ws.rs.Consumesまたはjavax.ws.rs.Producesアノテーションを追加し、リクエストおよびレスポンス・メディア・タイプをカスタマイズします。次の項を参照してください。
javax.ws.rs.Consumesアノテーションにより、クライアントから送信され、リソースが消費できる表現のMIMEメディア・タイプを指定できます。@Consumesアノテーションはクラスとメソッド・レベルの両方に指定でき、複数のメディア・タイプを同じ@Consumes宣言で宣言できます。
指定されたMIMEメディア・タイプを消費できるメソッドがリソース内にない場合、ランタイムはHTTP 「415 - サポートされていないメディア・タイプ」エラーを返します。
詳細は、Java EE 7 API仕様の@Consumesアノテーションを参照してください。
例2-11では、JavaクラスhelloWorldに定義された@Consumesアノテーションは、クラスがtext/plain MIMEメディア・タイプを使用してメッセージを作成することを指定します。
例2-10 @Consumesを使用したリクエスト・メッセージのメディア・タイプのカスタマイズ
package samples.consumes; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; ... @Path("/helloworld") public class helloWorld { ... @POST @Consumes("text/plain") public void postMessage(String message) { // Store the message } }
javax.ws.rs.Producesアノテーションにより、リソースが生成でき、クライアントに戻すことができる、表現のMIMEメディア・タイプを指定できます。@Producesアノテーションはクラスとメソッド・レベルの両方に指定でき、複数のメディア・タイプを同じ@Produces宣言で宣言できます。
指定されたMIMEメディア・タイプを生成できるメソッドがリソース内にない場合、ランタイムはHTTP 「406 許可されません」エラーを返します。
詳細は、Java EE 7 API仕様の@Producesアノテーションを参照してください。
例2-11では、JavaクラスSomeResourceに指定された@Producesアノテーションは、クラスがtext/plain MIMEメディア・タイプを使用してメッセージを作成することを指定します。doGetAsPlainTextメソッドのデフォルトは、クラス・レベルで指定されたMIMEメディア・タイプです。doGetAsHtmlメソッドはクラス・レベルの設定をオーバーライドし、メソッドがプレーン・テキストではなくHTMLを生成することを指定します。
例2-11 @Producesを使用したレスポンスのメディア・タイプのカスタマイズ
package samples.produces; import javax.ws.rs.Produces; import javax.ws.rs.Path; @Path("/myResource") @Produces("text/plain") public class SomeResource { @GET public String doGetAsPlainText() { ... } @GET @Produces("text/html") public String doGetAsHtml() { ... } }
リソース・クラスが複数のMIMEメディア・タイプの生成が可能な場合、選択されたリソース・メソッドは、HTTPリクエストのAcceptヘッダーに宣言された受入れ可能なメディア・タイプに対応します。例2-11では、AcceptヘッダーがAccept: text/htmlの場合、doGetAsPlainTextメソッドが呼び出されます。
複数のMIMEメディア・タイプが@Producesアノテーションに含まれており、両方がクライアントに受入れ可能な場合、指定された最初のメディア・タイプが使用されます。例2-11では、AcceptヘッダーがAccept: application/html, application/textの場合、doGetAsHtmlメソッドが呼び出され、リストの最初に表示されるapplication/html MIMEメディア・タイプが使用されます。
javax.ws.rsパッケージにより、リクエスト・メッセージから情報を抽出してJavaメソッドのパラメータに注入できるアノテーションのセット(表2-4を参照)が定義されます。
表2-4 リクエスト・メッセージから情報を抽出するためのjavax.ws.rsアノテーション
| アノテーション | 説明 |
|---|---|
|
|
単一のBeanに集約済リクエスト・パラメータを注入します。詳細は、Java EE 7 API仕様の その他の使用方法の詳細は、Jersey 2.21ユーザー・ガイドのパラメータ・アノテーション(@*Param)に関する項を参照してください。 |
|
|
HTTP Cookie関連ヘッダーから情報を抽出し、メソッド・パラメータの値を初期化します。詳細は、Java EE 7 API仕様の |
|
|
次に示すアノテーションのいずれかを使用してバインドされるリクエスト・メタデータのデフォルト値を定義します。 |
|
|
|
|
|
タイプ |
|
|
HTTPヘッダーから情報を抽出し、メソッド・パラメータの値を初期化します。詳細は、Java EE 7 API仕様の |
|
|
URIパス・セグメントから情報を抽出し、メソッド・パラメータの値を初期化します。詳細は、Java EE 7 API仕様の |
|
|
相対URIを変数として定義します(URIパス・テンプレートとして参照)。詳細は、「リクエストURIからの変数情報の抽出方法(@PathParam)」を参照してください。 |
|
|
リクエストURIの問合せ部分から情報を抽出し、メソッド・パラメータの値を初期化します。詳細は、「リクエスト・パラメータの抽出方法(@QueryParam)」を参照してください。 |
javax.ws.rs.PathParamアノテーションをリソースのメソッド・パラメータに追加し、リクエストURIから変数情報を抽出し、メソッド・パラメータの値を初期化します。@DefaultValueアノテーションを使用して、変数値のデフォルト値を定義できます。「DefaultValueの定義方法(@DefaultValue)」を参照してください。
例2-3では、@PathParamアノテーションが、@PathアノテーションによりURIパスの一部として定義されたusername変数の値をuserNameメソッド・パラメータに割り当てます。
例2-12 リクエストURIからの変数情報の抽出
package samples.helloworld; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.PathParam; // Specifies the path to the RESTful service @Path("/users") public class helloWorld { . . . @GET @Path("/{username}") @Produces("text/xml") public String getUser(@PathParam("username") String userName) { ... } }
javax.ws.rs.QueryParamアノテーションをリソースのメソッド・パラメータに追加し、リクエストURIの問合せ部分から情報を抽出し、メソッド・パラメータの値を初期化します。
アノテーションの付けられたメソッド・パラメータの種類は次のとおりです。
プリミティブ型(int、char、byteなど)
ユーザー定義型
1つの文字列引数を受入れるコンストラクタ
1つの文字列引数を受入れる静的メソッドvalueOfまたはfromString(たとえば、integer.valueOf(String))
List<T>、Set<T>、またはSortedSet<T>
@QueryParamアノテーションが指定されても、関連する問合せパラメータがリクエストに存在しない場合、そのパラメータ値は、List、SetまたはSortedSetの場合は空のコレクション、プリミティブ型の場合はJava定義のデフォルト、およびその他のすべてのオブジェクト型の場合はNULLに設定されます。または、@DefaultValueアノテーションを使用して、パラメータのデフォルト値を定義できます。「DefaultValueの定義方法(@DefaultValue)」を参照してください。
詳細は、Java EE 7 API仕様の@QueryParamアノテーションを参照してください。
例2-13では、step問合せパラメータがリクエストURIの問合せコンポーネントに存在する場合、その値はstepメソッドのパラメータに整数値として割り当てられます。値が整数値として解析できない場合、400 (クライアント・エラー)レスポンスが返ります。step問合せパラメータがリクエストURIの問合せコンポーネント内に存在しない場合、値はNULLに設定されます。
javax.ws.rs.DefaultValueアノテーションを追加して、次に示すアノテーションのいずれかを使用してバインドされるリクエスト・メタデータのデフォルト値を定義します。@CookieParam、@FormParam、@HeaderParam、@MatrixParam、@PathParamまたは@QueryParam。詳細は、Java EE 7 API仕様の@DefaultValueアノテーションを参照してください。
例2-14では、step問合せパラメータがリクエストURIの問合せコンポーネントに存在しない場合、デフォルト値2がstepパラメータに割り当てられます。
クラスまたはメソッド・レベルでjavax.ws.rs.Encodedアノテーションを追加して、@FormParam、@MatrixParam、@PathParamまたは@QueryParamのいずれかのアノテーションを使用してバインドされるパラメータ値のエンコードを有効にします。クラス・レベルで指定した場合は、そのクラスのすべてのメソッドのパラメータがエンコードされます。詳細は、Java EE 7 API仕様の@Encodedアノテーションを参照してください。
例2-15の@Encodedアノテーションは、@PathParamアノテーションを使用してバインドされるパラメータ値のエンコードを有効にします。
例2-15 パラメータ値のエンコード
package samples.helloworld; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.PathParam; import javax.ws.rs.Encoded; // Specifies the path to the RESTful service @Path("/users") public class helloWorld { . . . @GET @Path("/{username}") @Produces("text/xml") @Encoded public String getUser(@PathParam("username") String userName) { ... } }
デフォルトでは、正常なGETリクエストには200 OK、正常なPUTリクエストには201 CREATEDなどの、HTTP仕様で定義されたデフォルト・レスポンス・コードを使用して、JAX-RSはHTTPリクエストに応答します。
場合によっては、返されたレスポンス・コードをカスタマイズする、または追加メタデータ情報をレスポンスに含めることがあります。たとえば、新しく作成されたリソースにURIを指定するためのLocationヘッダーを含めるような場合です。返されたレスポンス・メッセージは、javax.ws.rs.core.Responseクラスを使用して変更できます。
アプリケーションではResponseクラスを直接拡張するか、表2-5で定義された静的Responseメソッドの1つを使用することで、javax.ws.rs.core.Response.ResponseBuilderインスタンスを作成してResponseインスタンスを構築できます。詳細は、Java EE 7 API仕様のResponseメソッドを参照してください。
表2-5 ResponseBuilderクラスを使用したレスポンス・インスタンスの作成
| メソッド | 説明 |
|---|---|
|
|
新しい |
|
|
新しい |
|
|
新しい |
|
|
新しい |
|
|
新しい |
|
|
新しい |
|
|
リダイレクトのための新しい |
|
|
新しい |
|
|
新しい |
|
|
一時的なリダイレクトのための新しい |
ResponseBuilderインスタンスを作成した後は、表2-6で定義されたメソッドを呼び出してカスタム・リソースを定義できます。次に、build()メソッドを呼び出して最終的なResponseインスタンスを作成します。詳細は、Java EE 7 API仕様のResponse.ResponseBuilderメソッドを参照してください。
表2-6 カスタム・レスポンスを構築するためのResponseBuilderメソッド
| メソッド | 説明 |
|---|---|
|
|
リソースに許可されているメソッドを設定します。 |
|
|
現在の |
|
|
キャッシュ・コントロールを設定します。 |
|
|
|
|
|
コンテンツの場所を設定します。 |
|
|
レスポンスにCookieを追加します。 |
|
|
メッセージ・エンティティのコンテンツ・エンコーディングを設定します。 |
|
|
エンティティを定義します。 |
|
|
有効期限を設定します。 |
|
|
レスポンスにヘッダーを追加します。 |
|
|
言語を設定します。 |
|
|
最終変更日を設定します。 |
|
|
リンク・ヘッダーを追加します。 |
|
|
1つ以上のリンク・ヘッダーを追加します。 |
|
|
場所を設定します。 |
|
|
新しい |
|
|
既存のヘッダーをすべて新しく指定したヘッダーで置き換えます。 |
|
|
ステータスを設定します。 |
|
|
エンティティ・タグを設定します。 |
|
|
レスポンス・メディア・タイプを設定します。 |
|
|
表現メタデータを設定します。 |
|
|
使用可能なバリアントの一覧を示す |
例2-16は、ResponseBuilderを使用したResponseインスタンスの構築方法を示しています。この例では、200 OKの標準ステータス・コードが返され、レスポンスのメディア・タイプがtext/htmlに設定されます。build()メソッドの呼出しによって最終的なResponseインスタンスが作成されます。
例2-16 カスタム・レスポンスの構築
import javax.ws.rs.Path; import javax.ws.rs.GET; import javax.ws.rs.PathParam; import javax.ws.rs.core.Response; import javax.ws.rs.core.ResponseBuilder; ... @Path("/content") public class getDocs { @GET @Path("{id}") public Response getHTMLDoc(@PathParm("id") int docId) { Document document = ...; ResponseBuilder response = Response.ok(document); response.type("text/html"); return response.build(); } }
汎用型を使用してHTTPレスポンスを構築する場合、実行時に型のイレイジャを回避するために、汎用型を保持するjavax.ws.rs.core.GenericEntityオブジェクトを作成する必要があります。詳細は、Java EE 7 API仕様のGenericEntityメソッドを参照してください。
例2-17に、汎用型を保持するGenericEntityを使用する、HTTPレスポンスの構築方法の例を示します。
例2-17 汎用型を使用したカスタム・レスポンスの構築
import javax.ws.rs.Path; import javax.ws.rs.GET; import javax.ws.rs.PathParam; import javax.ws.rs.core.Response; import javax.ws.rs.core.ResponseBuilder; javax.ws.rs.core.GenericEntity; ... @Path("/content") public class getDocs { @GET @Path("{id}") public Response getHTMLDoc(@PathParm("id") int docId) { Document document = ...; List<String> list = new ArrayList<String>(); GenericEntity<List<String>> entity = new GenericEntity<List<String>>(list) {}; ... ResponseBuilder response = Response.ok(document); response.entity(entity); return response.build(); } }
表2-7に、HTTPリクエストおよびレスポンスのエンティティ本文で自動的にサポートされるJavaタイプを示します。
表2-7 HTTPリクエストおよびレスポンスのエンティティ本文でサポートされるJavaタイプ
| Javaタイプ | サポートされるメディア・タイプ |
|---|---|
|
|
すべてのメディア・タイプ(*/*) |
|
|
すべてのメディア・タイプ(*/*) |
|
|
すべてのメディア・タイプ(*/*) |
|
|
すべてのメディア・タイプ(*/*) |
|
|
すべてのメディア・タイプ(*/*) |
|
|
すべてのメディア・タイプ(*/*) |
|
|
XMLメディア・タイプ( |
|
|
XMLメディア・タイプ( |
|
|
フォーム・コンテンツ( |
|
|
すべてのメディア・タイプ(*/*)、 |
RESTful Webサービスで、表2-7に示されていないタイプを使用する場合は、表2-8に定義されているインタフェースのいずれかを実装することでエンティティ・プロバイダを定義し、HTTPリクエストおよびレスポンスのエンティティ本文をメソッドのパラメータおよび戻りタイプにマップする必要があります。
表2-8 HTTPリクエストおよびレスポンスのエンティティ本文をメソッドのパラメータおよび戻りタイプにマップするためのエンティティ・プロバイダ
| エンティティ・プロバイダ | 説明 |
|---|---|
|
|
HTTPリクエストのエンティティ本文をメソッドのパラメータにマップします。 以下に例を示します。
@Consumes("application/x-www-form-urlencoded")
@Provider
public class FormReader implements MessageBodyReader<NameValuePair> { ... }
|
|
|
HTTPレスポンスのエンティティ本文に戻り値をマップします。 以下に例を示します。
@Produces("text/html")
@Provider
public class FormWriter implements
MessageBodyWriter<Hashtable<String, String>> { ... }
|
|
注意: Jersey JSONには、Jersey JSON拡張モジュールとともに配布されるJAX-RSMessageBodyReaderプロバイダおよびMessageBodyWriterプロバイダのセットが用意されています。詳細は、Jersey 2.21ユーザー・ガイドのJSONに関する項を参照してください。 |
次に示すコードの抜粋は、カスタム・タイプを返すメソッド(getClass)を含むクラスの例を示しています。このコードにはエンティティ・プロバイダを記述する必要があります。
public class Class1
{
public String hello() { return "Hello"; }
public Class2 getClass(String name) { return new Class2(); };
}
public class Class2
{
public Class2() { }
}
javax.ws.rs.core.Contextアノテーションを使用すると、アプリケーション・デプロイメント・コンテキストと個別リクエストのコンテキストに関する情報にアクセスできます。表2-9に@Contextアノテーションを使用してアクセスできるコンテキスト・タイプの概要を示します。詳細は、Java EE 7 API仕様の@Contextアノテーションを参照してください。
表2-9 コンテキスト・タイプ
| コンテキスト・タイプ名 | 目的 |
|---|---|
|
|
HTTPヘッダー情報にアクセスします。 |
|
|
一連の検索基準を基に、プロバイダ・インスタンスを参照します。 |
|
|
最も一致する表現バリアントを判別し、リソースの現在の状態が定義済の前条件に一致するかどうかを評価します。詳細は、「条件付きGETの使用」を参照してください。 |
|
|
セキュリティ・コンテキストにアクセスし、RESTful Webサービスを保護します。詳細は、「SecurityContextを使用したRESTful Webサービスの保護」を参照してください。 |
|
|
アプリケーションおよびリクエストURI情報にアクセスします。詳細は、「URIの構築」を参照してください。 |
javax.ws.rs.core.UriInfoを使用して、アプリケーションおよびリクエストURI情報にアクセスできます。具体的には、UriInfoは次の情報を返すために使用できます。
デプロイされたアプリケーションの基底URI
基底URIに相対するリクエストURI
絶対パスURI (問合せパラメータ付きの場合もあり)
UriInfoを使用して、URIまたはjavax.ws.rs.core.UriBuilderインスタンスを返すことができます。UriBuilderはURIの構築プロセスを簡素化し、新規URIの構築、または既存URIの拡張にも使用できます。
UriBuilderメソッドは、対応するURIコンポーネントでは許可されていない文字のコンテキスト・エンコーディングを、次のルールに基づいて実行します。
問合せパラメータについてはapplication/x-www-form-urlencodedメディア・タイプ(URL: http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1にあるHTML仕様の「Forms」で定義)
その他すべてのコンポーネントについてはRFC 3986 (URL: http://www.ietf.org/rfc/rfc3986.txtで定義)
例2-18に、@Contextを使用したUriInfoのインスタンスの取得と、そのインスタンスを使用して、リクエストURIの絶対パスをUriBuilderインスタンスとして返す方法を示します。次に、UriBuilderを使用して、ユーザーIDをパス・セグメントとして追加して特定のユーザー・リソースに対するURIを構築し、配列内に格納します。この例では、UriInfoインスタンスはクラス・フィールドに注入されます。この例は、「Jerseyブックマーク・サンプルについて」に記述されているとおり、ブックマーク・サンプルからの抜粋です。
例2-18 URIの構築
import javax.ws.rs.Path; import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.Context; ... @Path("/users/") public class UsersResource { @Context UriInfo uriInfo; ... @Produces("application/json") public JSONArray getUsersAsJsonArray() { JSONArray uriArray = new JSONArray(); for (UserEntity userEntity : getUsers()) { UriBuilder ub = uriInfo.getAbsolutePathBuilder(); URI userUri = ub .path(userEntity.getUserid()) .build(); uriArray.put(userUri.toASCIIString()); } return uriArray; } }
条件付きGETを使用すると、GETリクエストを処理する前に前条件を1つ以上評価できます。前条件が一致する場合、Not Modified (304)レスポンスを通常のレスポンスのかわりに返すことが可能で、これによって潜在的に帯域幅が縮小され、サーバー・パフォーマンスが向上します。
JAX-RSは、条件付きGETの実行を可能にするjavax.ws.rs.core.Requestコンテキスト・インタフェースを提供します。evaluatePreconditions()メソッドを呼び出してjavax.ws.rs.core.EntityTag、(java.util.Dateオブジェクトとして)最終変更日のタイムスタンプ、あるいはその両方を渡します。値はIf-None-MatchヘッダーまたはIf-Not-Modifiedヘッダーと、このヘッダーがリクエストとともに送信された場合は、それぞれ比較されます。
ヘッダーがリクエストとともに含まれ、前条件値がヘッダー値と一致する場合は、evaluatePreconditions()メソッドが定義済のResponseBuilderレスポンスをNot Modified (304)のステータス・コードとともに返します。前条件値が一致しない場合、evaluatePreconditions()メソッドはNULLを返し、通常のレスポンスが200, OKステータスとともに返されます。
例2-19に、EntityTagをevaluatePreconditions()メソッドに渡し、前条件の一致の有無に基づいてレスポンスを構築する方法を示します。
例2-19 条件付きGETの使用
...
@Path("/employee/{joiningdate}")
public class Employee {
Date joiningdate;
public Employee(@PathParam("joiningdate") Date joiningdate, @Context Request req,
@Context UriInfo ui) {
this.joiningdate = joiningdate;
...
this.tag = computeEntityTag(ui.getRequestUri());
if (req.getMethod().equals("GET")) {
Response.ResponseBuilder rb = req.evaluatePreconditions(tag);
// Preconditions met
if (rb != null) {
return rb.build();
}
// Preconditions not met
rb = Response.ok();
rb.tag(tag);
return rb.build();
}
}
}
Web Application Description Language (WADL)は、RESTful Webサービス・アプリケーションを記述するXMLベースのファイル形式です。デフォルトでは、ベースWADLが実行時に生成され、RESTfulアプリケーションの基底URIでGETを/application.wadlリソースに発行することで、RESTful Webサービスからアクセスできます。
|
注意: コンテキスト・タイプapplication/vnd.sun.wadl+xmlは、Microsoft Internet Explorer 8では認識されません。その場合、参照用にWADLのコピーをローカル・ファイル・システムにダウンロードできます。 |
以下に例を示します。
GET http://<path_to_REST_app>/application.wadl
もしくは、OPTIONSメソッドを使用して特定のリソースに対するWADLを返すこともできます。
例2-20に、例2-1の簡単なRESTful Webサービスに対するWADLの例を示します。
例2-20 WADLの例
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application xmlns="http://research.sun.com/wadl/2006/10">
<doc xmlns:jersey="http://jersey.dev.java.net/"
jersey:generatedBy="Jersey: 0.10-ea-SNAPSHOT 08/27/2008 08:24 PM"/>
<resources base="http://localhost:9998/">
<resource path="/helloworld">
<method name="GET" id="sayHello">
<response>
<representation mediaType="text/plain"/>
</response>
</method>
</resource>
</resources>
</application>
JAX-RSとEJBテクノロジおよびContexts and Dependency Injection (CDI)との統合やJAXBおよびJSONの使用など、高度なRESTful Webサービス開発タスクの詳細は、Jersey 2.21ユーザー・ガイドを参照してください。