普通の Spring Boot 2.0 Web Applicatrion 〜 Spring MVC で Hello World 〜

Spring Boot 2 で、なるべく標準的なやり方で、トラディショナルな Spring MVC による Web Application を作成するチュートリアルを数回に分けて。

Web Application 作成の流れを、細か過ぎる説明は省き、ざっくりと一通り見ていきます。

目次

今回は 「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.gradleenableFeaturePreview('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 がどんなものかは以下参照。

etc9.hatenablog.com


クエリパラメータ付けた結果は以下のようになります。

f:id:Naotsugu:20180514222659p:plain


ここまででディレクトリ構成はこんな感じになります。

f:id:Naotsugu:20180514222737p:plain



今回はここまでで、次回に続きます。