Springのチュートリアルをやる
GroupId
groupId uniquely identifies your project across all projects. A group ID should follow Java's package name rules. This means it starts with a reversed domain name you control. For example,
ドメインを逆順にしたものをセットするのが一般的
ArtifactId
artifactId is the name of the jar without version.
rootProject.name
リポジトリルートの名前を設定する。monorepoとかの場合に使うみたい...? (Qiitaの記事を参考)
プロジェクトに関する各種コマンド
// gradleで実行できるタスクを表示
$ ./gradlew tasks
// 起動
$ ./gradlew bootRun
// build
$ ./gradlew build
JAR、WAR、EARの違い
JAR: Javaのクラスファイルをランタイムで動かすデプロイ単位
WAR:「サーブレットコンテナ」で動かすデプロイ単位
サーブレット: Javaで書かれたWebサーバー (JettyやTomcatなど)
EAR: JARとWARを同時に動かすデプロイ単位
コンテナ単位で生成物が変わるのには、とても違和感を感じる....
ライブラリのInstallと読み込み
Install
build.gradleのdependenciesに必要なパッケージを記述する。implementaion
とかの各キーワードの意味については、以下のドキュメントを参考。
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
分かりづらいのは、api
と implementation
の違いだけど、以下の記事がめっちゃわかりやすい。要は、api
だと読み込んだライブラリが依存しているライブラリまで直接利用できるみたいなイメージ。(implementation
だとできない)
読み込み
JPA
JPAは「Java Persistence (JSR 338)」の略称であり、Java EE標準のO/R MappingおよびDAOの技術仕様です(元々の名称は「Java Persistence API」であり、その略称「JPA」が現在でも一般的に使用されているため、このドキュメントでも「JPA」という名称を使用します)。
slf4j
Javaのロガーライブラリ。内部的には、Logback、Log4Jなどを使って実装している。
Bean
@Beanと書いたメソッドでインスタンス化されたクラスがシングルトンクラスとしてDIコンテナに登録される。任意のクラスで@Autowiredで注入してアクセスできる。
Spring BootではDIコンテナに全てのBeanが登録された後、CommandLineRunnerインターフェイスを実装したBeanが実行される。
最新のバージョン 3.0.0.-M1 使ったらハマった...
If you are trying an existing application with Spring Boot 3.0 you’ll need to be aware that we’ve migrated all Java EE APIs to their equivalent Jakarta EE variant. For most users, this means you’ll need to replace any javax imports with jakarta. For example, javax.servlet.Filter would be replaced with jakarta.servlet.Filter.
詳しいことはあまり理解できていないけど、javax を jakarta に変える必要があるらしい。javax.persistance が読み込めなくてハマっていた。
Javaは以下の書き方ができる。アノテーション 型定義 変数名の並び。
Employee newEmployee(@RequestBody Employee newEmployee) {
return repository.save(newEmployee);
}
アノテーションの実装方法を理解したほうが良さそう
引数は複数渡せるけど、アノテーションの型定義は1つしか渡せなさそう。
RESTの話になってきた
HTTPベースのインターフェイスを持ったAPIがRESTなのではないとのこと。ハイパーメディアのように、メディアがリンクを介して繋がっている状態にするべき。Webで支える技術で読んだ話に近いことを、今回のAPIについても spring-boot-starter-hateoas
を利用して実装している。
Locationヘッダ
リダイレクト先のURLを示す。300系と201 (created) の時で有効
GET -> 成功:200, 304(条件付きGETの場合)
POST -> 成功:201,
PUT -> 成功:201 (新規作成の場合), 204 (No Content, 更新の場合)
Delete -> 成功:204 (No Content)
Restのチュートリアルは終わり
まとめ
- 古いフィールドを削除するな
- 状態の変化についても、ぺイロードでではなく、リンクを返すべき
サーバーがある状態のペイロードを返して、クライアントでもそのペイロードを見た操作を実装するとする。もしサーバーの状態を追加したりすると、クライアント側での修正も結構大きくなる。一方で、サーバーは状態に応じたリンクだけを返し、クライアントは状態に応じたリンクにアクセスするだけにすると、ロジックはすべてサーバーに隠蔽されるのでクライアントでの修正は最低限になる。
確かに、ロジックをどっちかに寄せればいいこともあるけど、良い UX を実現するためには Client と Server の両方での処理が必要になり、最近のReact や Remix のトレンドにはあっていない気がする。
次はこれ、Kotlinでやってみる
VSCode の Kotlin 拡張のGo to definition が壊れて使い物にならないので、Javaでそのまま書く
結構UIのターンが多いのでやめた (hooks以前のReactの世界だし...)
java の ==
は参照比較なのか
Kotlin気なるから以下をやろう
Kotlinはnull安全な言語、null 安全でないjavaはStringにnull突っ込んでもコンパイルは通るのか...
Spring のアノテーションの意味
@Component とかは、Spring の DI コンテナにクラスのライフサイクル (new して... みたいなところ) を任せる機能。@Autowiredは、Spring のDI コンテナに登録されているクラスをDIする機能。
kotlinのクラスはデフォルトでfinal。デフォルトで継承できない。
open修飾子をつけることでfinalが外れ、継承できるようになる。
途中からビルドエラーが出て、kotlinのチュートリアルはうまくできなかった
雰囲気だけ掴みたかったので、取り敢えず終わりにする。ちなみに、VSCodeとの相性がとても悪く (go to definitionができないなど)、もしビルドがうまくいったとしても書く気はあまりおきない... kotlin のほうが、JSに似ていたので書きやすかったし、Javaより色々安全にしてくれている言語だとは感じる
PS:ビルド周りの失敗は、kotlin extension とかがちゃんと読み込めていない感じがある... 依存周りを最新でやったからかな... Javaではうまくいったのに
初期値入れたらなおった、なんもわからん....
あとは、restTemplate.getForEntity
の第2引数が必要だったので追加で入れたり、findByIdOrNull
が使えなかったので findById(article.id!!).orElse(null)
に修正したりしたら、ビルドとテストも通った
最後はこれをやる、Javaでやろう
全体の感想
フレームワークを組みわせると色々実装できることはわかったが、使い方の詳しいところや何を裏でやっているのかは全然わからなかった... ちょっと調べようとしたけど、トップダウン的に調べる事になりわからないことだらけ出てきて辛かった... (Javaは検索ノイズがすごい....) あとは、デコレータや継承を多用するフレームワークが初めてだったのもあって、違和感がすごかった。基本的にデフォルトの挙動に乗っかって、変更したいときだけ上書きするという流れなので、デフォルトの挙動をちゃんと知りたいという気持ちになった。
Spring自体のアーキテクチャやコアのAPIの内容については、以下から学べられそう。まずこれを知らないと、正直コードが何やっているのかわからないし、どこからがSpringの守備範囲でどこからがプラグインの守備範囲なのかわからない。
Springを理解した先には、データ周りの扱いについては JPA の理解が必須となる。JPA自体は、単なる ORM マッパーだが、ここらへんのドキュメントが不足している感じがある。
ちなみに、 Lombokというライブラリは有名だが、Getter/Setter をいい感じにつけてくれるデコレータとかを提供する。