Tuesday, January 15, 2013

jax-rs(jersey)覚書 #2 基本編


サービスのパスの設定

@Pathアノテーション

クラス、メソッドに指定して、RESTサービスのパス(URL)を決める。
@Path("employee")
public class EmpService{
    
    @GET
    @Path("service1")
    public Response service1() {
この場合サービスのURLは
http://ホスト/コンテキストルート/employee/service1
となる。

可変パスの扱い
@Pathと@PathParam

RESTでは”一意なURL”というのがが基本的な考え方としてある。URLのパスにIDを含める形になる(”サービス/{id} ”というような形)。
jax-rsではパスの値が可変なURLを扱うことができる。
@Path("employee")
public class EmpService{
    
    @GET
    @Path("{id}")
    public Response service1(@PathParam String id) {
これで、
http://ホスト/コンテキストルート/employee/123
にアクセスした場合、 @PathParamアノテーションで修飾した引数 id に"123"が入ってくる。

複合キーならどうするか?

複合キーを"-"等で繋いだ場合、は以下のような形になる。
http://ホスト/コンテキストルート/employee/123-111 の場合

@Path("employee")
public class EmpService{
    
    @GET
    @Path("{id1}-{id2}")
    public Response service1(@PathParam String id1, @PathParam Strind id2) {


HTTPメソッドの指定

@GET, @PUT, @POST, @DELETE, @HEADアノテーションを使って、どのHTTPメソッドで受けるかを指定する。
同一パスでもHTTPメソッドによって処理を切り分けることができる。
@Path("employee")
public class EmpService{
    
    @GET
    @Path("{id}")
    public Response get(@PathParam String id) {
        
    }
    
    @PUT
    @Path("{id}")
    public Response update(@PathParam String id) {
        
    }
    
    @POST
    @Path("{id}")
    public Response insert(@PathParam String id) {
        
    }
    
    @DELETE
    @Path("{id}")
    public Response delete(@PathParam String id) {
        
    }
}
この場合、同じURL
http://ホスト/コンテキストルート/employee/123
を、HTTPメソッドを分けて使うことができる。正しいRESTの形はこのように実現できる。
実装されていないメソッドでアクセスがあった場合、405 Method Not Allowed がクライアントに返される。

POST,PUTされる様々なContent-TypeのデータをJavaオブジェクトへ変換する

@Consumesアノテーションで受け取るデータのContent-Typeを指定することができる。
たとえば以下のJSONデータをPOSTされて、Employeeというクラス(Value Object)にマッピングする場合は以下のようになる。

{ "empId" : "123", "firstName" : "Oscar" , "lastName" : "Jarjays", "gender" : "female" }

@Path("employee")
public class EmpService{

 @POST
 @Consumes({ MediaType.APPLICATION_JSON })
 public Response post(Employee employee) {

public class Employee {

    private String empId;
    private String firstName;
    private String LastName;
    private String gender;
    
    public String getEmpId() {
        return empId;
    }
    public void setEmpId(String empId) {
        this.empId = empId;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return LastName;
    }
    public void setLastName(String lastName) {
        LastName = lastName;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }

}
JSON以外のContent-Typeにも対応している。

  • application/json : MediaType.APPLICATION_JSON
  • application/xml : MediaType.APPLICATION_XML
  • application/x-www-form-urlencoded : MediaType.APPLICATION_FORM_URLENCODED
  • application/octet-stream : MediaType.APPLICATION_OCTET_STREAM
  • multipart/form-data : MediaType.MULTIPART_FORM_DATA
  • text/plain : MediaType.TEXT_PLAIN
  • etc..

Javaオブジェクトを様々なContent-Typeに変換してレスポンスを返す


@Producesアノテーションでレスポンスとして返すContent-Typeを指定する。
javax.ws.rs.core.Responseを使って、実際に変換を行ってレスポンスを返す。
EmployeeをJSONにして返す場合は以下のようになる。
@Path("myRestService")
public class MyRestService {
    
    @GET
    @Path("{id}")
    @Produces({ MediaType.APPLICATION_JSON })
    public Response get(@PathParam(name = "id") String id) {
        
        Employee emp = getEmp(id);
        return Response.ok(emp, MediaType.APPLICATION_JSON).build();
    }

Response.ok()ではHTTPステータスコード200を返す。

OK以外のレスポンスを返す
javax.ws.rs.core.Response.status() を使う。


  • status(int status)
  • status(Response.Status status)
  • status(Response.StatusType status)


  • Response.status(404);
  • Response.status(500);
  • Response.status(Status.FORBIDDEN);
  • Response.status(Status.INTERNAL_SERVER_ERROR);


クエリパラメータを扱う

http://ホスト/コンテキストルート/myRestService?param1=value1&param2=value2
という形で、パラメータを指定した場合は、引数を@QueryParamアノテーションで修飾することによって受け取ることができる。
@Path("myRestService")
public class MyRestService {
    
    @GET
    public Response get(@QueryParam(value="param1") param1, @QueryParam(value="param2" param2)) {

この方法だと、パラメータ値一つ一つをバラバラに受け取ることになる。
クラスにマッピングする方法もある。

まず、パラメータを受け取るクラスのフィールドに@QueryParamアノテーションをつける。
public class Employee {

    @QueryParam("id")
    String id;
    
    @QueryParam("firstName")
    String firstName;

    @QueryParam("lastName");
    String lastName;

サービスのメソッドの引数に@Contextアノテーションをつけたcom.sun.jersey.api.core.ResourceContextを指定する。
ResourceContext.getResource()にパラメータを格納するクラスを指定して、インスタンスを得ることができる。
これは@QueryParamだけでなく、@PathParam等にも使える。

@Path("myRestService")
public class MyRestService {
    
    @GET
    public Response get(@Context ResourceContext rc)) {
        
        Employee emp = rc.getResource(Employee.class);
このやり方の問題は、引数がResourceContextになってしまって、欲しいパラメータはResourceContextから得ることになってUnit Testがやりにくくなってしまう。
まとまった数のパラメータをPOJOで受け取りたいのであれば、POSTを使ってPOJOで受け取る方が良さそう。

No comments:

Post a Comment