Closed20

Springのチュートリアルをやる

nissy-devnissy-dev

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,

ドメインを逆順にしたものをセットするのが一般的

https://maven.apache.org/guides/mini/guide-naming-conventions.html

ArtifactId

artifactId is the name of the jar without version.

rootProject.name

リポジトリルートの名前を設定する。monorepoとかの場合に使うみたい...? (Qiitaの記事を参考)

https://qiita.com/BooookStore/items/695b199a5d13f633a2dc#マルチプロジェクトの作成

プロジェクトに関する各種コマンド

// gradleで実行できるタスクを表示
$ ./gradlew tasks

// 起動
$ ./gradlew bootRun

// build
$ ./gradlew build

JAR、WAR、EARの違い

JAR: Javaのクラスファイルをランタイムで動かすデプロイ単位

WAR:「サーブレットコンテナ」で動かすデプロイ単位

サーブレット: Javaで書かれたWebサーバー (JettyやTomcatなど)

EAR: JARとWARを同時に動かすデプロイ単位

https://rainbow-engine.com/ear-jar-war-difference/#:~:text=WARファイルはWebアプリ,役割が異なっています。

コンテナ単位で生成物が変わるのには、とても違和感を感じる....

nissy-devnissy-dev

ライブラリのInstallと読み込み

Install

build.gradleのdependenciesに必要なパッケージを記述する。implementaion とかの各キーワードの意味については、以下のドキュメントを参考。

https://developer.android.com/studio/build/dependencies?hl=ja#dependency_configurations

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'
}

分かりづらいのは、apiimplementation の違いだけど、以下の記事がめっちゃわかりやすい。要は、apiだと読み込んだライブラリが依存しているライブラリまで直接利用できるみたいなイメージ。(implementationだとできない)

https://qiita.com/tkhs0604/items/7afe40599af2354eb2ad

読み込み

nissy-devnissy-dev

JPA

JPAは「Java Persistence (JSR 338)」の略称であり、Java EE標準のO/R MappingおよびDAOの技術仕様です(元々の名称は「Java Persistence API」であり、その略称「JPA」が現在でも一般的に使用されているため、このドキュメントでも「JPA」という名称を使用します)。

slf4j

Javaのロガーライブラリ。内部的には、Logback、Log4Jなどを使って実装している。

https://qiita.com/NagaokaKenichi/items/9febd2e559331152fcf8

Bean

@Beanと書いたメソッドでインスタンス化されたクラスがシングルトンクラスとしてDIコンテナに登録される。任意のクラスで@Autowiredで注入してアクセスできる。

https://dev.classmethod.jp/articles/springboot-what-is-bean/

Spring BootではDIコンテナに全てのBeanが登録された後、CommandLineRunnerインターフェイスを実装したBeanが実行される。

https://qiita.com/fanfanta/items/7a3a343b2d5b0c2e7337

nissy-devnissy-dev

最新のバージョン 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 が読み込めなくてハマっていた。

https://spring.io/blog/2022/01/20/spring-boot-3-0-0-m1-is-now-available

nissy-devnissy-dev

Javaは以下の書き方ができる。アノテーション 型定義 変数名の並び。

  Employee newEmployee(@RequestBody Employee newEmployee) {
    return repository.save(newEmployee);
  }

アノテーションの実装方法を理解したほうが良さそう

https://qiita.com/yasushi-jp/items/fca645778d44fd228864

引数は複数渡せるけど、アノテーションの型定義は1つしか渡せなさそう。

nissy-devnissy-dev

RESTの話になってきた

HTTPベースのインターフェイスを持ったAPIがRESTなのではないとのこと。ハイパーメディアのように、メディアがリンクを介して繋がっている状態にするべき。Webで支える技術で読んだ話に近いことを、今回のAPIについても spring-boot-starter-hateoasを利用して実装している。

https://addsict.hatenablog.com/entry/2014/12/29/000036

nissy-devnissy-dev

Restのチュートリアルは終わり

まとめ

  • 古いフィールドを削除するな
  • 状態の変化についても、ぺイロードでではなく、リンクを返すべき

サーバーがある状態のペイロードを返して、クライアントでもそのペイロードを見た操作を実装するとする。もしサーバーの状態を追加したりすると、クライアント側での修正も結構大きくなる。一方で、サーバーは状態に応じたリンクだけを返し、クライアントは状態に応じたリンクにアクセスするだけにすると、ロジックはすべてサーバーに隠蔽されるのでクライアントでの修正は最低限になる。

確かに、ロジックをどっちかに寄せればいいこともあるけど、良い UX を実現するためには Client と Server の両方での処理が必要になり、最近のReact や Remix のトレンドにはあっていない気がする。

nissy-devnissy-dev

Spring のアノテーションの意味

@Component とかは、Spring の DI コンテナにクラスのライフサイクル (new して... みたいなところ) を任せる機能。@Autowiredは、Spring のDI コンテナに登録されているクラスをDIする機能。

https://zenn.dev/tm35/articles/101df54b9e32a7

nissy-devnissy-dev

途中からビルドエラーが出て、kotlinのチュートリアルはうまくできなかった
雰囲気だけ掴みたかったので、取り敢えず終わりにする。ちなみに、VSCodeとの相性がとても悪く (go to definitionができないなど)、もしビルドがうまくいったとしても書く気はあまりおきない... kotlin のほうが、JSに似ていたので書きやすかったし、Javaより色々安全にしてくれている言語だとは感じる

PS:ビルド周りの失敗は、kotlin extension とかがちゃんと読み込めていない感じがある... 依存周りを最新でやったからかな... Javaではうまくいったのに

初期値入れたらなおった、なんもわからん....
https://qiita.com/wildmouse/items/6aaac2393fdaa930c1b2

あとは、restTemplate.getForEntity の第2引数が必要だったので追加で入れたり、findByIdOrNull が使えなかったので findById(article.id!!).orElse(null) に修正したりしたら、ビルドとテストも通った

https://github.com/spring-projects/spring-data-commons/blob/ca5676d904f711cb06ee5c140e1acb9349893d1f/src/main/kotlin/org/springframework/data/repository/CrudRepositoryExtensions.kt#L26

https://qiita.com/akkino_D-En/items/520085f50990c3edaec1

nissy-devnissy-dev

全体の感想

フレームワークを組みわせると色々実装できることはわかったが、使い方の詳しいところや何を裏でやっているのかは全然わからなかった... ちょっと調べようとしたけど、トップダウン的に調べる事になりわからないことだらけ出てきて辛かった... (Javaは検索ノイズがすごい....) あとは、デコレータや継承を多用するフレームワークが初めてだったのもあって、違和感がすごかった。基本的にデフォルトの挙動に乗っかって、変更したいときだけ上書きするという流れなので、デフォルトの挙動をちゃんと知りたいという気持ちになった。

Spring自体のアーキテクチャやコアのAPIの内容については、以下から学べられそう。まずこれを知らないと、正直コードが何やっているのかわからないし、どこからがSpringの守備範囲でどこからがプラグインの守備範囲なのかわからない。

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core

Springを理解した先には、データ周りの扱いについては JPA の理解が必須となる。JPA自体は、単なる ORM マッパーだが、ここらへんのドキュメントが不足している感じがある。

このスクラップは2022/01/30にクローズされました