マイクロサービスを10分で作る-郵便番号検索サービス-Apache Camel


今回は試しに郵便番号から住所情報を検索できるサービスを作ってみる。

# マイクロサービスとは

このブログがよくまとまっていると思う
http://techlife.cookpad.com/entry/2014/09/08/093000

良い点

* 共通で利用できるサービスだったら言語関係なく呼べばいいだけなので便利！
* もしサービスが古くなって作り直しとなっても、作り直しの範囲が小さくなる。

悪い点

* サービスの数が増えるので、運用するサービスが増える。

### 今回のサンプル限定で考えると

良い点

* 各個別のアプリで郵便番号DBを持たなくて済む
* 郵便番号テーブルの最新化が１箇所で済む
* 郵便番号検索プログラムを個別のアプリで作らなくて済む
* 検索プログラムにバグがあっても、検索サービスだけ修正すればいいだけ。

### Apache Camelを使って作る事

英語の記事なので読める人だけ。 
http://java.dzone.com/articles/apache-camel-micro%C2%ADservice


# Apache Camelとは

Apache Camel ™ is a versatile open-source integration framework based on known Enterprise Integration Patterns.

ということで、色んなシステムと統合できるフレームワークであり、メッセージ流通なフレームワーク。
[Apache Camel (Java)を使うと開発が楽になる７つの理由](http://qiita.com/daikuro/items/5e22c78c0342fde04b87)

ちなみに、Camelが提供しているコンポーネント一覧はこんな感じ
https://twitter.com/davsclaus/status/506728047928942592/photo/1
全ては既存のOSSのライブラリをラップして動いているだけだけ。
とうとう170コンポーネント以上になったという事らしい。

# 環境

* Tomcat7, 8
* Java7, 8
* Apache Camel 2.14.0
* MySQL


# 完成したものを動かしてみる

作り方は下のほうに書くので、どういう動作結果になるかをまず見せる。


下記のURLにアクセスすると

http://localhost:8881/address/zip?zip=100-0000

アクセス結果

{"id":100000000,"ken_id":13,"city_id":13101,"town_id":131010000,"zip":"100-0000","office_flg":false,"delete_flg":false,"ken_name":"東京都","ken_furi":"トウキョウト","city_name":"千代田区","city_furi":"チヨダク","town_name":"","town_furi":"　","town_memo":"（該当なし）","kyoto_street":"","block_name":"","block_furi":"","memo":"","office_name":"","office_furi":"","office_address":"","new_id":0}

という結果が帰ってくる。

# Webブラウザで状態確認もできる

hawtio-default-1.4.19に関しては`デプロイ`の所に記述。
tomcatにデプロイするhawtioというツールでcamelの状態を確認できる。
アクセス方法は下記のような感じ
http://localhost:8080/hawtio-default-1.4.19

1つめのルート定義を確認。
http受信返信（rest）の処理

![スクリーンショット 2014-09-28 8.05.46.png](https://qiita-image-store.s3.amazonaws.com/0/37624/20690e1b-7429-aa6c-5fa1-d6af3895e9f6.png)

2つめのルートを確認。
郵便番号テーブルからデータを取得し、結果レコードの１番目を返す。

![スクリーンショット 2014-09-28 8.59.50.png](https://qiita-image-store.s3.amazonaws.com/0/37624/360a6e20-9824-49a5-76f7-21cf29e35c3f.png)

## アクセスしてみる
http://localhost:8881/address/zip?zip=100-0000

![スクリーンショット 2014-09-28 9.12.58.png](https://qiita-image-store.s3.amazonaws.com/0/37624/cbe62c05-434f-6241-0599-167881b9015a.png)

データが流れた部分に`1`が付いた

情報がないデータにアクセスしてみる
http://localhost:8881/address/zip?zip=999-0000

![スクリーンショット 2014-09-28 9.13.35.png](https://qiita-image-store.s3.amazonaws.com/0/37624/3d926c49-0927-8444-2560-a83049f66ca5.png)

データが流れた部分に1が付いた
振り分けられたようですね

## トレース機能をONにして、流通データを追跡

`start trace`ボタンをクリックして、データを流してみる。
データが流れた結果を後で確認できるのがトレース機能。

![スクリーンショット 2014-09-28 9.16.33.png](https://qiita-image-store.s3.amazonaws.com/0/37624/04366938-0623-0afd-8ec8-2d7a6eb99ebe.png)

![スクリーンショット 2014-09-28 9.30.54.png](https://qiita-image-store.s3.amazonaws.com/0/37624/bf0a6736-a09e-eda5-bcdf-854678bc1189.png)

![スクリーンショット 2014-09-28 9.31.03.png](https://qiita-image-store.s3.amazonaws.com/0/37624/e16f687f-2b72-affd-1187-e7ef8b618ab0.png)

![スクリーンショット 2014-09-28 9.31.22.png](https://qiita-image-store.s3.amazonaws.com/0/37624/86eb7773-0e13-2dd6-a585-de3d92e22f1d.png)

### 処理速度を確認

![スクリーンショット 2014-09-28 10.16.17.png](https://qiita-image-store.s3.amazonaws.com/0/37624/3dada5aa-7f17-50fd-cf2a-d19a704bd551.png)

テーブルにインデックスを設定していない為、検索に平均20ミリ秒もかかっている事が分かる・・・


# 作り方

## DBの作成 - 1分

ここからsqlをダウンロード
http://jusyo.jp/sql/document.html

mysqlに突っ込む

```
mysql -u ユーザー名 -p データベース名 < ファイル名
```

## プロジェクトを作成する - 1分

![スクリーンショット 2014-09-27 21.29.01.png](https://qiita-image-store.s3.amazonaws.com/0/37624/11c2e12b-6f06-3afb-d417-3ea52408a944.png)

![スクリーンショット 2014-09-27 21.29.12.png](https://qiita-image-store.s3.amazonaws.com/0/37624/c25e761c-52bc-ed3f-e982-6b0aecda0657.png)

![スクリーンショット 2014-09-27 21.29.23.png](https://qiita-image-store.s3.amazonaws.com/0/37624/9f4c983d-01fa-4b73-427e-4524bbf88e53.png)

![スクリーンショット 2014-09-27 21.30.06.png](https://qiita-image-store.s3.amazonaws.com/0/37624/657192a4-d5cc-2873-7846-e61c27fec504.png)

![スクリーンショット 2014-09-27 21.31.51.png](https://qiita-image-store.s3.amazonaws.com/0/37624/de4d2aff-da21-3dae-0ebb-a782c4681e66.png)

![スクリーンショット 2014-09-27 21.32.08.png](https://qiita-image-store.s3.amazonaws.com/0/37624/e26a90e8-c5bd-62c8-d7a6-e61494cf64ab.png)

![スクリーンショット 2014-09-27 21.32.48.png](https://qiita-image-store.s3.amazonaws.com/0/37624/ece04329-9550-af5e-7912-50b6602bf755.png)


![スクリーンショット 2014-09-27 21.33.26.png](https://qiita-image-store.s3.amazonaws.com/0/37624/0bf46328-e266-059c-7f96-26fa17680098.png)


## いろいろ設定 - 4分

pom.xmlはこんな感じ
https://github.com/d7kuro/post/blob/master/pom.xml

web.xmlはいつものコピペ
https://github.com/d7kuro/post/blob/master/src/main/webapp/WEB-INF/web.xml

spring.xmlはいつものコピペ
https://github.com/d7kuro/post/blob/master/src/main/resources/spring.xml

spring-db.xmlはいつものコピペ
https://github.com/d7kuro/post/blob/master/src/main/resources/spring-db.xml

spring-camel.xmlはrestConfigurationが付いた。ここでrestのport番号が決まっている

```src/main/resources/spring-camel.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.14.0.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       ">

	<!-- ルートの自動登録（サブディレクトリも検索される） @Componentが対象 -->
	<context:component-scan base-package="post" />

	<!-- SQLコンポーネントの全共通デフォルト値を設定 -->
	<bean id="sql" class="org.apache.camel.component.sql.SqlComponent">
		<property name="dataSource" ref="ds_mysql" />
	</bean>

	<!-- camelルート -->
	<camelContext xmlns="http://camel.apache.org/schema/spring"
		id="post">
		<contextScan />
		<restConfiguration component="jetty" host="0.0.0.0"
			port="8881" bindingMode="json" >
		</restConfiguration>
	</camelContext>

</beans>
```




## プログラムを作る - 3分


郵便番号検索用ルートを作成

```java:src/main/java/post/route/api/AddressRoute.java
package post.route.api;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.sql.SqlConstants;
import org.springframework.stereotype.Component;

/**
 * 000-0000形式の郵便番号からjsonデータを返す
 */
@Component
public class AddressRoute extends RouteBuilder {

	public static final String CLASSNAME = AddressRoute.class.getSimpleName();
	public static final String IN = "direct:in" + CLASSNAME;

	@Override
	public void configure() throws Exception {
		from(IN).routeId(CLASSNAME)
		
		// SQL実行
		.to("sql:SELECT * FROM ad_address WHERE zip = :#zip ")
		
		// 見つからなかった時の処理
		.choice()
		.when(header(SqlConstants.SQL_ROW_COUNT).isEqualTo(0))
			.setBody(constant(null))
		.otherwise()
			// 結果データ作成（List<Map>の0番目のデータを返却）
			.setBody(simple("${body[0]}"))
		.end()
		;
	}

}
```




HTTP受信用ルートを作成

```java
package post.route;

import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

import post.route.api.AddressRoute;

/**
 * HTTP受信 <br>
 * 返却値は自動的にjsonに変換される 
 * 
 */
@Component
public class HttpRoute extends RouteBuilder {

	@Override
	public void configure() throws Exception {
		rest("/address")
		.get("/zip").to(AddressRoute.IN);
	}

}
```

## ビルド・デプロイ - 1分

### warファイルを作成

maven clean package を実行
target/post-1.warができる。

![スクリーンショット 2014-09-28 16.02.29.png](https://qiita-image-store.s3.amazonaws.com/0/37624/1d7607df-d3b3-2759-76e1-fd6129360119.png)



![スクリーンショット 2014-09-28 15.58.52.png](https://qiita-image-store.s3.amazonaws.com/0/37624/523f145c-e8ce-935c-1708-f5b900d8086c.png)



### ブラウザでCamelの状態を確認・操作できるツールを入手

hawtio-default-1.4.19.warをダウンロード
( http://hawt.io/getstarted/index.html からダウンロード)


### tomcatにデプロイ

* post-1.war
* hawtio-default-1.4.19.war

上記のファイルを下記のフォルダにコピーするだけ
tomcat/webapps/


全体のソースコード
https://github.com/d7kuro/post


お
わ
り