新トップページへ | Tip

RESTを使う

LastUpdate : 12/11/03

RESTサービスもとても簡単に作成できるようになっています。
基本的な使い方のサンプルを示します。

RESTには様々な設定を施すことが出来ますが、基本ほとんど設定を行わずデフォルト設定で行くんじゃないかなと思います。なので、基本パターンさえ知ってれば十分じゃないかなーって私は思ってます。いやー詳細しらないとだめだわーってなったら、このページを加筆します。


もくじ

RESTのパラメータの様々な受け取り方


RESTのパラメータの様々な受け取り方

パラメータの受け取り方などをいくつかバリエーションをサンプルで示します(詳細はJavadocの中にかいてあります)。
また、web.xmlの設定も必要ですのえ、web.xmlのサンプルも示します。

@Consumesアノテーションで、受け付ける入力のタイプを、@Producesアノテーションで、応答として返すタイプを指定しています。

Service1Rest.java
package alctail.rest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;

import alctail.bean.RestRequest;
import alctail.bean.RestResponse;


/**
 * RESTのサンプル.
 * 
 * MediaType.TEXT_PLAINは「"text/plain"」を示す。
 */
@Path("/study1")
@Produces(MediaType.TEXT_PLAIN)
public class Service1Rest {
        
        @Context
        private UriInfo uriInfo;
        
        /**
         * 以下のパスでアクセス
         *    http://(ホスト名)/(コンテキストルート)/study1/restService1
         */
        @GET
        @Path("/restService1/")
        public String restService1() {
                return "本格的戻り値";
        }
        
        /**
         * 以下のパスでアクセス
         *    http://(ホスト名)/(コンテキストルート)/study1/restService2/(任意の文字列)
         */
        @GET
        @Path("/restService2/{msg}")
        public String restService2(@PathParam("msg")String msg) {
                return "本格的引数:"+msg;
        }
        
        /**
         * 以下のパスでアクセス
         *    http://(ホスト名)/(コンテキストルート)/study1/restService3?name=XXXXX&age=XXXXX&job=XXXXX
         *    (XXXXXは任意の値)
         *    jobの値は指定しなかった場合、「NEET」というデフォルト値が設定される
         */
        @GET
        @Path("/restService3/")
        public String restService3(@QueryParam("name")String name, @QueryParam("age")int age, @DefaultValue("NEET") @QueryParam("job")String job) {
                return "name="+name+"\nage="+age+"\njob="+job;
        }
        
        /**
         * 以下のパスでアクセス
         *    http://(ホスト名)/(コンテキストルート)/study1/restService4:name=XXXXX;age=XXXXX
         *    (XXXXXは任意の値)
         */
        @GET
        @Path("/restService4/")
        public String restService4(@MatrixParam("name")String name, @MatrixParam("age")int age) {
                return "name="+name+"\nage="+age;
        }
        
        /**
         * POSTで送信された情報を受け付ける(単純なケース)
         */
        @POST
        @Path("/restService5/")
        @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
        public String restService5(@FormParam("name") String name, @FormParam("age") int age) {
                return "name="+name+"\nage="+age;
        }
        
        /**
         * POSTで送信された情報を受け付ける(restService5と同じだが、こちらのほうが便利)。
         * (MultivaluedMapを使用する)
         */
        @POST
        @Path("/restService6/")
        @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
        public String restService6(MultivaluedMap<String, String> map) {
                StringBuilder builder = new StringBuilder();
                for (Map.Entry<String, List<String>> entry : map.entrySet()) {
                        builder.append("key:").append(entry.getKey()).append("\n");
                        builder.append("   value:\n");
                        for (String value : entry.getValue()) {
                                builder.append("      ").append(value).append("\n");
                        }
                }
                return builder.toString();
        }
        
        /**
         * XMLを受信し、処理結果をXMLで応答する.
         * 送受信するXMLを、マーシャル・アンマーシャルされる。
         * 以下のようなXMLを受信可能
         * <pre>
         * <restRequest>
         *     <name>alctail</name>
         *     <age>17</age>
         * </restRequest>
         * </pre>
         */
        @POST
        @Path("/restService7/")
        @Consumes(MediaType.APPLICATION_XML)
        @Produces(MediaType.APPLICATION_XML)
        public RestResponse restService7(RestRequest request) throws IOException {
                RestResponse result = new RestResponse();
                result.setName(request.getName()+"_response");
                result.setAge(request.getAge()+100);
                return result;
        }
        
        
        /**
         * XMLを受信し、処理結果をXMLで応答する.
         * 受信したXMLをInputStreamで受け取ることもできる
         */
        @POST
        @Path("/restService8/")
        @Consumes(MediaType.APPLICATION_XML)
        @Produces(MediaType.APPLICATION_XML)
        public RestResponse restService8(InputStream inputStream) throws IOException {
                InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
                BufferedReader reader = new BufferedReader(inputStreamReader);
                String line = null;
                while ((line = reader.readLine()) != null) {
                        System.out.println(line);
                }
                
                RestResponse result = new RestResponse();
                result.setName("aaa");
                result.setAge(17);
                return result;
        }
        
        /**
         * コンテキスト情報や、Httpヘッダ情報の取得について
         * UriInfoクラスをDIしてもらうことで、パスなどの情報が取得できます。
         * いろいろと取得できますが、サンプルではてきとうに1つピックアップしています。
         */
        @GET
        @Path("/restService9/")
        public String restService9(@Context HttpHeaders header) {
                String msg1 = "path : "+uriInfo.getPath();
                Map<String, List<String>> map = header.getRequestHeaders();
                
                StringBuilder builder = new StringBuilder();
                for (Map.Entry<String, List<String>> entry : map.entrySet()) {
                        builder.append("key : ").append(entry.getKey()).append("\n");
                        for (String value : entry.getValue()) {
                                builder.append("   "+value).append("\n");
                        }
                }
                return msg1+"\n"+builder.toString();
        }
}


RestRequest.java
package alctail.bean;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class RestRequest {
        
        private String name;
        private int age;
        
        
        public String getName() {
                return name;
        }
        public void setName(String name) {
                this.name = name;
        }
        public int getAge() {
                return age;
        }
        public void setAge(int age) {
                this.age = age;
        }
}


RestResponse.java
package alctail.bean;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class RestResponse {
        
        private String name;
        private int age;
        
        
        public String getName() {
                return name;
        }
        public void setName(String name) {
                this.name = name;
        }
        public int getAge() {
                return age;
        }
        public void setAge(int age) {
                this.age = age;
        }
}

JAX-RSでは、マーシャル・アンマーシャルをするクラスは、「@XmlRootElement」もしくは「@XmlType」がついていないといけないみたい。そうしないと、NoMessageBodyWriterFoundFailure例外が出る。
なので、RestRequestクラスとRestResponseクラスには@XmlRootElementをつけてあります。

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version="3.0">
        <display-name>RestStudy1</display-name>

        <servlet-mapping>
                <servlet-name>javax.ws.rs.core.Application</servlet-name>
                <url-pattern>/*</url-pattern>
        </servlet-mapping>
</web-app>

web.xmlは、JBossの場合これで動きます。ほかのアプリサーバーの場合このままでいいのか、変えなきゃいけないのかは不明。。。
url-patternに「/*」ではなく「/rs/*」を指定すると、上記サンプルを実行するURLは「http://(ホスト名)/(コンテキストルート)/rs/study1/restServiceX」と変化させることが可能です(「*」は書き忘れないように・・・)。