Jerseyに触ってみる
せっかくの夏休みなんで、JerseyでRESTfulなWebサービスとか作る練習とかしてみようといろいろ調べ中。
Webアプリケーションの作成
とりあえずは
Jersey, Jetty and Maven: HelloWorld
に従ってEclipse上でアプリケーションを作成。こういう時にpom.xmlを写せばそれだけで実行できるってのはやはり便利だ。maven様様。
GETメソッドでリソースを取得
へGETメソッドを使ってアクセスすると、URLの"helloworld"リソースに紐付けられたHelloWorldクラスのgetMessageメソッドが呼ばれ、その戻り値である文字列
が戻る。まあ何の工夫もないけど、ここまでは良し。
よく考えると
上の例はGETメソッドだからいいけど、URIの"helloworld"リソースに対してDELETEメソッドとか使う場合を考えると破綻するよな。"helloworld"リソース(に紐付けられたHelloWorldクラス)を削除???インスタンスならともかくクラスを削除とかできないし。
URIのリソースはあくまでJavaの特定のインスタンスに対して紐付けるものであり、上記のようにクラスに対して紐付けてしまうのは微妙っぽい。
要は、あるメッセージ(インスタンス)を表すリソースとして、下記の例のようにメッセージID文字列を指定するようにしたい。
http://localhost:8080/message/${メッセージID文字列}
で、上記URIに対してPUTメソッドを実行するとメッセージの内容が上書きされ、DELETEメソッドを実行するとそのメッセージが削除されるようにする。
どうやってURIとインスタンスを紐付ける?
こういう時は公式ページを見るに限る。
Jersey 1.3 User Guide - Example 2.2. Specifying URI path parameter
要は、URIパスにパラメータ(今回の場合、特定のインスタンスを示すID文字列)を含ませることで解決。
- パスを指定する@Pathアノテーションの引数として、以下のように"{}"で囲んだ変数名を使用する。
@Path("/message/{id}")
例:
@Path("/message/{id}") public class HelloWorld { //中略 @GET @Produces("text/plain") public String getMessage(@PathParam("id") String id ) { //hogehoge }
オリジナルのHelloWorldクラスを改変したソース全体はこんな感じ(元のサンプルからパッケージ名を変更したため、web.xmlでパッケージ名を指定している箇所を修正する必要があるので注意)。
package com.sample; import java.util.HashMap; import java.util.Map; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.Path; @Path("/message/{id}") public class HelloWorld { private static Map<String, Message> messages = new HashMap<String, Message> (); @GET @Produces("text/plain") public String getMessage(@PathParam("id") String id ) { return messages.get(id)==null?null:messages.get(id).toString(); } @PUT @Produces("text/plain") public String setMessage(@PathParam("id") String id, String text) { Message message = messages.get(id); if(message == null){ message = new Message(id); messages.put(id, message); } message.setText(text); return message.toString(); } @DELETE @Produces("text/plain") public String delMessage(@PathParam("id") String id) { Message message = messages.get(id); messages.remove(id); return message.toString() + " was deleted!"; } } /** * メッセージを表すクラスです。インスタンスを作成するためには任意のidが必要。 * */ class Message{ private String id; private String text = null; public Message(String id){ this.id = id; } public String getId(){ return this.id; } public void setText(String text){ this.text = text; } public String getText(){ return this.text == null?"":this.text; } public String toString(){ return "id: " + this.id + " text: " + this.text; } }
このコードを元にwarファイルをビルドし、Webコンテナにデプロイする(細かいことはMavenが勝手にやってくれるけど)
下記のURIに対して、GET、PUT、DELETEメソッドでアクセスすると・・・
●一回目に上記のURIに対してGETメソッドを実行
→id="hoge"であるメッセージが存在しないため、レスポンスコード204が戻る(本来、404を戻すべきだが・・・・とりあえず)
●データとして"ああああ"と入れてPUTメソッドを実行。
→id="hoge"のMessageインスタンスが作成される。
戻り値として、新規作成されたMessageインスタンスの文字列表現"id: hoge text: ああああ"が戻る。
●再度、上記のURIに対してGETメソッドを実行
→id="hoge"のMessageインスタンスが、Mapから取得される。
戻り値として、Messageインスタンスの文字列表現"id: hoge text: ああああ"が戻る。
●上記のURIに対してDELETEメソッドを実行
→id="hoge"のMessageインスタンスが、Mapから削除される。
●再度、上記のURIに対してGETメソッドを実行
→id="hoge"であるメッセージが存在しないため、レスポンスコード204が戻る(本来、404を戻すべきだが・・・・とりあえず)