Springbootで業務用アプリケーションを作ってみよう！

## はじめに
以前、自分の勉強のために簡単なCRUD処理をするSpringbootアプリケーション(確か2.xx系だったと思う)
を作っていたのですが、情報が古すぎて老朽化していたので
Springboot 3.xx系でリニューアルしようと考えました。

Springbootでのアプリケーションの作り方は、今となっては探せば山の様に出てくると思います。
私が今回作ったアプリケーションのコンセプトは以下です。

- 簡単なCRUD処理が行えること
- 凝ったアーキテクチャを使わず、シンプルな実装であること
- 最近のアプリケーション開発でよくある
    - ファイルアップロードはs3に保存する
    - ダミーデータはfakerで作成できる
    - migration管理できる(今回はflywayを使いました)
あたりは盛り込んでいます。
- dockerを使った開発であること
    - 中身を見ればわかるんですが、実はSpringboot自体はコンテナの外なんです。ご承知おきくださいm(_ _)m

私が考えるに、恐らく業務用アプリケーション開発で使えるテクニックは
盛り込んでいるんじゃないかなという感じです。

## 何を作ったの？
書籍のレビュー情報を投稿できるサイトを作りました。
書籍名や投稿者名を入力し、コメントや評価を入れて登録できます。
同じ書籍のレビューが無いか一覧画面で検索することもできます。

## 使い方
以下のGitHub URLからclone、mainブランチをチェックアウトします。
https://github.com/engineer-yone3/spring-web-sample

予め、dockerとJDK17が動く環境をセットアップした状態で
```
docker compose up -d
```
コマンドを実行すると、MySQLやらminioやらをセットアップします。

VSCodeやInteliJ IDEA等でSpringWebApplicationを動かす起動構成を作成し、そのまま起動します。
<details><summary>起動イメージ(こんな感じのものが出たらOK)</summary>


```
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.2)

2024-09-29T18:30:00.033+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] c.e.y.s.SpringWebSampleApplication       : Starting SpringWebSampleApplication using Java 17 with PID 10348 (/develop/spring-web-sample/out/production/classes started by root in /develop/spring-web-sample)
2024-09-29T18:30:00.034+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] c.e.y.s.SpringWebSampleApplication       : No active profile set, falling back to 1 default profile: "default"
2024-09-29T18:30:00.065+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2024-09-29T18:30:00.066+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2024-09-29T18:30:00.082+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] .s.b.d.c.l.DockerComposeLifecycleManager : Using Docker Compose file '/develop/spring-web-sample/docker-compose.yml'
2024-09-29T18:30:00.573+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] .s.b.d.c.l.DockerComposeLifecycleManager : There are already Docker Compose services running, skipping startup
2024-09-29T18:30:01.667+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
2024-09-29T18:30:01.682+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 8 ms. Found 0 JDBC repository interfaces.
2024-09-29T18:30:03.064+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2024-09-29T18:30:03.071+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-09-29T18:30:03.072+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.26]
2024-09-29T18:30:03.102+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-09-29T18:30:03.103+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2524 ms
2024-09-29T18:30:03.604+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] org.flywaydb.core.FlywayExecutor         : Database: jdbc:mysql://127.0.0.1:3306/spring_web_sample_db (MySQL 8.0)
2024-09-29T18:30:03.701+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.051s)
2024-09-29T18:30:03.722+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] o.f.core.internal.command.DbMigrate      : Current version of schema `spring_web_sample_db`: 1
2024-09-29T18:30:03.727+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] o.f.core.internal.command.DbMigrate      : Schema `spring_web_sample_db` is up to date. No migration necessary.
2024-09-29T18:30:05.048+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2024-09-29T18:30:05.074+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@5a68a2ce
2024-09-29T18:30:05.075+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2024-09-29T18:30:05.189+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2024-09-29T18:30:05.453+09:00  WARN 10348 --- [spring-web-sample] [  restartedMain] org.jline                                : Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)
2024-09-29T18:30:05.694+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2024-09-29T18:30:05.704+09:00  INFO 10348 --- [spring-web-sample] [  restartedMain] c.e.y.s.SpringWebSampleApplication       : Started SpringWebSampleApplication in 5.953 seconds (process running for 6.534)
```

</details>

初回の場合はflywayによるmigrationが行われ、DBテーブルが作成されます。
ローカル環境で動くことを前提としているので、どこかのサーバにデプロイしても動かないと思います。
AWS s3へのファイル保存はdockerのminioイメージで実現させています。

## 解説ポイント(仕様とかも)

### 一覧画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956382/f4c28cac-67a4-3612-0d18-1fcd17f5478c.png)

- getパラメータでpage(番号)とpageSize(1ページあたりの表示サイズ)を指定して検索できます。<br>書籍名は部分一致検索です。
- ページング処理はpagehelper-spring-boot-starterパッケージを追加して実装しています。
- 削除処理のみ、APIによる非同期処理にしています。画面を開いている端末のIPアドレスと、レビュー情報のIPアドレスが同一の場合のみ、削除できるような仕様にしています。

### 新規登録・編集画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956382/6b354c53-2c86-d6f2-1ca9-0d9d69a37611.png)

- 投稿者名、書籍名、書籍の画像(URLもしくは画像ファイル)、評価(S～E)、コメントを登録できます。
- 基本的に全て必須入力、画像のみURLかファイルかどちらかを必須入力にする相関チェックを行っています。
- 入力バリデーションはspring-boot-starter-validationパッケージを導入しています。
- 登録も更新も同じThymeleaf Templateを使って実装しています。

### その他（ダミーデータ作成）
DataFakerというライブラリを使って、LaravelでいうところのSeederプログラムもどきを作ってみました。
デフォルトでは100件作成しますが、コマンド実行時引数で件数をコントロールできます。

## 実装してみて（所感など）
今回、dockerを使ったJavaの開発というものをやってみました。
だいぶ昔に[こんな記事](https://qiita.com/yone3/items/0dca5dfe45b586846b20)を書いたのですが
やはりeclipseを使う時代はそろそろ終わりかな、と個人的に考えたため。
（今もeclipseを使っている方をdisりたいわけではありません）

ただ、実装してみて気になったのは
- セットアップが面倒(全部dockerにしまえなかった)
- ORMは色々模索した結果、前回同様MyBatisに・・・(JPA使いたかった)
- Thymeleaf単独だとフロントエンドjsはjquery一択になりそう

というのがありました。勿論、私の技術不足も大きいのですが
Laravelほど簡単に導入できなかったな、という印象でした。

ただ、事業会社で業務用アプリと言えばまだまだJavaで開発している現場は
多いと思われますのでSpringboot、覚えて損は無いと思います！

拙い記事ですが、ご覧頂ければ幸いです。