SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事(AD)

JAX-RS/CDIのサポートでマイクロサービスの開発も容易に ~ Java EE 7正式対応で大幅強化された「WebSphere Application Server Liberty Core」

  • このエントリーをはてなブックマークに追加

ダウンロード sample.zip (87.5 KB)

4 CDIとJAX-RSを使ったWebサービスの作成

 今回は簡単なWebサービスとして、パラメータに7桁の郵便番号を渡すと、それに対応した住所を返すようなアプリケーションを実装してみる。実は『軽量・高速・安価で、安定性と信頼性も兼ね備えたWebSphere Application ServerのLiberty Coreを使ってみた』でも同様のサンプルを実装しているが、当時はJAX-RS 1.1とCDI 1.0の組み合わせだった。一方Java EE 7のWeb Profileでは、特に以下の点が従来と大きく異なっている。

  • CDIを使う際にbeans.xmlの定義が省略できるようになった
  • JAX-RSが正式にCDI連携に対応した
  • JSON形式のデータをJSON-Pで簡単に扱えるようになった
  • JAX-RSにクライアントAPIが追加された

 JAX-RSとCDIの連携については、JAX-RS 1.1は直接CDIには対応していなかったため、JAX-RSのリソースクラスをEJB連携機能を使ってEJB化することで、間接的にCDIを利用していた。それに対してJAX-RS 2.0は正式にCDIをサポートするようになったため、EJBを経由することなく直接CDIを使えるようになっている。

 では、早速実装していこう。プロジェクト名は「ZipcodeService」とした。

図4.1
図4.1

 まず、住所を表すAddressクラスを次のように定義する。

リスト4.2
public class Address {
    private String id;         // ID
    private String zip;        // 郵便番号
    private String address;    // 住所
    
    public Address(String id, String zip, String address) {
        this.id = id;
        this.zip = zip;
        this.address = address;
    }
    
    public String toString() {
        return this.id + ":" + this.zip+ ":" + this.address;
    }
    
    // Setter/Getterは省略
}

 住所データの一覧を扱うロジックは、AddressListクラスに次のように実装した。スコープは@ApplicationScopedを指定した。

リスト4.3
@ApplicationScoped
public class AddressList {

    private List<Address> addressList = new ArrayList<>();    // 住所のリストを格納
        
    public AddressList() {
        try {
            // csvファイルから郵便番号と住所のリストを読み込む
            URI uri = this.getClass().getResource("postalcode.csv").toURI();
            try (Stream<String> source = Files.lines(Paths.get(uri))) {
                this.addressList =
                    source.map(s -> new Address(s.split(",")[0], s.split(",")[1], s.split(",")[2]))
                        .collect(Collectors.toList());

            } catch(IOException ex) {
                ex.printStackTrace();
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 指定された郵便番号の住所データを検索して返す
     * @param zipcode 7桁の郵便番号
     * @return マッチしたAddressを格納したList
     */
    public List<Address> search(String zipcode) {
        List<Address> result = 
            this.addressList.stream()
                .filter(s -> s.getZip().equals(zipcode))
                .collect(Collectors.toList());
        return result;
    }
    
    /**
     * すべての住所データを返す
     * @return すべてのAddressを格納したList
     */
    public List<Address> getAll() {
        return this.addressList;
    }
}

 郵便番号データは日本郵便が公開している郵便番号データから、郵便番号と住所の情報のみ抽出し、一意のIDを付加したものをCSVファイルとして使用した。これをAddressListのコンストラクタで読み込んでListとして保持する。AddressListには、読み込んだ住所データから、指定された郵便番号の住所を検索して返すsearch()メソッドと、すべての住所データを返すgetAll()メソッドを用意している。

 JAX-RSのリソースクラスは、SearchAddressクラスとして次のような実装になった。

リスト4.4
@ApplicationScoped
@Path("/address")
public class SearchAddress {

    @Inject
    private AddressList addressList;    // データソース
    
    /**
     * すべての住所データを取得し、JSON形式で返す
     */
    @Path("all")
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public List<Address> all()
    {
        List<Address> address = addressList.getAll();
        return address;
    }
    
    /**
     * 指定された郵便番号の住所データを検索し、結果をJSON形式で返す
     */
    @Path("search")
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public List<Address> search(
                      @QueryParam("zip") String zipcode)
    {
        List<Address> address = addressList.search(zipcode);
        return address;
    }

    /**
     * JSON形式で指定された郵便番号の住所データを検索し、結果をJSON形式で返す
     */
    @Path("jsonsearch")
    @POST
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    public List<Address> jsonsearch(ZipRequestParam param)
    {
        List<Address> address = addressList.search(param.getZip());
        return address;
    }
}

 ポイントは、データソースとなるAddressListオブジェクトをCDIを利用して@Injectアノテーションでインジェクションしていることだ。こうすることで、SearchAddressクラスはAddressListの実装への依存を取り除くことができる。

 このクラスでは、Webサービスとして機能する3つのメソッドを用意している。1つはすべての住所データを取得するためのGETリクエストを提供するall()メソッドで、AddressListのgetAll()の実行結果をJSON形式で返す。リクエストパスは「/address/all」となるように設定している。レスポンスをJSON形式にするには、@Producesアノテーションを使って「@Produces({MediaType.APPLICATION_JSON})」を指定すればよい。

 2つ目は、「zip」パラメータで指定した郵便番号をGETリクエストとして受け取るsearch()メソッドである。このメソッドへのリクエストパスは「/address/search」となっており、AddressListのsearch()の結果をJSON形式で返す。

 3つ目は、JSON形式で指定されたパラメータをPOSTリクエストとして受け取るjsonsearch()メソッドで、リクエストパスは「/address/jsonsearch」とした。

 JSON形式でパラメータを受け取る場合は、@Consumesアノテーションを使って「@Consumes({MediaType.APPLICATION_JSON})」を指定すればよい。この例では、次の形式のJSONデータを受け取ることができる。

リスト4.5
{ "zip" : "整数7桁の郵便番号" }

 このJSON形式のパラメータを扱うためのクラスをZipRequestParamとして次のように定義した。

リスト4.6
public class ZipRequestParam {
    private String zip;  // 郵便番号

    public ZipRequestParam() {}
    
    public ZipRequestParam(String zip) {
        this.zip = zip;
    }

    // Setter/Getterは省略
}

 なお、all()、search()、jsonsearch()が返す結果のJSONデータは、いずれも複数の住所データに対応した次の形式になるようにしてある。メソッドの処理としてはListオブジェクトをreturnしているだけだが、これをJAX-RSがJSONの配列として取り扱ってくれる。

リスト4.7
[
  { "address" : "住所1", 
    "id"      : "ID1",
    "zip"     : "郵便番号1"},
  { "address" : "住所2",
    "id"      : "ID2",
    "zip"     : "郵便番号2"},
      ......
]

 JAR-RSを使用するために必要となるApplidationConfigクラスについては次のようにした。ルートパスを「ws」とし、リクエストを受け取るSearchAddressクラスを登録している。

リスト4.8
@javax.ws.rs.ApplicationPath("ws")
public class ApplicationConfig extends Application{
        
    public Set<Class<?>> getClasses(){
        HashSet<Class<?>> set = new HashSet<Class<?>>();
        set.add(SearchAddress.class);
        return set;
    }
}

次のページ
5 ZipcodeServiceを使った住所の検索

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

杉山 貴章(スギヤマ タカアキ)

有限会社オングスにて、Javaを中心としたソフトウェア開発や、プログラミング関連書籍の執筆、IT系の解説記事やニュース記事の執筆などを手がけている。そのかたわら、専門学校の非常勤講師としてプログラミングやソフトウェア開発の基礎などを教えている。著書に『Javaアルゴリズム+データ構造完全制覇』『Ja...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

【AD】本記事の内容は記事掲載開始時点のものです 企画・制作 株式会社翔泳社

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/8834 2015/08/05 10:39

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング