デモ
GitHub PagesとHerokuでホスティングしています。
Herokuは無料プランのため、初回の画面表示に時間がかかります。
ソースコード
アーキテクチャ
アーキテクチャの構成要素
front
シングルページアプリケーションのクライアントです。
構成要素 | 説明 |
---|---|
TypeScript | Microsoftが開発した、プログラミング言語です。 JavaScriptに「静的型付け」と「クラスベースのオブジェクト指向」をもたらします。 |
Angular | Googleが開発した、フレームワークです。 フルスタックであり、フロントエンドに必要な機能が揃っています。 |
PrimeNG | トルコのPrimeTek Informaticsが開発した、UIコンポーネントライブラリです。 高機能なUIコンポーネントが揃っています。 |
back
WebAPIを提供するサーバーです。
構成要素 | 説明 |
---|---|
Java | 「静的型付け」で「クラスベースのオブジェクト指向」のプログラミング言語です。 |
Spring Boot | 支持率の高い、フレームワークです。 |
H2 Database | 軽量なデータベースです。 手軽に利用するために、サーバーに組み込んでいます。 |
MyBatis | データベースを操作する、フレームワークです。 後述する、MyBatis Generatorで自動生成しています。 |
springdoc‑openapi | Spring Bootをもとに、OpenAPIを自動生成するライブラリです。 後述する、OpenAPI Generatorのために、自動生成しています。 |
back-dao-generator
データベースを操作するための、プログラムを自動生成します。
構成要素 | 説明 |
---|---|
MyBatis Generator | MyBatisのプログラムを、自動生成するツールです。 |
front-api-generator
WebAPIを呼び出すための、プログラムを自動生成します。
構成要素 | 説明 |
---|---|
OpenAPI Generator | WebAPIを呼び出すプログラムを、自動生成するツールです。 さまざまなプログラム言語/フレームワークにむけて、自動生成できます。 |
特徴
プログラムの自動生成
データベースを操作するためのプログラム
つぎのプログラムを自動生成しています。
これらを使って、つぎのようにデータベースを操作できます。
// プライマリキーで、SELECTする。
public Optional<Sample> selectByPrimaryKey(Integer id) {
return Optional.ofNullable(sampleMapper.selectByPrimaryKey(id));
}
// プライマリキーで、UPDATEする。
public void updateByPrimaryKey(Sample sample) {
sampleMapper.updateByPrimaryKey(sample);
}
// FIELD_TEXTというカラムで、SELECTする。
public List<Sample> selectByFieldText(String fieldText) {
var example = new SampleExample();
example.createCriteria().andFieldTextEqualTo(fieldText);
return sampleMapper.selectByExample(example);
}
たったの3行で、SELECTできます!
SQLを書いたり、DTOを作ったり、、の作業から解放されます!
Javaでデータベースを操作するなら、
ほかにもJPAなどがありますが、SIerにはMyBatisが最適かな?と思っています。
WebAPIを呼び出すためのプログラム
つぎのプログラムを自動生成してます。
これらを使って、つぎのようにWebAPIを呼び出せます。
this.http([
this.sampleFormControllerService.get(this.id).pipe(
tap((sampleForm) => {
this.sampleForm = sampleForm;
})
),
]);
たったの5行で、WebAPIを呼び出せます!
通信処理を書いたり、DTOを作ったり、、の作業から解放されます!
「DTOの項目名を間違えていた」とか、よくあるミスも無くなります!
OpenAPI Generatorは、さまざまな言語に対応しています。
jQuery、C#、Rust、、夢が膨らみますね!
共通処理の工夫
5行でWebAPIを呼び出せるようになりましたが、、それだけでは終わりません!
- 通信中はオーバーレイを表示して、二重送信を防止する。
- 入力エラーがあれば、メッセージを表示して、該当箇所までスクロールする。
- 予期せぬエラーがあれば、メッセージを表示して、ログを出力する。
といったことは、共通処理にします。
protected http<T>(task: Observable<any>[]): void {
// 表示中のメッセージとエラーをクリアする。
this.messageService.clear();
this.clearValidationError();
// オーバーレイを表示する。
this.progressSpinnerOverlayService.show();
forkJoin(task)
// 最後にオーバレイを非表示にする。
.pipe(finalize(() => this.progressSpinnerOverlayService.hide()))
.subscribe({
next: (response) => console.log(response),
// エラーなら、handleErrorを呼び出す。
error: (error) => this.handleError(error),
});
}
private handleError(response: any): void {
if (response.status === 400 && this.isValidationError(response.error)) {
// 入力エラーなら、メッセージを表示して、該当箇所を赤くして、該当箇所までスクロールする。
this.toastService.addError('入力エラーがあります。');
this.showValidationError(response.error);
} else {
// 予期せぬエラーなら、メッセージを表示して、ログを出力する。
this.messageService.addError(
'通信エラー',
'予期せぬエラーが発生しました。管理者に問い合わせてください。'
);
console.error(response);
}
}
こうすることで、簡単に登録処理が実現できるようになります!
共通処理をつくった甲斐があったはず!
onSubmit(): void {
// WebAPIを呼び出す。
this.http([
this.sampleFormControllerService
.put(this.id, this.sampleForm)
.pipe(
// 成功したときは、メッセージを表示する。
tap(() => this.toastService.addSuccess('登録しました。'))
),
]);
// 失敗したときは、ほっといたらイイカンジになる。
}
プログラムが増えると、バグも増えるし、読むのも大変だし、テストするのも大変だから、減らしたい!
コンポーネント指向の設計
格好つけてますが、すこし工夫しているだけです。
ふつうに入力欄をつくると、つぎのような実装になります。
<!-- デザインを整えるためのdiv -->
<div class="field" #field>
<!-- label -->
<label htmlFor="text">文字列</label>
<!-- input -->
<input
id="text"
[(ngModel)]="sampleForm.fieldText"
pInputText
type="text"
[maxlength]="50"
#ngModel="ngModel"
/>
<!-- エラーメッセージを表示するためのsmall -->
<small
*ngIf="ngModel.invalid"
class="p-error"
>
{{ invalidMessage }}
</small>
</div>
このままだと、つぎのような問題があります。
- 記述量が多い
- 変更に弱い(デザインを変更することになったらどうする!)
- わかりにくい(divとかngModelとかpInputTextってなんだ!)
- まちがえやすい(「p-error」が「p-errOr」になってたらどうする!)
なんとかせねば!
これらを解決するために、つぎのようなコンポーネントをつくります。
このコンポーネントをつかうと、6行で入力欄ができます。
<and-field-text
name="text"
label="文字列"
[(value)]="sampleForm.fieldText"
[maxlength]="50"
></and-field-text>
画面全体をみても、いい感じです!
いいかんじになった!
フォーマッターの導入
これまではIDEに内蔵されているフォーマッターをつかっていました。(Eclipseとか、IntelliJ IDEAとか、Visual Studio Codeとか)
しかし、つぎのような問題がありました。
- フォーマッターの実行を忘れる人がいる。(人間なので仕方がない!)
- 好きなIDEをつかえない。(仕事道具は選ばせて!)
- IDEに依存してしまう。(OSのバージョンアップで動かなくなったらどうする!)
- GitHookやCIと連携できない。
- フォーマッターの実行を忘れていたら、コミットしたときに通知したり、自動でフォーマットしてあげたい!(GitHook)
- フォーマッターの実行を忘れていたら、プッシュしたときに通知したい!(CI)
これまた、なんとかせねば!
これらを解決するために、フォーマッターを導入しました。
バックエンドにはgoogle-java-formatを導入しました。
フロントエンドにはPrettierを導入しました。
これまた、いいかんじになった!
ビルドツールでの管理
ビルドツールで管理することで、ワンコマンドで、つぎの操作ができるようになってます。
- ビルド
- デプロイ
- フォーマッターの適用
- プログラムの自動生成
環境構築に時間がかかったり、
設定ファイルの〇〇を書き換えないと、本番環境に繋がるトラップがあったり、
ビルドするまえに、〇〇バッチを動かさないとダメというトラップがあったり、
というのは、なくしていきたいなとおもっています!
なにかを覚えるのって大変ですよね。
Wikiの手順どおりに〇〇してください!じゃなくて、説明がなくても分かるようにできたらなぁとおもいます。