前回作成したサンプルを使って JAX-RS のパスのマッピングについて見ていきます。
- Path の指定
- メソッド の指定
- QueryParam
- @PathParam
- パスの正規表現指定
- @MatrixParam
- PathSegment
- ヘッダ情報の取得
- @FormParam
- @BeanParam
- モデルの作成
- Resource の作成
Path の指定
JAX-RS では Resource クラスに @Path
アノテーションを付けることで URL とのマッピングを指定します。
以下の ExampleResource を作成します。
package example.web.resource; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.PathSegment; import javax.ws.rs.core.Response; import java.io.InputStream; import java.util.StringJoiner; @Path("example") public class ExampleResource { @Path("hello") @GET public String pathHello() { return "hello"; } }
メソッドに @Path
を指定することでパスの階層を扱うことができます。クラスに付けた @Path("example")
と メソッドに付けた @Path("hello")
で、example/hello というパスでのリクエストが、作成したメソッドにルーティングされます。
@GET
で HTTP GET に応答する指定となります。
アプリケーションを起動し、curl で GET リクエストを投げてみましょう。
$ curl 'http://localhost:8090/example/hello' hello
hello という文字列が返却されました。
メソッド の指定
@POST
を指定することで HTTP POST に応答するようになります。
以下のメソッドを追加しましょう。
@POST public Response echoPost(InputStream is) { return Response.ok(is).build(); }
引数で指定した InputStream
からは HTTPリクエストのボディの内容を取得することができます。
アプリケーションを起動し、curl で -X
オプションを指定して POST リクエストを投げてみましょう。
$ curl 'http://localhost:8090/example' -X POST -d 'HELLO' HELLO
リクエストに付けた HELLO という文字列がそのまま返却されました。
メソッドの指定は HTTP メソッドの種類に応じたアノテーションが用意されています。
- @javax.ws.rs.GET
- @javax.ws.rs.PUT
- @javax.ws.rs.POST
- @javax.ws.rs.DELETE
- @javax.ws.rs.HEAD
WebDAV などのメソッドを扱う場合は @HttpMethod
でアノテートすることで拡張可能です。
例えばLOCK メソッドが必要な場合は以下のようにアノテーションを自作します。
@Target({ElementType.METHOD}) @Retention({RetentionPolicy.RUNTIME}) @HttpMethod("LOCK") public @interface LOCK {}
QueryParam
@QueryParam
で HTTPリクエストのクエリを取得することができます。
@GET @Produces({MediaType.TEXT_PLAIN}) public String queryParam(@QueryParam("name") String name, @QueryParam("age") @DefaultValue("30") int age) { return name + " " + age; }
@Produces({MediaType.TEXT_PLAIN})
でレスポンスのコンテントタイプが Content-Type: text/plain
となります。
@DefaultValue
でデフォルト値を指定することができます。
$ curl 'http://localhost:8090/example?name=Thomas' Thomas 30
フィールドにアノテーションを付けて取得することもできます。
@QueryParam("fieldValue") private String fieldValue; @GET @Path("field") public Response queryParamField() { return Response.ok(fieldValue).build(); }
$ curl 'http://localhost:8090/example/field?fieldValue=Who' Who
@PathParam
@Path
と @PathParam
で HTTPリクエストのパスを取得することができます。
REST の場合はこちらが一般的ですね。
@GET @Path("path/{name}") public Response pathParam(@PathParam("name") String name) { return Response.ok(name).build(); }
URLパスを {name}
で指定して @PathParam
で取得します。
$ curl 'http://localhost:8090/example/path/Eddie' Eddie
以下のようにいくつも指定することができます。
@GET @Path("path/{firstname}-{lastname}") public Response pathParams(@PathParam("firstname") String first, @PathParam("lastname") String last) { return Response.ok(first + " " + last).build(); }
@PathParam
で応答する名前で取得できます。
$ curl 'http://localhost:8090/example/path/Eddie-Vedder' Eddie Vedder
パスの正規表現指定
パスは正規表現を使ってマッチさせることができます。
@GET @Path("path/{id : \\d+}") public Response pathParamsRegexp(@PathParam("id") int id) { return Response.ok("id[" + id + "]").build(); }
この例では数字にマッチさせ、id という名前で取得しています。
$ curl 'http://localhost:8090/example/path/9999' id[9999]
@MatrixParam
MatrixParam はパスパラメータを ;
で区切る形式です。
@GET @Path("matrix") public Response matrixParam(@MatrixParam("author") String author, @MatrixParam("year") int year) { return Response.ok("MatrixParam[" + author + " " + year + "]").build(); }
以下のように取得できます。
$ curl 'http://localhost:8090/example/matrix;author=Michael;year=2016' MatrixParam[Michael 2016]
PathSegment
パスは PathSegment として取得し、後から値を取り出すこともできます。
@GET @Path("matrix/{model}/{year}") public Response pathSegment(@PathParam("model") PathSegment car, @PathParam("year") int year) { return Response.ok("PathSegment[" + car.getMatrixParameters().getFirst("color") + "]").build(); }
$ curl 'http://localhost:8090/example/matrix/e50;color=black/2016' PathSegment[black]
また、以下のように @Context
で UriInfo から PathSegment を操作することもできます。
@GET @Path("matrix/{model}/{year}") public Response pathSegment(@Context UriInfo info) { PathSegment model = info.getPathSegments().get(1); // ・・・ }
UriInfo からはパス文字列を取得することなども出来ます。
ヘッダ情報の取得
@HeaderParam
で HTTPヘッダの値、@CookieParam
で cookie の値が取得できます。
@GET @Path("header") public Response header(@HeaderParam("X-Name") String name) { return Response.ok("header[" + name + "]").build(); } @GET @Path("cookie") public Response cookie(@CookieParam("name") String name) { return Response.ok("cookie[" + name + "]").build(); }
$ curl 'http://localhost:8090/example/header' -H 'X-Name: Joe' header[Joe] $ curl 'http://localhost:8090/example/cookie' -b 'name=cookie' cookie[cookie]
@FormParam
フォームからPOSTしたパラメータは @FormParam
で取得できます。
@POST @Path("form") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response form(@FormParam("number") int number) { return Response.ok("form[" + number + "]").build(); }
@Consumes
にて受け入れるコンテントタイプを指定しています。
以下のように取得できます。
$ curl 'http://localhost:8090/example/form' -X POST -d 'number=9999' form[9999]
@BeanParam
JAX-RS 2.0 からパラメータが多い場合は @BeanParam
で任意のBeanを指定して取得できます。
@POST @Path("bean") public Response bean(@BeanParam Input in) { StringJoiner joiner = new StringJoiner(",", "[", "]"); return Response.ok("BeanParam" + joiner.add(in.getFirstName()) .add(in.getLastName()) .add(in.getContentType()).toString()).build(); } public static class Input { @FormParam("firstName") String firstName; @FormParam("lastName") String lastName; @HeaderParam("Content-Type") String contentType; public String getFirstName() { return firstName;} public String getLastName() { return lastName; } public String getContentType() { return contentType; } public void setFirstName(String firstName) { this.firstName = firstName;} public void setLastName(String lastName) { this.lastName = lastName; } public void setContentType(String contentType) { this.contentType = contentType; } }
Bean のフィールドに @FormParam
のように指定してまとめて取得することができます。
$ curl 'http://localhost:8090/example/bean' -X POST -d 'firstName=F&lastName=L' BeanParam[F,L,application/x-www-form-urlencoded]
モデルの作成
以下のような Customer
と Address
の POJO を作成します。
package example.domain.model; import javax.xml.bind.annotation.XmlRootElement; import java.io.Serializable; @XmlRootElement public class Customer implements Serializable { private Long id; private String firstName; private String lastName; private Address address; public Customer(Long id, String firstName, String lastName, Address address) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.address = address; } public Long getId() { return id; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public Address getAddress() { return address; } public void setId(Long id) { this.id = id; } public void setFirstName(String firstName) { this.firstName = firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public void setAddress(Address address) { this.address = address; } }
Customer は @XmlRootElement
でアノテートしておきます。
JAX-RS で扱う場合にはルートとなるモデルに このアノテーションが必要です。
Customer から参照する Address を以下のように作成します。
package example.domain.model; import java.io.Serializable; public class Address implements Serializable { private String street; private String city; private String state; private String zip; private String country; public Address(String street, String city, String state, String zip, String country) { this.street = street; this.city = city; this.state = state; this.zip = zip; this.country = country; } public String getStreet() { return street; } public String getCity() { return city; } public String getState() { return state; } public String getZip() { return zip; } public String getCountry() { return country; } public void setStreet(String street) { this.street = street; } public void setCity(String city) { this.city = city; } public void setState(String state) { this.state = state; } public void setZip(String zip) { this.zip = zip; } public void setCountry(String country) { this.country = country;}
Resource の作成
作成したモデルを扱うリソースとして CustomerResource
を作成しましょう。
package example.web.resource; import example.domain.model.Address; import example.domain.model.Customer; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("customers") public class CustomerResource { @GET @Path("{id}") @Produces({MediaType.APPLICATION_JSON}) public Customer get(@PathParam("id") Long id) { return new Customer(id, "Michael", " Stipe", new Address("1016", "Hollywood", "CA", "90038", "US")); } }
簡単のため、新しい Customer を作成して返却しているだけです。
@Produces({MediaType.APPLICATION_JSON})
を指定し、戻り値を Customer
として以下のURLでアクセスします。
Customer は @XmlRootElement
でアノテートしてあるため、メソッドの戻り値としてそのまま指定すれば 、上記の例では自動的にJSON形式に変換されます。
作成したリソースにアクセスしてみましょう。
http://localhost:8090/customers/100
以下のようにJson形式で取得することができます。
簡単ですね。
ここまでのソースはGithubを参照してください。