From eb86960e3b40d6547bd3b926bba46c68ae9d212f Mon Sep 17 00:00:00 2001 From: tamago0224 Date: Thu, 8 Aug 2024 12:53:00 +0900 Subject: [PATCH] =?UTF-8?q?Java=E3=82=A6=E3=82=A7=E3=83=96=E3=82=A2?= =?UTF-8?q?=E3=83=97=E3=83=AA=E3=82=B1=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3?= =?UTF-8?q?=202024=E5=AF=BE=E5=BF=9C=20(#172)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ファイル編集をVSCode上で行うためにDockerfileを修正 * compose.ymlを追加 * ファイルコピーは必要なのでもとに戻す * docker-compose.ymlに修正 * markdownlint * 環境構築方法をdocker composeを使って行うものに修正 * 利用するdocker-compose.ymlをコピペ用に追記 * 私はそこまで過激派ではないので記述を削除 * ファイル編集方法をvscodeにしたので表記を変更 * コードブロックのインデントを調整 * lsの対象ディレクトリが間違っていたので修正 * コンテナへの入り方の箇所にコメントを追加 * チェックポイントをvisual-bootcampでわかりやすいように番号を追加 * エディタについての説明を追加 --- src/server-app/java/README.md | 341 ++++++++++-------- src/server-app/java/server-app/Dockerfile | 9 +- .../java/server-app/docker-compose.yml | 7 + 3 files changed, 198 insertions(+), 159 deletions(-) create mode 100644 src/server-app/java/server-app/docker-compose.yml diff --git a/src/server-app/java/README.md b/src/server-app/java/README.md index 0d3ab3a5..3497d1da 100644 --- a/src/server-app/java/README.md +++ b/src/server-app/java/README.md @@ -12,17 +12,20 @@ prior_knowledge: Java ## 始めに -- Javaの基本 -- Spring Bootの基本 -- Spring Bootハンズオン - -本講義では上記について紹介し、Javaというプログラミング言語とそのWebフレームワークであるSpring Bootといった技術的な選択肢を増やすことを目的としています。 +- Java の基本 +- Spring Boot の基本 +- Spring Boot ハンズオン +本講義では上記について紹介し、Java というプログラミング言語とその Web フレームワークである Spring Boot といった技術的な選択肢を増やすことを目的としています。 ### 本講義の前提 -本講義ではプログラム言語共通の制御構文や概念、たとえばif文や型など、の解説は行いません。そのため、受講者は何らかのプログラミング言語で簡単な制御構文が書けることを前提とさせてください。 + +本講義ではプログラム言語共通の制御構文や概念、たとえば if 文や型など、の解説は行いません。そのため、受講者は何らかのプログラミング言語で簡単な制御構文が書けることを前提とさせてください。 + +また、ファイルの編集については VSCode を使って編集することを前提として進めていきます。もちろん、vim などのお好きなエディタを使って頂いても問題ありませんが、その場合は適宜資料を読み替えて対応をお願いします。 ### この資料のお約束 + :computer: は自分で操作する箇所を示しています。 また`$`はホストマシンのプロンプトを意味し、`❯`はコンテナ内部でのプロンプトを意味します。 たとえば下記の通りです。 @@ -35,59 +38,91 @@ $ git clone git@github.com:iij/bootcamp.git ❯ curl localhost:8080 ``` - ### 下準備 -講義を受講する前にコンテナイメージのpullと起動をしておくことをお勧めしています。 -また、Dockerの実行環境があることを前提として本講義を進めます。 - -#### 手順 - -1. ハンズオン用のDockerイメージをpullしてくる - -```bash -# やや重たいので注意してください -$ docker pull tamago0224/bootcamp-springboot:2023 -``` -2. コンテナを起動する +講義を受講する前にコンテナイメージの pull と起動をしておくことをお勧めしています。 +また、Docker の実行環境があることを前提として本講義を進めます。 -```bash -# プロキシ環境下にいる人はプロキシの設定をする -$ PROXY_HOST=YOUR.PROXY.HOST -$ PROXY_PORT=YOUR_PROXY_PORT -$ JAVA_OPT="-Dhttp.proxyHost=${PROXY_HOST} -Dhttp.proxyPort=${PROXY_PORT} -Dhttps.proxyHost=${PROXY_HOST} -Dhttps.proxyPort=${PROXY_PORT}" -# プロキシ設定ここまで -# コンテナを起動する -$ docker run --name bootcamp-springboot -it -p 8080:8080 -e JAVA_OPT="${JAVA_OPT}" tamago0224/bootcamp-springboot:2023 -``` - -3. アプリケーションの起動チェック - -```bash -# Spring Bootを起動する -❯ ./gradlew bootrun -# ... -# いろんなログが流れる -``` +#### 手順 -4. 動作チェック +1. ハンズオン用の Docker イメージを pull してくる + + ```bash + # やや重たいので注意してください + $ docker pull tamago0224/bootcamp-springboot:2024 + ``` + +2. ハンズオン用の作業ディレクトを作成する + + ```bash + # 適当な場所に作業用ディレクトリを作成し、その中に work ディレクトリを作成してください。 + $ mkdir bootcamp-java-2024 # このディレクトリ名は何でも良い + $ cd bootcamp-java-2024 + $ mkdir work + ``` + +3. ハンズオン用の docker-compose.yml を用意する + + ```bash + $ curl -o docker-compose.yml https://raw.githubusercontent.com/iij/bootcamp/master/src/server-app/java/server-app/docker-compose.yml + ``` + + ```yaml + services: + java: + image: tamago0224/bootcamp-springboot:2024 + volumes: + - ./work:/work + working_dir: /work + tty: true + ``` + +4. コンテナを起動する + + ```bash + # コンテナを起動する + $ docker compose up -d + # コンテナに入る + $ docker compose exec java /bin/bash + > pwd + /work + ``` + +5. 必要なプロジェクトファイルの用意。別画面のターミナルで以下のコマンドを実行 + + ```bash + $ cd bootcamp-java-2024 + $ docker exec cp java:/app/. ./work + $ ls ./work # 以下のファイル群が確認できる + build build.gradle gradle gradlew settings.gradle src + ``` + +6. アプリケーションの起動チェック + + ```bash + # Spring Bootを起動する + ❯ ./gradlew bootrun + # ... + # いろんなログが流れる + ``` + +7. 動作チェック ホストマシンの適当なブラウザから[localhost:8080](http://localhost:8080)にアクセスし、下記のようなエラーページが表示されることを確認してください。 ![初回起動 - WhitelabelErrorPage](./images/white-label-error.png) +## Java の基本 -## Javaの基本 - -JavaはOpenJDKコミュニティによって開発され、各ベンダからリリースされているプログラミング言語です。 -古くから利用されているプログラミング言語/プラットフォームである一方、2022年現在でもSIや大規模開発の現場などでよく利用されています。 +Java は OpenJDK コミュニティによって開発され、各ベンダからリリースされているプログラミング言語です。 +古くから利用されているプログラミング言語/プラットフォームである一方、2022 年現在でも SI や大規模開発の現場などでよく利用されています。 ### 言語としての特徴 -JavaはC言語やRustと同じ静的型付き言語です。そのため文法や記法はC言語を踏襲した書き方となっています。\ -Javaの言語のパラダイムとしては、クラスの継承の概念やインタフェースなどの言語仕様を持つためオブジェクト指向プログラミングであります。その一方、Javaのバージョン8以降は関数型インタフェースやパターンマッチなど、関数型プログラミングを楽しめるような仕様も導入されています。 +Java は C 言語や Rust と同じ静的型付き言語です。そのため文法や記法は C 言語を踏襲した書き方となっています。\ +Java の言語のパラダイムとしては、クラスの継承の概念やインタフェースなどの言語仕様を持つためオブジェクト指向プログラミングであります。その一方、Java のバージョン 8 以降は関数型インタフェースやパターンマッチなど、関数型プログラミングを楽しめるような仕様も導入されています。 -:::details Javaのサンプルコード +:::details Java のサンプルコード ```java package com.github.iij.bootcamp.serverapp; // パッケージ名(世界でユニークであると良い) @@ -144,7 +179,7 @@ public class SampleClass extends Object { ### プロジェクト構成 -Javaのプロジェクトのディレクトリ構成は、ほかのプログラミング言語と異なり言語として定められています。名前空間として定義できる"パッケージ"がそのままディレクトリに反映されるようにディレクトリを構成する必要があります。 +Java のプロジェクトのディレクトリ構成は、ほかのプログラミング言語と異なり言語として定められています。名前空間として定義できる"パッケージ"がそのままディレクトリに反映されるようにディレクトリを構成する必要があります。 参考: https://docs.oracle.com/javase/tutorial/java/package/managingfiles.html @@ -167,48 +202,44 @@ Javaのプロジェクトのディレクトリ構成は、ほかのプログラ ``` :::tip パッケージ -Javaにおけるパッケージとは、DNS形式で定義できる名前空間のような概念です。`.`で区切ることでパッケージ間の親子関係を定義できます。たとえば`com.example.iij`パッケージと`com.example.iij.bootcamp`パッケージでは前者が親で後者が子といった関係があります。 +Java におけるパッケージとは、DNS 形式で定義できる名前空間のような概念です。`.`で区切ることでパッケージ間の親子関係を定義できます。たとえば`com.example.iij`パッケージと`com.example.iij.bootcamp`パッケージでは前者が親で後者が子といった関係があります。 ::: ### Gradle -Pythonであればpip、Rustであればcargo、Node.jsであればnpmのようにプログラミング言語にはそれぞれ依存関係を解決しビルドを自動化する自動化システムツールが用意されています。 -JavaではMavenとGradleという2つの種類の自動化システムツールがよく利用されています。本講義ではGradleを利用して話を進めていきます。 +Python であれば pip、Rust であれば cargo、Node.js であれば npm のようにプログラミング言語にはそれぞれ依存関係を解決しビルドを自動化する自動化システムツールが用意されています。 -:::warning +Java では Maven と Gradle という 2 つの種類の自動化システムツールがよく利用されています。本講義では Gradle を利用して話を進めていきます。 -Mavenを使わずにGradleを利用する理由は、Gradleの方が優れている/イケているからではなく、単に筆者がXMLが嫌いであるためである。 +## Spring Boot の基本 -::: +Spring Boot は Java の Web フレームワークのひとつです。Spring Boot の規約に従ってアプリケーションロジックを実装することで簡単に Web アプリケーションを構築できます。 +このフレームワークは大規模な主幹システムや Web アプリケーションを実装/構築する際によく利用されており、IIJ がホストしているいくつかのサービスも Spring Boot を利用して実装されています。 -## Spring Bootの基本 -Spring BootはJavaのWebフレームワークのひとつです。Spring Bootの規約に従ってアプリケーションロジックを実装することで簡単にWebアプリケーションを構築できます。 +### 特徴 -このフレームワークは大規模な主幹システムやWebアプリケーションを実装/構築する際によく利用されており、IIJがホストしているいくつかのサービスもSpring Bootを利用して実装されています。 +Spring Boot は複雑な業務要件や非機能要件をクリアするためのさまざまな機能を有しています。依存関係を宣言して注入してくれる DI コンテナや横断的な関心事を解決する AOP のサポート、数多く公開されている starter パッケージなどはその最たる例です。 -### 特徴 -Spring Bootは複雑な業務要件や非機能要件をクリアするためのさまざまな機能を有しています。依存関係を宣言して注入してくれるDIコンテナや横断的な関心事を解決するAOPのサポート、数多く公開されているstarterパッケージなどはその最たる例です。 +残念ながらこの Bootcamp ですべての要素に触れることはできないため、興味のあるほうはドキュメントを読んでみることをお勧めします。 -残念ながらこのBootcampですべての要素に触れることはできないため、興味のあるほうはドキュメントを読んでみることをお勧めします。 +## Spring Boot ハンズオン -## Spring Bootハンズオン -本ハンズオンではブラウザで閲覧できるWeb UIの機能を持たない、HTTP API(Application Programming Interface)だけを持つAPIサーバを構築していきます。 +本ハンズオンではブラウザで閲覧できる Web UI の機能を持たない、HTTP API(Application Programming Interface)だけを持つ API サーバを構築していきます。 それでは始めましょう。 ### 簡単なクラスを作ってみる -まず始めに、Java言語のウォーミングアップとして純粋なJavaのクラスを作ってみましょう。 + +まず始めに、Java 言語のウォーミングアップとして純粋な Java のクラスを作ってみましょう。 :computer: `User`クラスを作成します。 -```bash -# 下記の通りに修正する -❯ vim src/main/java/com/github/iij/bootcamp/serverapp/User.java -``` +下記の通りに修正してみましょう。 ```java +// src/main/java/com/github/iij/bootcamp/serverapp/User.java package com.github.iij.bootcamp.serverapp; public class User { @@ -244,18 +275,12 @@ public class User { ``` これで`User`クラスを作成できました。次にこのクラスを実際にインスタンス化してみます。\ -Spring Bootアプリケーションのmain関数は`com.github.iij.bootcamp.serverapp.ServerAppApplication`にあります。ためしにこのmain関数の中で`User`クラスをインスタンス化してみます。 +Spring Boot アプリケーションの main 関数は`com.github.iij.bootcamp.serverapp.ServerAppApplication`にあります。ためしにこの main 関数の中で`User`クラスをインスタンス化してみます。 -:computer: ServerAppApplication.javaを修正してください。 - -```bash -# 下記の通りに修正する -❯ vim src/main/java/com/github/iij/bootcamp/serverapp/ServerAppApplication.java -# Spring Bootサーバーを再起動する -❯ ./gradlew bootRun -``` +:computer: ServerAppApplication.java を修正してください。 ```java{10-13} +// src/main/java/com/github/iij/bootcamp/serverapp/ServerAppApplication.java package com.github.iij.bootcamp.serverapp; import org.springframework.boot.SpringApplication; @@ -274,31 +299,34 @@ public class ServerAppApplication { } ``` -再起動時にログに"name: アリス,id: alice"と表示されていればOKです。 +編集が完了したら以下のコマンドをコンテナから実行してサーバを起動しましょう。 + +```bash +❯ ./gradlew bootRun +``` + +再起動時にログに"name: アリス,id: alice"と表示されていれば OK です。 + +#### チェックポイント その 1 -#### チェックポイント -- Javaのクラスを作成した +- Java のクラスを作成した - クラスをインスタンス化し、標準出力に文字列を表示した #### 解説 -純粋なJavaのクラスを作成し、インスタンス化とメソッドの呼び出しを行いました。`User`クラスを眺めてもらうとわかるとおり、`getName`や`getId`などJavaにはかなり冗長なコードが多いです。これらのコードはよく「ボイラープレート」と呼ばれ、開発者が嫌うコードです。 -JavaにはLombokなどのボイラープレートを解消するツールなどありますが、本講義はあえて紹介しません。興味がある人は調べてみてください。 +純粋な Java のクラスを作成し、インスタンス化とメソッドの呼び出しを行いました。`User`クラスを眺めてもらうとわかるとおり、`getName`や`getId`など Java にはかなり冗長なコードが多いです。これらのコードはよく「ボイラープレート」と呼ばれ、開発者が嫌うコードです。 -### 簡単なHTTPのインタフェースを作成してみる -それではSpring Bootを使ってみましょう。\ -簡単なHTTPのインタフェースを作成し、実際にSpring Bootがどのように動作しているのかを見てみます。 +Java には Lombok などのボイラープレートを解消するツールなどありますが、本講義はあえて紹介しません。興味がある人は調べてみてください。 -:computer: ServerAppApplication.javaを修正し、サーバを再起動してみてください。 +### 簡単な HTTP のインタフェースを作成してみる -```bash -# 下記の通りに修正する -❯ vim src/main/java/com/github/iij/bootcamp/serverapp/ServerAppApplication.java -# Spring Bootサーバーを再起動する -❯ ./gradlew bootRun -``` +それでは Spring Boot を使ってみましょう。\ +簡単な HTTP のインタフェースを作成し、実際に Spring Boot がどのように動作しているのかを見てみます。 + +:computer: ServerAppApplication.java を修正し、サーバを再起動してみてください。 ```java{5-8,19-27} +// src/main/java/com/github/iij/bootcamp/serverapp/ServerAppApplication.java package com.github.iij.bootcamp.serverapp; import org.springframework.boot.SpringApplication; @@ -330,6 +358,11 @@ public class ServerAppApplication { ``` ```bash +# Spring Bootサーバーを再起動する +❯ ./gradlew bootRun +``` + +``` # 動作確認 $ curl localhost:8080 -X GET hello world @@ -337,47 +370,43 @@ hello world "hello world"が返ってきたら成功です。 -#### チェックポイント -- `@RestController`アノテーションをクラスに付与してHTTPのインタフェースを作成した +#### チェックポイント その 2 + +- `@RestController`アノテーションをクラスに付与して HTTP のインタフェースを作成した #### 解説 -`bootRun`コマンドによりSpring Bootが起動します。すると、Spring Bootの機能により `@RestController`アノテーションが付いている`ServerAppApplication.HelloController`がHTTPのインタフェースとして登録されます。 + +`bootRun`コマンドにより Spring Boot が起動します。すると、Spring Boot の機能により `@RestController`アノテーションが付いている`ServerAppApplication.HelloController`が HTTP のインタフェースとして登録されます。 ![handler](./images/http-handler.png) -その結果、このSpring Bootが動いている8080番ポート宛のHTTPリクエストと`ServerAppApplication.HelloController#helloWorld`が紐づけられることになり、`GET /`へのリクエストのレスポンスとして"hello world"が返ってきました。 +その結果、この Spring Boot が動いている 8080 番ポート宛の HTTP リクエストと`ServerAppApplication.HelloController#helloWorld`が紐づけられることになり、`GET /`へのリクエストのレスポンスとして"hello world"が返ってきました。 -:::details Spring BootとDIコンテナ +:::details Spring Boot と DI コンテナ -Spring Bootは起動時に起動クラスのパッケージ配下のJavaファイルから特殊なアノテーション(`@Contoroller` / `@Component` / etc...)がついたクラスを探し出します。そしてSpring Bootはそのクラスを適当な方法でインスタンス化し、自身の管理下(=DI コンテナ)に置きます。 +Spring Boot は起動時に起動クラスのパッケージ配下の Java ファイルから特殊なアノテーション(`@Contoroller` / `@Component` / etc...)がついたクラスを探し出します。そして Spring Boot はそのクラスを適当な方法でインスタンス化し、自身の管理下(=DI コンテナ)に置きます。 (「適当な方法」を指定することもできます > [Bean Annotation](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html)) -DIコンテナに格納されたインスタンスは、後述する`@Autowired`アノテーションを使って引き出すことができます。 +DI コンテナに格納されたインスタンスは、後述する`@Autowired`アノテーションを使って引き出すことができます。 -特に、`@Controller` `@RestController`アノテーションが付与されたクラスから生成されたインスタンスはHTTPのインタフェースとして働くことになります。 +特に、`@Controller` `@RestController`アノテーションが付与されたクラスから生成されたインスタンスは HTTP のインタフェースとして働くことになります。 今回の例では、 `ServerAppApplication`クラスに`@SpringBootApplication`アノテーションが付与されているので`ServerAppApplication`クラスのパッケージ`com.github.iij.bootcamp.serverapp`配下のクラスから上述の特殊なアノテーションがついているクラスを探索します。 -`HelloController`クラスは`@RestController`アノテーションが付与されているため、Spring Boot起動時に`HelloController`がSpring Bootによってインスタンス化されDIコンテナに登録されました。 -その結果、`GET /`のリクエストをSpring Bootが受け取ると`HelloController#helloWorld` が実行されるようになっていたというわけです。 +`HelloController`クラスは`@RestController`アノテーションが付与されているため、Spring Boot 起動時に`HelloController`が Spring Boot によってインスタンス化され DI コンテナに登録されました。 +その結果、`GET /`のリクエストを Spring Boot が受け取ると`HelloController#helloWorld` が実行されるようになっていたというわけです。 ::: - ### 簡単なリクエストを受け取ってみる -次にクエリパラメータから情報を取得してみましょう。 -:computer: UserController.javaを作成し、サーバを再起動してみてください。 +次にクエリパラメータから情報を取得してみましょう。 -```bash -# 下記の通りに修正する -❯ vim src/main/java/com/github/iij/bootcamp/serverapp/UserController.java -# Spring Bootサーバーを再起動する -❯ ./gradlew bootRun -``` +:computer: UserController.java を作成し、サーバを再起動してみてください。 ```java +// src/main/java/com/github/iij/bootcamp/serverapp/UserController.java package com.github.iij.bootcamp.serverapp; import org.springframework.web.bind.annotation.GetMapping; @@ -400,42 +429,41 @@ public class UserController { } ``` +```bash +# Spring Bootサーバーを再起動する +❯ ./gradlew bootRun +``` + ```bash # 動作確認 $ curl 'localhost:8080/user?id=bob' {"name":"ボブ","id":"bob"} ``` -#### チェックポイント -- `@GetMapping`アノテーションを持つメソッドを作成し、HTTPのハンドラとして登録した -- HTTPのハンドラとして登録されたメソッドの引数に`@RequestParam`アノテーションを付与することでクエリパラメータを実装した +#### チェックポイント その 3 + +- `@GetMapping`アノテーションを持つメソッドを作成し、HTTP のハンドラとして登録した +- HTTP のハンドラとして登録されたメソッドの引数に`@RequestParam`アノテーションを付与することでクエリパラメータを実装した #### 解説 -新しいクラス`UserController`を作成しました。このクラスにも`@RestController`アノテーションが付いているためHTTPのインタフェースとして振る舞います。 -`UserController`クラスの持つメソッド`find`には`@GetMapping`アノテーションがついているため、`GET /user`宛のリクエストのハンドラとして登録されることになります。そのため、Spring Bootアプリケーションの`/user`へGETリクエストを送ることでこの`find`メソッドがコールされます。 +新しいクラス`UserController`を作成しました。このクラスにも`@RestController`アノテーションが付いているため HTTP のインタフェースとして振る舞います。 -さらに`find`メソッドの引数`id`に`@RequestParam`アノテーションが付与されています。これにより、HTTPリクエストのクエリパラメータの値がこの変数に注入されます。つまり`GET /user?id=bob`へのリクエストをSpring Bootアプリケーションへ送ることで`find`メソッドがコールされ引数`id=bob`が引き渡されます。 +`UserController`クラスの持つメソッド`find`には`@GetMapping`アノテーションがついているため、`GET /user`宛のリクエストのハンドラとして登録されることになります。そのため、Spring Boot アプリケーションの`/user`へ GET リクエストを送ることでこの`find`メソッドがコールされます。 +さらに`find`メソッドの引数`id`に`@RequestParam`アノテーションが付与されています。これにより、HTTP リクエストのクエリパラメータの値がこの変数に注入されます。つまり`GET /user?id=bob`へのリクエストを Spring Boot アプリケーションへ送ることで`find`メソッドがコールされ引数`id=bob`が引き渡されます。 ### 責任を分離する -さて、前章まで基本的なHTTPのインタフェースの作り方と使い方について解説してきました。もう少し実装を深めていきましょう。\ -現在`UserController`クラスはHTTPのインタフェースとデータソースの管理の2つの責務を持っています。これは単一責務の原理から外れているためリファクタリングする対象です。 -今回はシンプルに`UserController#find`の処理を抽出して別のクラスに分離、処理そのものを`UserController`クラスの外から与えてあげるようにしましょう。 +さて、前章まで基本的な HTTP のインタフェースの作り方と使い方について解説してきました。もう少し実装を深めていきましょう。\ +現在`UserController`クラスは HTTP のインタフェースとデータソースの管理の 2 つの責務を持っています。これは単一責務の原理から外れているためリファクタリングする対象です。 -:computer: UserService.javaを作成、UserController.javaを修正し、サーバを再起動してください。 +今回はシンプルに`UserController#find`の処理を抽出して別のクラスに分離、処理そのものを`UserController`クラスの外から与えてあげるようにしましょう。 -```bash -# 新しいクラスUserServiceを作成する -❯ vim src/main/java/com/github/iij/bootcamp/serverapp/UserService.java -# UserControllerクラスを修正する -❯ vim src/main/java/com/github/iij/bootcamp/serverapp/UserController.java -# Spring Bootサーバーを再起動する -❯ ./gradlew bootRun -``` +:computer: UserService.java を作成、UserController.java を修正し、サーバを再起動してください。 ```java +// src/main/java/com/github/iij/bootcamp/serverapp/UserService.java package com.github.iij.bootcamp.serverapp; import java.util.ArrayList; @@ -449,7 +477,7 @@ public class UserService { // データソースに該当する部分 private List userPool = new ArrayList(Arrays.asList(new User("ボブ", "bob"))); - + /** * ユーザープールからid値で検索し、その結果を返却します idと一致するユーザーが見つからない場合nullを返却します * TODO 本当にこの実装で問題ないか、考えてみましょう @@ -470,6 +498,7 @@ public class UserService { ``` ```java{6-8,13-21} +// src/main/java/com/github/iij/bootcamp/serverapp/UserController.java package com.github.iij.bootcamp.serverapp; import org.springframework.web.bind.annotation.GetMapping; @@ -494,39 +523,39 @@ public class UserController { } ``` +```bash +# Spring Bootサーバーを再起動する +❯ ./gradlew bootRun +``` + ```bash # 動作確認 $ curl 'localhost:8080/user?id=bob' {"name":"ボブ","id":"bob"} ``` -#### チェックポイント -- `@Component`アノテーションをクラスに付与し、Spring Boot起動時に自動的にインスタンス化した -- `@Autowired`アノテーションをフィールドに付与し、そのフィールドにSpring Bootがインスタンス化したインスタンスの中から適切なインスタンスを注入した +#### チェックポイント その 4 + +- `@Component`アノテーションをクラスに付与し、Spring Boot 起動時に自動的にインスタンス化した +- `@Autowired`アノテーションをフィールドに付与し、そのフィールドに Spring Boot がインスタンス化したインスタンスの中から適切なインスタンスを注入した #### 解説 -新しいクラス`UserService`を作成しました。このクラスには`@Component`アノテーションが付与されているため、Spring Boot起動時にSpring Bootによって自動的にインスタンス化されSpring Bootの管理下に入ります。このようにSpring Bootに管理されるようになったインスタンスはほかのクラスから`@Autowired`を利用することで利用されます。 -今回の例では`UserController`クラスが`userService`フィールドに`@Autowired`アノテーションを付与しているため自動的に作成された`UserService`クラスのインスタンスが`UserController.userService`に代入されることになりました。このように依存関係を分離、外から依存関係を持ち込む構成のことをDI(Dependency Injection)と呼びます。 +新しいクラス`UserService`を作成しました。このクラスには`@Component`アノテーションが付与されているため、Spring Boot 起動時に Spring Boot によって自動的にインスタンス化され Spring Boot の管理下に入ります。このように Spring Boot に管理されるようになったインスタンスはほかのクラスから`@Autowired`を利用することで利用されます。 -注意点として、デフォルトの挙動ではSpring Bootが管理するインスタンスは各クラス"1つ"となっています。つまり`UserController`クラスが引っ張ってきている`userService`とほかのクラスが引っ張ってこれる`UserService`インスタンスは完全に一致しています。このようにひとつのインスタンスを使い回す構成のことを"シングルトン"と呼びます。 +今回の例では`UserController`クラスが`userService`フィールドに`@Autowired`アノテーションを付与しているため自動的に作成された`UserService`クラスのインスタンスが`UserController.userService`に代入されることになりました。このように依存関係を分離、外から依存関係を持ち込む構成のことを DI(Dependency Injection)と呼びます。 +注意点として、デフォルトの挙動では Spring Boot が管理するインスタンスは各クラス"1 つ"となっています。つまり`UserController`クラスが引っ張ってきている`userService`とほかのクラスが引っ張ってこれる`UserService`インスタンスは完全に一致しています。このようにひとつのインスタンスを使い回す構成のことを"シングルトン"と呼びます。 ### 少し複雑なリクエストを受け取ってみる -最後に、POSTリクエストとリクエストボディを指定して`User`インスタンスを登録してみましょう。\ -`User`インスタンスには`id`と`name`の値を指定する必要があるので、これらを与えられるエンドポイントを用意します。 -:computer: UserService.javaとUserController.javaを修正し、サーバを再起動してください。 +最後に、POST リクエストとリクエストボディを指定して`User`インスタンスを登録してみましょう。\ +`User`インスタンスには`id`と`name`の値を指定する必要があるので、これらを与えられるエンドポイントを用意します。 -```bash -# 下記の通りに修正する -❯ vim src/main/java/com/github/iij/bootcamp/serverapp/UserService.java -❯ vim src/main/java/com/github/iij/bootcamp/serverapp/UserController.java -# Spring Bootサーバーを再起動する -❯ ./gradlew bootRun -``` +:computer: UserService.java と UserController.java を修正し、サーバを再起動してください。 ```java{27-35} +// src/main/java/com/github/iij/bootcamp/serverapp/UserService.java package com.github.iij.bootcamp.serverapp; import java.util.ArrayList; @@ -540,7 +569,7 @@ public class UserService { // データソースに該当する部分 private List userPool = new ArrayList(Arrays.asList(new User("ボブ", "bob"))); - + /** * ユーザープールからid値で検索し、その結果を返却します idと一致するユーザーが見つからない場合nullを返却します */ @@ -566,6 +595,7 @@ public class UserService { ``` ```java{7-10,23-52} +// src/main/java/com/github/iij/bootcamp/serverapp/UserController.java package com.github.iij.bootcamp.serverapp; import org.springframework.beans.factory.annotation.Autowired; @@ -622,6 +652,11 @@ public class UserController { } ``` +```bash +# Spring Bootサーバーを再起動する +❯ ./gradlew bootRun +``` + ```bash # 動作確認 $ curl localhost:8080/user -X POST -H 'Content-Type: application/json' -d '{"name": "アリス", "id": "alice"}' @@ -631,22 +666,24 @@ $ curl 'localhost:8080/user?id=alice' {"name": "アリス", "id": "alice"} ``` -#### チェックポイント -- `@PostMapping`アノテーションをメソッドに付与し、POSTリクエストのHTTPハンドラとして登録した -- JavaのPOJOを用いてPOSTリクエストのリクエストボディのスキーマを表現した +#### チェックポイント その 5 + +- `@PostMapping`アノテーションをメソッドに付与し、POST リクエストの HTTP ハンドラとして登録した +- Java の POJO を用いて POST リクエストのリクエストボディのスキーマを表現した ## まとめ -以上でSpring Bootのハンズオンは終了です。 -本講義ではJavaの基本的な知識や書き方、Spring Bootの使い方など、基本的な機能や文法に触れてもらいました。しかしSpring Bootには多様な機能がまだまだ存在しており、データベースとの接続や非同期処理などさまざまなプロダクション環境で活躍できるポテンシャルを持っているフレームワークです。 +以上で Spring Boot のハンズオンは終了です。 + +本講義では Java の基本的な知識や書き方、Spring Boot の使い方など、基本的な機能や文法に触れてもらいました。しかし Spring Boot には多様な機能がまだまだ存在しており、データベースとの接続や非同期処理などさまざまなプロダクション環境で活躍できるポテンシャルを持っているフレームワークです。 本講義が、受講者のみなさまの今後の技術選定の手助けになれれば幸いです。 ### 追加の資料 -- [Spring Bootリファレンスドキュメント](https://spring.pleiades.io/spring-boot/docs/current/reference/html) - - 多くのSpring Boot開発者がお世話になる公式ドキュメントです。アプリケーションの開発からデプロイ方法まで、幅広く情報が提供されています。 +- [Spring Boot リファレンスドキュメント](https://spring.pleiades.io/spring-boot/docs/current/reference/html) + - 多くの Spring Boot 開発者がお世話になる公式ドキュメントです。アプリケーションの開発からデプロイ方法まで、幅広く情報が提供されています。 - [Spring Boot Guides](https://spring.pleiades.io/guides) - - Spring Bootの各種機能を試してみるチュートリアルが公開されています。Pub/SubやMongoDB、Dockerとの連携などSpring Bootの拡張が多種公開されています。興味のある項目に触ってみてください。 + - Spring Boot の各種機能を試してみるチュートリアルが公開されています。Pub/Sub や MongoDB、Docker との連携など Spring Boot の拡張が多種公開されています。興味のある項目に触ってみてください。 diff --git a/src/server-app/java/server-app/Dockerfile b/src/server-app/java/server-app/Dockerfile index e28bdf9e..52d9dd8d 100644 --- a/src/server-app/java/server-app/Dockerfile +++ b/src/server-app/java/server-app/Dockerfile @@ -1,12 +1,7 @@ -FROM amazoncorretto:17.0.8 +FROM amazoncorretto:21 WORKDIR /app -# 開発ツールインストール -RUN yum update \ - && yum install vim emacs -y \ - && yum clean all - -# 固定シェルとプロジェクト設定をコピー +# プロジェクトファイルをコピー COPY gradlew settings.gradle /app/ # gradleバイナリ本体 diff --git a/src/server-app/java/server-app/docker-compose.yml b/src/server-app/java/server-app/docker-compose.yml new file mode 100644 index 00000000..9f442232 --- /dev/null +++ b/src/server-app/java/server-app/docker-compose.yml @@ -0,0 +1,7 @@ +services: + java: + image: tamago0224/bootcamp-springboot:2024 + volumes: + - ./work:/work + working_dir: /work + tty: true