【Azure Functions】Java APIからDB(SQL Server)接続 (Win10)
事前準備
docker-composeを使ってSQL Serverをローカルで起動します。
Docker Desktop for Windows セットアップ
※すでにインストール済みであればこの手順はスキップしてください。
インストール
cinst docker-desktop -y
確認
$ docker -v
Docker version 19.03.5, build 633a0ea
$ docker-compose -v
docker-compose version 1.24.1, build 4667896b
Hyper-Vの設定
Docker for Windows を使用する場合、Hyper-Vの有効化が必要です。以下手順で有効化します。
- 「Win + i」で設定画面を開く
- アプリ > アプリと機能 > プログラムと機能 を開く
- Windowsの機能の有効化または無効化 を開く
- Hiper-V にチェックが入っていなければ、チェックして再起動する
データベース準備
前回の記事 で c:\TEST 以下にapiを作成したので、ここに docker-compose.yml を作成します。
c:\TEST\docker-compose.yml
version: '3'
services:
db:
image: mcr.microsoft.com/mssql/server:latest
ports:
- "1433:1433"
environment:
ACCEPT_EULA: Y
SA_PASSWORD: test1234@password
起動
$ cd c:\TEST
$ docker-compose up -d
Starting test_db_1 ... done
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8a32a712e45d mcr.microsoft.com/mssql/server:latest "/opt/mssql/bin/perm…" 44 minutes ago Up 12 seconds 0.0.0.0:1433->1433/tcp test_db_1
データベースとテーブル作成
起動したSQL Serverにデータベースを準備します。
# test_db_1コンテナに入る
$ docker exec -i -t test_db_1 bash
# SQL Server へ接続
mssql@8a32a712e45d:/$ /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P test1234@password
# データベース作成
1> CREATE DATABASE mydb COLLATE Japanese_Bushu_Kakusu_140_CS_AS_KS_WS;
2> go
1> use mydb
2> go
Changed database context to 'mydb'.
# membersテーブル作成
1> create table members(
2> id int identity(1,1) primary key,
3> name nvarchar(32),
4> created_at datetime
5> );
6> go
1> insert into members values
2> ('太郎', current_timestamp),
3> ('次郎', current_timestamp),
4> ('三郎', current_timestamp);
5> go
(3 rows affected)
# データ確認
1> select * from members;
2> go
id name created_at
----------- -------------------------------- -----------------------
1 太郎 2021-04-28 23:52:21.427
2 次郎 2021-04-28 23:52:21.427
3 三郎 2021-04-28 23:52:21.427
(3 rows affected)
長くなりましたがこれで事前準備が完了です。次に作ったテーブルをAzure Functionから利用する処理の実装です。
実装
ライブラリの準備
まずは基本中の基本である、JDBCを使ってデータベースへのアクセスを行います。JDBCはほとんどすべてのリレーショナルDBへアクセスできる標準Java APIです。
pom.xml
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.2.1.jre8</version>
</dependency>
Function側の処理
Function.java
前回の記事 で作成したFunctionの処理を次のように修正します。
// Parse query parameter
final String query = request.getQueryParameters().get("id");
int id = 0;
Map<String, String> response = new HashMap<>();
int status = 200;
String message = null;
// 入力パラメータのチェック
try {
if (request.getBody().orElse(query) != null) {
id = Integer.parseInt(request.getBody().orElse(query));
}
} catch (NumberFormatException nfex) {
status = 400;
message = "Invalid parameter";
}
if (status == 200) {
try {
// データベース接続
Driver driver = (Driver) Class.forName(
"com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
String connectionUrl =
"jdbc:sqlserver://localhost;database=mydb;"
+ "integratedSecurity=false;user=sa;password=test1234@password";
Connection connection = driver.connect(connectionUrl, new Properties());
// SQL実行
String sql = "select * from members where id = " + id + ";";
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery(sql);
// 結果を取得
if (result.next()) {
message = "Hello, " + result.getString("name");
} else {
status = 404;
message = "What's your name?";
}
result.close();
statement.close();
} catch (Exception e) {
// エラー処理
status = 500;
message = e.getMessage();
e.printStackTrace();
}
}
// レスポンスを作成
response.put("message", message);
HttpResponseMessage.Builder builder = request
.createResponseBuilder(HttpStatus.valueOf(status))
.header("Content-Type", "application/json");
builder.body(response);
return builder.build();
入力パラメータをString型のnameからint型のidとして受け取っているので数値チェックを行い、パラメータ不正はステータス400を返すようにします。
パラメータチェックが問題なければ、データベース接続 > SQL実行 > 結果処理を行います。また、検索結果が0件の場合は404を返却し、予期しないエラーが発生した場合は500を返すようにしました。
動作確認
※テストコードスキップでAPIを起動します。
mvn clean package azure-functions:run -Dmaven.test.skip=true
$ curl -i -X GET \
> 'http://localhost:7071/api/HttpExample?id=2'
HTTP/1.1 200 OK
Date: Thu, 29 Apr 2021 14:03:19 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
{
"message": "Hello, 次郎"
}
今回は単純な例のためFunction.javaにすべて処理を書きましたが、生産性を上げるための様々なライブラリが用意されているので次回以降でこの辺を見ていこうと思います。
コメント
コメントを投稿