Spring Boot 2 で、なるべく標準的なやり方で、トラディショナルな Spring MVC による Web Application を作成するチュートリアルを数回に分けて。
Web Application 作成の流れを、細か過ぎる説明は省き、ざっくりと一通り見ていきます。
目次
- Spring MVC で Hello World
- Spring Data JPA でデータベースアクセス
- 登録・更新処理と Bean Validataion
- Bootstrap と Thymeleaf でページネーション
- Spring Boot DevTools で Automatic Restart
- Spring Security でログイン認証
- ファイルアップロード
- T.B.D
今回は 「Spring MVC で Hello World」 の回となります。
環境
Java は LTS の 1.8 を使います。
Gradle は現時点の最新 4.7 を使います(けどリリースサイクル早いので多分古くなってる気がします)。
その他は以下のような感じ。
$ gradle -version ------------------------------------------------------------ Gradle 4.7 ------------------------------------------------------------ Build time: 2018-04-18 09:09:12 UTC Revision: b9a962bf70638332300e7f810689cb2febbd4a6c Groovy: 2.4.12 Ant: Apache Ant(TM) version 1.9.9 compiled on February 2 2017 JVM: 1.8.0_131 (Oracle Corporation 25.131-b11) OS: Mac OS X 10.13.3 x86_64
プロジェクトの作成
gradle の init タスクでプロジェクトの雛形を作成していきましょう。
$ mkdir spring-boot-stdweb && cd spring-boot-stdweb $ gradle init --type java-application
プロジェクトの雛形を作成できる Spring Initializr から始めるのが早いですが、今回は少しづつ進めたいので手で作っていくことにします。
build.gradle と BOM
build.gradle を以下のように編集します。
plugins { id 'java' id 'org.springframework.boot' version '2.0.1.RELEASE' } sourceCompatibility = targetCompatibility = 1.8 dependencies { compile 'org.springframework.boot:spring-boot-starter-web:2.0.1.RELEASE' } repositories { jcenter() }
Spring Boot Gradle Plugin と 依存には spring-boot-starter-web を指定します。Spring Boot は 2.0.1 ですね。
Gradle では Maven にあるような BOM の読み込みに対応していません。この代替として、Spring チームが提供する io.spring.dependency-management
プラグインを使うことが多かったです。
しかし Gradle 5 からは BOM インポート機能の追加が予定されており、4.6 以降でも feature preview としてこの機能を使うことができるようになりました。
デフォルトでは無効となっているので settings.gradle
に enableFeaturePreview('IMPROVED_POM_SUPPORT')
とすることで有効化できます(BOM import を参照)。
ちなみに、BOM とは Bill Of Materials の略で、プロダクトの一連の依存性のバージョンを定義した一覧表になります。 これをインポートすることで、利用者は BOM のバージョンを指定さえすれば、個々の依存性のバージョン指定が不要になります。
Spring Boot 1.0.0 の頃は、Spring Boot Gradle プラグインと dependency-management プラグインを build.gradle に双方指定する必要がありました。
これが Spring Boot 1.3.0 では Gradle の Spring Boot プラグインが dependency-management プラグインを自動的に適用するようになったため dependency-management の設定を明記する必要がなくなりました。
そしてそして Spring Boot 2.0 では Spring Boot Gradle プラグイン からdependency-management は除外されるようになりました(こちらを参照)。
このような経緯があり build.gradle の設定方法がバージョンによって色々あるので少しややこしいところです。
閑話休題。今回は、せっかくなので Gradle の新機能で BOM を使って進めることにします。
settings.gradle
で BOMインポートを有効化しましょう(gradle 5 になればこれは不要)。
rootProject.name = 'spring-boot-stdweb' enableFeaturePreview('IMPROVED_POM_SUPPORT')
build.gradle には spring-boot-dependencies
を指定します。
plugins { id 'java' id 'org.springframework.boot' version '2.0.1.RELEASE' } sourceCompatibility = targetCompatibility = 1.8 dependencies { implementation 'org.springframework.boot:spring-boot-dependencies:2.0.1.RELEASE' compile 'org.springframework.boot:spring-boot-starter-web' compile 'org.springframework.boot:spring-boot-starter-thymeleaf' } repositories { jcenter() }
これで個々の依存についてのバージョン指定が不要になります。
SpringBootApplication
Spring Boot のエントリポイントを作成しましょう。
package stdweb; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Main { public static void main(String[] args){ SpringApplication.run(Main.class, args); } }
SpringApplication.run()
という static メソッド内にて SpringApplication
のインスタンスを生成してアプリケーションを実行します。
メインクラスに指定した @SpringBootApplication
により以下の設定がまとめて有効になります。
アノテーション | 説明 |
---|---|
@SpringBootConfiguration |
このクラスをBean定義可能とマーク。@SpringBootConfiguration の中で @Configuration が定義されておりこのクラス自体がコンポーネントとなる。 |
@EnableAutoConfiguration |
Spring Bootの自動設定メカニズムを有効化。 EnableAutoConfigurationImportSelector 経由で クラスパス上の jar にある/META-INF/spring.factories に定義されたものをインポートする。 |
@ComponentScan |
このクラスのパッケージ配下のコンポーネントをスキャンしてDI コンテナにコンポーネントとして自動登録する |
Spring MVC のコントローラ作成
トラディショナルな Spring MVC を普通に使っていきましょう。
stdweb.hello.HelloController.java
を以下のように作成します。
package stdweb.hello; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class HelloController { @GetMapping("/hello") public String hello( @RequestParam(name="name", required=false, defaultValue="World") String name, Model model) { model.addAttribute("name", name); return "hello"; } }
@Controller
はステレオタイプアノテーションで、結局のところは@Component
ですが、レイヤ別で以下が用意されています(org.springframework.stereotype
パッケージ配下)。
アノテーション | 説明 |
---|---|
@Component |
Spring 管理コンポーネントの汎用ステレオタイプ |
@Controller |
プレゼンテーション層(Spring MVC)のためのステレオタイプ |
@Service |
サービス層のためのステレオタイプ |
@Repository |
パーシステンス層のためのステレオタイプ |
コントローラのメソッドに指定した @GetMapping("/hello")
は @RequestMapping(value = "/hello", method = RequestMethod.GET)
と同意で Spring4.3 から追加されたアノテーションです。
他にも @GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
と一揃い用意されています。
メソッド引数の @RequestParam
は ?name=hoge
のようなリクエストパラメータがバインドされます。name
属性(Spring 4.2以前は value
属性)を省略した場合は引数名がパラメータ名になります。
その他以下のようなアノテーションでリクエストからパラメータを受け取ることができます。
アノテーション | 説明 |
---|---|
@RequestParam |
クエリパラメータ、ポストパラメータを受け取る |
@PathVariable |
@GetMapping("/foo/{id}") のようなパスパラメータを受け取る |
@MatrixVariable |
マトリックスパラメータを受け取る |
@CookieValue |
クッキーパラメータへアクセス |
@RequestHeader |
@RequestHeader("User-Agent") のようにリクエストヘッダへアクセス |
@RequestBody |
リクエストボディを文字列としてそのまま受け取る |
@RequestAttribute |
HttpServletRequest で管理しているオブジェクトにアクセス(Spring 4.3〜) |
@SessionAttribute |
HttpSession で管理しているオブジェクトにアクセス(Spring 4.3〜) |
コントローラのメソッドはモデルを受け取ることができ、このモデルを介してビューへ情報の受け渡しを行います。
モデルは以下の種類があります。
オプション | 説明 |
---|---|
Model |
Model はインターフェースでaddAttribute メソッドなどをもつ |
ModelMap |
ModelMap はMAPインターフェースの実装。LinkedHashMapの子クラスになっている |
ModelAndView |
ModelMap とviewオブジェクトのコンテナで、コントローラメソッドの戻り値にすることができる(return new ModelAndView("hello", "name", name); )。 |
キー・バリューで扱うのが気に入らないという意見もありますが、結局ビュー側ではテンプレートエンジンなど文字列をキーとして扱うことになるので気にしない方がよいです。
コントローラのメソッドからは hello
という文字列の Viewの id を返却しています。
View の作成
JSPは過去のものなので、Spring ではテンプレートエンジンの Thymeleaf を標準としていいます。
Thymeleaf の最大の特徴は、そのまま HTML として扱えるので、エンジン通さなくてもブラウザで見ることができる点です。
HTML のタグの中に th:XXX
という属性を使ってテンプレート処理していく感じです。
Springで使うと Spring の独自拡張などもあり機能満載です。 機能満載なのであまり学びやすいとは言えず、Thymeleaf のテンプレートはそのままHTMLであるという制約のために書き方が難しくなるケースもあり個人的にはあまり好きではありません。。
それは置いておいて src/main/resources/templates/hello.html
を作成しましょう。
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Getting Started: Serving Web Content</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <p th:text="'Hello, ' + ${name} + '!'" /> </body> </html>
変数式 ${...}
でコントローラで追加した属性を参照できます。
th:text
はタグ内のテキストをエスケープ付きで出力するもので、モデルに追加した name
を表示するものです。
アプリケーションの実行
Spring Boot Gradle Plugin により bootRun
タスクが追加されているので、以下のようにすればアプリケーションが起動します。
./gradlew bootRun
java
プラグインを入れていれば bootJar
というタスクが追加され、実行可能な jar ファイルが出力できますし、war
プラグインを入れていれば bootWar
というタスクが追加され、war ファイルが出力できるようになります。
Embedded Tomcat が起動するので http://localhost:8080/hello
にアクセスすれば Hello, World! が出力されます。
Embedded Tomcat がどんなものかは以下参照。
クエリパラメータ付けた結果は以下のようになります。
ここまででディレクトリ構成はこんな感じになります。
今回はここまでで、次回に続きます。