スマートデバイスアプリ開発のあれやこれや

Spring Bootで作る簡単WebAPI

サーバ通信を行うスマホアプリを開発する際にデータをやり取りするWebアプリ
(※httpでリクエストするとJSONで結果を返す類のWebAPI)が必要だったので
何とか簡単に作れないかと模索ところ、Spring Bootがなかなか便利だった。


最大の便利ポイントはAPサーバ(Tomcat)を組み込んだ.jarファイルが作れるところ。
関係者に展開するときに”.jarファイルをjava -jarで実行すりゃいいよ!”で済むのが良い。
(関係者の環境で”動かない!”とか言われて揉めるのを避ける効果がある!)


手順をさらっとまとめてみます。
ちなみに検証環境は以下の通り。

1. Mavenプロジェクトを作る

Eclipseのプロジェクト作成ウィザードからMavenプロジェクトを選択する。
最近、Mavenを使い始めた初心者だけど、ライブラリ同士のバージョン関係をいっさい
考えなくても必要なライブラリ一式がゴッソリ入手出来る点が素晴らしいです。
(ただ、相手側もMaven知ってる前提じゃないとソース展開が面倒)

ちなみにMavenプロジェクトのarchetypeは指定なしで良いです。
「Create a Simple Project」をしれっと選択して次に進む。
artifacatIdやgroupId、バージョンは任意の設定でOK。

2. pom.xmlファイルを編集する

必要なライブラリの依存関係を定義するpom.xmlファイルを編集する。

  <parent>
  	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.0.2.RELEASE</version>
  </parent>

まず、parent要素に上の内容を追記。
Spring Bootを使う上での必要ライブラリ諸々が定義された
親のpom.xmlファイルを入手しますよ......という意味だと思う。
後述のdependencyも親のpom.xmlの利用が前提になっている。

  <dependencies>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-web</artifactId>
  	</dependency>
  </dependencies>

続いて本命のSpring Boot本体を取得する依存性設定を追加する。

この状態で保存して、プロジェクト右クリック Maven --> Update Projectを実行。
これでインターネットから必要なライブラリがローカルにダウンロードされる。
Maven Dependencies」にjarファイルが入ってれば成功。

3. Controllerクラスを作る

クライアントからのリクエストを受け付けるControllerクラスを作る。

@Controller
@EnableAutoConfiguration
public class SampleController {
	// これからメソッド書いていくよ!

ポイントはクラスに付けてるアノテーション「@EnableAutoConfiguration」。
このアノテーションが付くことで「Spring Bootよ!面倒な設定は任せた!」という
殿様的な伝令が発せられ、疲弊した開発者は面倒な設定から解放される。

4. リクエストを受け付けるメソッドを作る

Controllerクラスにリクエストを受け付けるメソッドを作っていく。
メソッドの戻り値はListでもHashMapでも独自クラスでも何でも良い。
指定したクラスの中身がJSONになってクライアントに返却されるので
開発対象のサービスの仕様次第で柔軟に変えるとハッピー。

@Controller
@EnableAutoConfiguration
public class SampleController {
	
	@RequestMapping("/service")
	@ResponseBody
	public List<String> top() {
		List<String> list = new ArrayList<String>();
		list.add("太宰");
		list.add("夏目");
		return list;
	}

ポイントはメソッドに付けてるアノテーション
@RequestMappingでは、メソッドに紐付いたURLを設定する。
上のtopメソッドの場合「http://localhost:8080/service」というURLが対応する。
@ResponseBodyは端的にいうと「JSONを返却するよ!」という宣言である。


これらのお膳立てが出来た状態で何らかのクラスを返却してやると
そのクラスの中身がJSONに変換されてクライアントに送られる動きになる。

クライアントからのリクエストパラメータを元に
何か処理を制御したい場合、@RequestParamアノテーションを駆使して、
valueでパラメータ名、その後のメソッド引数に対応する型と変数名を
指定してやることでメソッド内で簡単にパラメータを扱うことが出来る。

@Controller
@EnableAutoConfiguration
public class SampleController {
	
	@RequestMapping("/service")
	@ResponseBody
	public List<String> top(@RequestParam(value="name", required=false) String name) {
		List<String> list = new ArrayList<String>();
		if (name == "hoge") {
			list.add("芥川");
		} else {
			list.add("江戸川乱歩");
		}
		list.add("太宰");
		list.add("夏目");
		
		return list;
	}

4. mainメソッドを作る

Spring Bootを使ったアプリは、コンソールのJavaプログラムのように
mainメソッドから実行される仕様であるため、mainメソッドを作っていく。

	public static void main(String args[]) {
		SpringApplication.run(SampleController.class, args);
	}

mainメソッドでは、SpringApplication.runメソッドを実行する。
引数になるのは最初に作ったControllerクラスである。

5. 実行する

「mvn spring-boot:run」で実行する。
コンソールにSpring Bootのロゴやらログが表示される。
最後に「Started SampleController in 2.326 seconds」とか出たら成功。

6. アクセスしてみる

http://localhost:8080/service」にリクエストを送ってみる。
上手くいけば以下のようにブラウザで結果が見て取れる。

f:id:cross-xross:20150331215249p:plain

オマケ. 単体で実行可能なjarファイルを作る

pom.xmlに追加設定を加えれば単体実行可能な.jarファイルも作成出来る。

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <mainClass>jp.co.cross_xross.controller.SampleController</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>

mainClassにmainメソッドを実装したクラス名を指定するところがミソ。


この状態で「mvn package」を実行すると
targetディレクトリに単体実行可能な.jarファイルが生成される。
実行する場合は「java -jar xxxx.jar」で良いので非常に簡単。

Glassfish 4.1 + MySQL でデータソース定義

ソースコードからデータベースに対して直接コネクションを張ることも出来るが
どうもアプリ→データベースで接続&切断を行うのはコストが高いらしい……。
なので、お作法としてはAPサーバにデータベースとのコネクションを持たせておいて
アプリはAPサーバからコネクションを拝借する方がベターなのだという!
(アプリ全体で接続数は◯◯個とかの制限をかけてコネクションの使い回しが可能)

今回は以下のレシピでAPサーバにデータソース定義をしてみようと思う。

1. MySQL用のJDBCコネクタを入手する。

GlassfishMySQLにアクセスためにはJDBCコネクタが必要である。
Oracleの以下のサイトから入手する。

MySQL :: Download Connector/J

zipファイルに同梱されているmysql-connector-java-5.0.8-bin.jarを
glassfish4/glassfish/domains/domain1/lib/extにコピーしておく。

2. Glassfishの管理コンソールを表示する

Glassfishが起動した状態でhttp://localhost:4848を開くと管理コンソールが表示される。

f:id:cross-xross:20150223203700p:plain

この管理コンソールは今回解説するデータソースの定義以外にも
サーバのログの確認やクラスタ構成の設定等もGUIから出来るようだ。

3. 管理コンソールからJDBC Connection Poolを設定する

左メニューからJDBCJDBC Connection Poolを選択する。
「New...」ボタンを押下し、接続情報を入力していく。

  • Pool Name: 任意(今回はmysqlPoolにしておく)
  • Resource Type: javax.sql.DataSource
  • Database Driver Vendor: MySQL


Additional Propertiesには最低限以下の情報を入力する。

  • DatabaseName: 接続先DB名
  • User: 接続用のDBユーザ
  • Password: 接続用のDBユーザパスワード
  • ServerName: サーバアドレス

以上の情報を入力して「Finish」ボタンを押下する。

4. 接続確認する

Ping」ボタンを押下して成功メッセージ出れば完成。

f:id:cross-xross:20150225215657p:plain

Mac標準のApacheでクライアント認証環境を構築する

前回はSSL環境を構築しました。

今回は前回の内容を踏まえてクライアント認証環境の構築方法をまとめようと思います。
前提環境は前回と同じです。

1. 認証局(CA)の秘密鍵と証明書署名要求を作成する

クライアント認証環境実現のポイントは,
サーバ証明書作成のコマンド実行時に「認証局証明書」と「秘密鍵」を指定する点です。

そのため,前回作成していない認証局秘密鍵と証明書署名要求を作成します。
出力するファイル名が異なるだけで,コマンド内容はサーバ証明書を作ったときと同じです。

openssl req -new -keyout ca.key -out ca.csr -rand rand.dat


前回は秘密鍵と証明書署名要求を分けて作成しましたが,
以上のようなコマンドを実行することで同時に作成することも可能です。

なお,サーバ証明書を作成した時と同様に
国情報や市区町村の情報の入力を求められるので前回同様に入力します。

2. 認証局の証明書を作成する

認証局秘密鍵認証局の証明書署名要求を元に認証局用の証明書を作成します。

openssl x509 -req -signkey ca.key -in ca.csr -days 365 -sha1 -out ca.crt

生成された認証局証明書は,apacheからアクセス出来る場所
(例: /private/etc/apache2以下)に置いておきましょう。

3. サーバ証明書を作成する

クライアント認証を行う場合,サーバ証明書認証局証明書と紐づくので
新しく作りなおす必要があります。

必要なファイルは以下の通りです。

openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 -sha1 -in server.csr -out server.crt

生成されたサーバ証明書は,apacheからアクセス出来る場所
(例: /private/etc/apache2以下)に置いておきましょう。

4. クライアント証明書を作成する

正規ユーザに配布するクライアント証明書を作成します。
必要なファイルは以下の通りです。

  • サーバの秘密鍵(server.key)
  • サーバの証明書(server.crt)
  • 認証局の証明書(ca.crt)
openssl pkcs12 -export -inkey server.key -in server.crt -certfile ca.crt -out server.p12

opensslの「pkcs12」コマンドは,証明書と秘密鍵をまとめて
.p12型式で出力する機能を提供しています。

これでクライアント証明書(server.p12)ファイルが生成されます。
このファイルを正規のユーザに配布してください。

5. apacheの設定を変更する

SSL環境構築時に編集した「httpd-ssl.conf」ファイルを再び編集します。

sudo vi /private/etc/apache2/extra/httpd-ssl.conf

編集する箇所は以下の通りです。

#SSLCACertificateFile "/private/etc/apache2/ca.crt"
↓
SSLCACertificateFile "/private/etc/apache2/ca.crt"

#SSLVerifyClient require
#SSLVerifyDepth  1
↓
SSLVerifyClient require
SSLVerifyDepth  1

1点目の変更では,認証局用の証明書をApacheに認識させます。
2点目の変更では,クライアント確認処理を有効にして
クライアント証明書の存在チェックする認証局証明書の数を指定します。
(今回はca.crt単体なので,1を指定すれば良いです)

変更を保存したら,Apacheを再起動しましょう。

sudo apachectl restart

6 結果確認

では,「https://localhost」にアクセスしてみましょう。
クライアント証明書を選択するダイアログが表示されれば成功です。

Mac標準のApacheでSSL環境を構築する

Macにデフォルトで入っているApacheを使ったSSL環境を作ってみました。
環境の概要は以下の通りです。

  • Apache: 2.4.9
  • OpenSSL: 0.9.8za

次回はクライアント認証対応版の環境構築について書きたいです!

1. サーバ秘密鍵用の乱数ファイルを作成する

サーバ側が保持する秘密鍵作成時に必要な乱数ファイルを作成します。

openssl dgst -md5 /var/log/system.log > rand.dat


opensslのコマンドで「dgst」を指定することで,
後で指定する文字列(system.logの中身)を入力とした乱数を生成します。
(ここではsystem.logを指定していますが,実際はテキストファイルだったら何でもOK)

ちなみにオプションの「-md5」は乱数生成のアルゴリズムの指定です。
結果,生成される乱数はrand.datファイルに保存されます。

2. サーバ秘密鍵を作成する

サーバ秘密鍵を作成します。
秘密鍵は,クライアントから送信された共通鍵(暗号化済み)を復号化する際に利用します。

openssl genrsa -des3 -rand rand.dat 1024 > server_key.pem


opensslのコマンドで「genrsa」を指定することで,RSA秘密鍵を生成します。
オプションの「-des3」は,暗号化アルゴリズムの指定です。
秘密鍵の作成には乱数が必要になるので「-rand」オプションで前述の
手順で作成した乱数(rand.datファイル)を指定しています。
最後の「1024」は秘密鍵のビット数指定です。

作成した鍵は「server_key.pem」という名前で保存します。

Generating RSA private key, 1024 bit long modulus
................++++++
...............................++++++
e is 65537 (0x10001)
Enter pass phrase:
Verifying - Enter pass phrase:


パスワードの入力を求められるので任意のパスワードを2回入力します。

3. サーバ秘密鍵のパスワードを削除する

前述の手順で作成したサーバ秘密鍵にはパスワードが付いています。
そのままだとApache再起動時にパスワードを求められて面倒なので,
パスワードを削除した秘密鍵に加工します。

openssl rsa -in server_key.pem -out server_key.pem


rsaコマンドは,秘密鍵を表示/操作するためのコマンドです。
具体的にいうと「-in」で指定した鍵からパスワードを取り除き
「-out」で指定した名前で保存し直します。

Enter pass phrase for server_key.pem:
writing RSA key

秘密鍵作成時に指定したパスワードの入力を求められます。

3.証明書署名要求(CSR)ファイルを作成する

サーバ証明書の元データ(これに署名することで証明書になる)である
証明書署名要求ファイルを作成します。

openssl req -new -key server_key.pem -out server_csr.pem


「req」は,証明書署名要求を作成するためのコマンドです。
オプションの「-new」は,新規作成時に指定するお約束みたいです。
「-key」は,公開鍵(≒証明書署名要求)に対応した秘密鍵ファイルを指定します。
「-out」で,出力する署名要求のファイル名を指定します。

コマンド実行後は,対話型式で以下の情報の入力を求められます。

  • Country Nmae(国名):JP
  • State or Province Name(都道府県): Kyoto
  • Locality Name(市町村): Kyoto
  • Organization Name(組織名): Red Libbon Army
  • Organizational Unit Name(部署名): Labo
  • Common Name(サーバ名):localhost
  • Email Address(メールアドレス): hoge@example.com
  • A challenge password(証明書破棄時に必要なパスワード):なし
  • An optional company name(別の組織名):なし

4. 自己署名証明書を作成する

前述の手順で作成した証明書署名要求を元に証明書を作成します。

openssl req -days 365 -in server_csr.pem -key server_key.pem -x509 -out crt.pem


再び「req」コマンドで,証明書を作成します。
「-days」オプションでは,証明書の有効期限を指定しています。
「-in」オプションでは,署名対象の署名要求ファイルを
「-key」オプションでは,公開鍵に対応した秘密鍵ファイルを指定します。
「-out」で,出力する証明書のファイル名を指定します。

これまでの成果物は以下の4つです。

以降の手順で必要なファイルは以下の2つです。

  • server_key.pem
  • crt.pem

これらのファイルはApacheの設定ファイルと後で
紐付けるのでリネームして別の場所にコピーしておきます。

sudo cp server_key.pem /private/etc/apache2/server.key
sudo cp crt.pem /private/etc/apache2/server.crt

5. Apacheの設定ファイル(httpd.conf)を変更する

Apacheの設定ファイルを変更してSSL通信を行う準備を行います。
具体的には「/private/etc/apache2/httpd.conf」を編集していきます。

cd /private/etc/apache2
sudo vi httpd.conf

変更箇所は3箇所です。

#LoadModule ssl_module libexec/apache2/mod_ssl.so
↓
LoadModule ssl_module libexec/apache2/mod_ssl.so

#LoadModule socache_shmcb_module libexec/apache2/mod_socache_shmcb.so
↓
LoadModule socache_shmcb_module libexec/apache2/mod_socache_shmcb.so

# Secure (SSL/TLS) connections
#Include /private/etc/apache2/extra/httpd-ssl.conf
↓
Include /private/etc/apache2/extra/httpd-ssl.conf


この変更により,ApacheSSL通信に必要な依存ライブラリと
設定ファイル(httpd-ssl.conf)をロードするようになります。

6. SSL用の設定ファイル(httpd-ssl.conf)を編集する

いよいよ大詰めです。
前述の手順で作成した秘密鍵と証明書を読み込むように
設定ファイル(httpd-ssl.conf)を編集します。

cd /private/etc/apache2/extra
sudo vi httpd-ssl.conf


変更箇所は以下の2箇所です。

#SSLCertificateFile "/private/etc/apache2/server.crt"
↓
SSLCertificateFile "/private/etc/apache2/server.crt"

#SSLCertificateKeyFile "/private/etc/apache2/server.key"
↓
SSLCertificateKeyFile "/private/etc/apache2/server.key"

すでにコメントアウトされているなら編集は不要です。

7. Apacheを再起動する。

動作確認です。
以下のコマンドでApacheを再起動しましょう。

sudo apachectl restart

ブラウザのアドレスバーに「https://localhost」を入力して
次の図のような画面が表示されればひとまず成功です。

f:id:cross-xross:20150114233529p:plain