DynamoDBの情報を読み込んでJavaFXで表示してみる

# この記事について

将来的に書く予定の「JavaFX で DynamoDB Viewer作ってみた」記事の１ステップ。
結構大きな話になると思うので、少しずつ技術ポイント毎に記事を書いて、ある一定程度の要件を満たせた段階で前述まとめ記事書く予定。今回は、基本技術確認まで。

# 背景

業務や趣味でDynamoDBを使用している。少しのデータならAWS管理コンソールや [NoSQL Workbench for DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.html) が存在するものの、どうもしっくりこない。表示可能なデータ量少ないし、カラム幅の変更などの操作も微妙に遅い。大体痒いところに手が届かない。
調べると結構Viewer作っている人はいるものの、大体サービス起動してブラウザで見る形式。
GoogleSpreadSheetレベルに完成度が高いブラウザツールがあったらそれを使いたいが、今のところ見当たらない。なので作ってしまおうという事。

# 開発環境

Eclipse Neon
JavaFX Scene Builder 2.0
※著者は結構前にインストールしたのを使ってるので古いです。

# 要件

- スタンドアロンのツールにする。
- LinuxでもWindowsでも動くようにする
- GUIでもCUI（ファイル出力とか）でも使えるようにする
- １つのフィールドにJSON形式などで保存されてるデータも参照したい

# 技術選定

## GUI

要件からほぼ JavaFX 一択。ブラウザで見る形式は取りたくない。
JavaFXはJDK11からは標準装備ではなくなったけど、[OpenJFX](https://openjfx.io/) として続いている模様。何となくJava8用とJava11用ビルドの２種類が必要になりそうな気配。
何にせよ、先が無い技術というわけでもない。実際今回の様な案件にはピッタリなので需要が無くなるという気がしない。

※2021-01-21 追記
java11でも別ビルドにする必要なく動きました。こちらがその際に参考にさせて頂いたページです。
[Java11でJavaFXを動かす](https://qiita.com/tsudon/items/ea2e78171e32b3cb1578)

## 基本ライブラリ

JDBCがあれば使いたいが、[CData社製](https://www.cdata.com/jp/drivers/dynamodb/jdbc/?gclid=Cj0KCQiA9P__BRC0ARIsAEZ6irhYz1-mV4Mv0v71sEQFSvScsHXq0OPPQYWVMnmIsuckIIU-nJ2rhnwaAqVuEALw_wcB) の様に有料のものしかなさそう。
趣味のものなのでお金使いたくない。[aws-sdk-java-v2](https://github.com/aws/aws-sdk-java-v2/#using-the-sdk) を使う。

# 準備

## mavenプロジェクト（pom.xml）作成

```bash
mvn archetype:generate -DgroupId=com.silverboxsoft -DartifactId=dynamodbtool -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
```

dynamodbtool フォルダ及び、基本フォルダが作成される。

## EclipseにImport

```bash
cd dynamodbtool
mvn eclipse:eclipse
```

Eclipseを起動し、File => Import。Existing Project into Workspace を選び、dynamodbtool フォルダを選択。

## .gitignoreファイル作成

dynamodbtool 直下に以下内容でフ.gitignore ファイル作成

```text:.gitignore
target
```
## dependency追加

[公式サイト](https://github.com/aws/aws-sdk-java-v2/#using-the-sdk) に従い、以下をpom.xml

```xml:pom.xmlのprojectブロック配下に追加
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>bom</artifactId>
        <version>2.15.64</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
```

```xml:pom.xmlのdependenciesブロック配下に追加
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>dynamodb</artifactId>
    </dependency>
```

再度コンソールで mvn eclipse:eclipse 実行して、EclipseのプロジェクトをRefresh

```console
mvn eclipse:eclipse
```
※以後 pom.xml変更後は同じことする。

# Queryしてみる

## コードコピー

[サンプルコード](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb) を真似る。
サンプルの [Query.java](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/Query.java) の中身をまるっとApp.java（自動生成されたソース）にコピーし、package名、class名、リージョン指定部分だけ変える（元に戻す）。

```java:App.java
package com.silverboxsoft;
// 中略
public class App {
// 中略
Region region = Region.AP_NORTHEAST_1;
// 後略
```

## 認証情報

AWS SDKのセットアップを終わらせておく。
もしくは Eclipse の Run => RunConfigurationで、Environmentタブにて、以下の変数と値を追加

- AWS_ACCESS_KEY_ID=your_access_key_id
- AWS_SECRET_ACCESS_KEY=your_secret_access_key

## テスト実行

EclipseのRunConfigurationで、ProgramArgumentに「テーブル名 主キー名 主キー値」の形式で指定。今回は[自分用の家計簿ツール](https://qiita.com/silverbox/items/18036bb08f16618c21f5) で使用しているテーブルを使用。「account_balance tgt_date 20200208」を指定。

```console:結果
Querying account_balance
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
There were 3record(s) returned
```

単純な処理だが、DynamoDBへのアクセスに成功。次のステップに移る。

# JavaFX準備始

## Scene Builderのインストール

すいませんが、ここは検索すると良記事がたくさん出てくるのでそちらを参考にお願いします。

## 画面デザイン作成

Scnene Builderで、File => New From Template => Basic Application

- 左ペインのDocument => Controller の Controller classに、「com.silverboxsoft.controller.DynamoDbToolController」を指定（後でjavaクラスで作成する）。
- ButtonとTableView配置
- Button の Inspector => Code の On Action に ```actLoad``` を指定（後で関数で作成する）
- TableView の Inspector => Code => fx:id に```tableResultList```を指定
- TableViewに　TableColumn を追加して３つにする。
- TableColumn の fx:id にそれぞれ```tableColTgtDate```、```tableColTargetCd```、```tableColValue```を指定

```src/main/resources/com/silverboxsoft/controller/javafx/DynaboDbToolController.fxml``` に保存

## pom.xml に起動クラス指定

ついでにエンコーディングやjavaバージョン指定

```xml:pom.xml
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <start-class>com.silverboxsoft.App</start-class>
  </properties>
```
※修正後はお約束の```mvn eclipse:eclipse```とEclipseのプロジェクトRefresh

## メインクラス変更

コピーして作っていたDynamoDBへの接続テスト部分は削除

```java:App.java
package com.silverboxsoft;

import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

// Application クラスを継承する
public class App extends Application {

	public static void main(String[] args) {
		launch(args);
	}

	@Override
	public void start(Stage stage) throws Exception {
		prepareControl(stage);
		stage.show();
	}

	private void prepareControl(Stage stage) throws IOException {

		FXMLLoader fxmlLoader = new FXMLLoader(
				getClass().getResource("controlloer/javafx/DynamoDbToolController.fxml"));
		// Templateで作成されるデザインのルートコンテナが VBoxの為
		VBox newPane = (VBox) fxmlLoader.load();

		Scene scene = new Scene(newPane);
		stage.setTitle("DynamoDB Tool");
		stage.setScene(scene);
	}
}
```

## java側コントローラークラス作成

```java:DynamoDbToolController.java
package com.silverboxsoft.controller;

import java.net.URL;
import java.util.ResourceBundle;

import com.silverboxsoft.dao.AccountBalanceDao;
import com.silverboxsoft.model.AccountBalance;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;

// Initializable を継承
public class DynamoDbToolController implements Initializable {

	// 画面デザイン上のコンポーネントと結びつける
	@FXML
	TableView<AccountBalance> tableResultList;

	@FXML
	TableColumn<AccountBalance, String> tableColTgtDate;

	@FXML
	TableColumn<AccountBalance, String> tableColTargetCd;

	@FXML
	TableColumn<AccountBalance, Long> tableColValue;

	@Override
	public void initialize(URL location, ResourceBundle resources) {
		setTableColumns();
	}

	// ボタンに指定したアクションと結びつける
	@FXML
	protected void actLoad(ActionEvent ev) {
		AccountBalanceDao dao = new AccountBalanceDao();

		// 今回はテストなのでベタ打ち
		tableResultList.getItems().clear();
		tableResultList.getItems().addAll(dao.getBalanceListAtOneDay("20200208"));
	}

	// カラムとデータクラスメンバの結び付け
	private void setTableColumns() {
		tableColTgtDate.setCellValueFactory(new PropertyValueFactory<AccountBalance, String>("tgtDate"));
		tableColTargetCd.setCellValueFactory(new PropertyValueFactory<AccountBalance, String>("methodCd"));
		tableColValue.setCellValueFactory(new PropertyValueFactory<AccountBalance, Long>("value"));
	}
}
```

## その他Daoやmodelクラス

今回の主目的とは違う部分なのでgithubで。
[Dao](https://github.com/silverbox/dynamodbtool/blob/1st-simpleload/src/main/java/com/silverboxsoft/dao/AccountBalanceDao.java)
[Model](https://github.com/silverbox/dynamodbtool/blob/1st-simpleload/src/main/java/com/silverboxsoft/model/AccountBalance.java)

## 各ソースの関係まとめ

- pom.xml で Application クラスを継承した起動クラス指定
- 起動クラス内で、fxmlファイルを読み込む。
- fxmlファイルで、結びつくControllerクラスを指定
- fxmlファイルで、Controllerで使用するコンポーネントのfx:idを指定して@FXMLアノテーションで結び付ける
- fxmlファイルで、ボタンのアクション関数名を指定して、Controllerの関数と@FXMLアノテーションで結びつける

## 変なエラーが出たら

```console
restriction on required library 'C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar'
```
というエラーが出たら、[EclipseでJavaFXを使おうとするとアクセス制限とでる問題の解決方法](http://informationstudent.blog.fc2.com/blog-entry-20.html) を参考に、環境設定＞Java＞コンパイラー＞エラー警告＞「使用すべきでない制限されたAPI」の「禁止された参照（アクセス・ルール）」を「エラー」から「無視」に変更

## 現在の画面

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530376/fc76463c-22bb-787e-2292-4f66ca97377f.png)

# 今後のステップ

今はテーブルは固定カラム。今回作成するのは汎用DBツールなのでそこを動的に判断して処理する必要がある。
テーブルリスト表示や、接続先の指定なども可能にしたい。細かい読み込み指定もしたい。

# 参考にさせて頂いたページ

※2021-01-21 追記
[Java11でJavaFXを動かす](https://qiita.com/tsudon/items/ea2e78171e32b3cb1578)