最終更新日:2020/03/23 原本2019-02-26

Spring Bootで始める簡単Webプロジェクト~ひな型の作成からWeb APIの実装まで

Spring Bootで作るマイクロサービス 第2回

 Spring Bootの利点は、プロジェクトの作成から、実行、配布までが簡単にできることです。しかし、フレームワークを使う場合にいざプロジェクトを作ろうとしても、一体何から始めればよいのか、わからないことがあります。今回は、Spring Bootでのプロジェクトの作成方法から簡単なWeb APIの実装を通じてSpring Bootでの開発の流れを紹介します。

プロジェクトの概要

 最近のフレームワークでは、フレームワーク自身のツールでプロジェクトを始めることもよくありますが、Javaの場合には、既に広く普及しているMavenGradleといったプロジェクト管理ツールがあります。

 プロジェクトの管理はMavenもしくはGradleを使います。MavenやGradleは便利ですが、最初からプロジェクトを作るというと少々気が重くなります。

 しかし、Spring Bootではプロジェクトのひな型を作成するツールが用意されていて、必要な機能を選択しながら進められるので簡単に作成することができます。

 一度プロジェクトを作成してしまえば、Maven、もしくはGradle形式であるため、既にJava開発に慣れている方にとって非常にメリットがあり、初心者から上級者まで扱いやすくなっています。

プロジェクトの作成

 簡単にプロジェクトを始めるには、いくつか方法があります。

  1. Spring Initializr (Webツール)からプロジェクトのひな型をダウンロードする
  2. IDE(EclipseやIntelliJなど)を使ったウィザード形式

Webツールを使ったプロジェクトの始め方

 Spring Bootでプロジェクトを始める際に環境に依存しない方法を望むのであれば、Spring Initializrで提供しているWebサービスを使用する方法があります。

 Spring Initializrにブラウザでアクセスすると、図1のように最低限の入力でプロジェクトを作成することが可能です。

図1:Spring Initializr(簡易版)を用いたプロジェクトひな型の作成
図1:Spring Initializr(簡易版)を用いたプロジェクトひな型の作成

 また、画面下部の「Switch to the full version」をクリックすると、図2のようにフォームが表示されます。これは、各項目について詳細に指定したい場合に利用できるので、より詳細にカスタマイズしたい方はこちらのモードが使えます。

図2:Spring Initializr(フルバージョン)を用いたプロジェクトひな型の作成
図2:Spring Initializr(フルバージョン)を用いたプロジェクトひな型の作成

 これらで指定する項目は、表1に示す内容を設定します。各項目はMavenでプロジェクトを作成する際に記述するpom.xmlの内容とほぼ同じになっています。

表1:プロジェクト作成時に選択もしくは入力する項目
項目名 説明
プロジェクトタイプ MavenもしくはGradleのいずれかのタイプを選択します。
言語 Java以外にもKotlinやGroovyなどが選択できます。ここではJavaを選択します。
バージョン バージョンは1.5.xと2.0.x、2.1.xなどがありますが、これからプロジェクトを始める場合には、2.1以降を選択します。
Group グループ(プロジェクトのグループ名。通常、プロジェクトのルートパッケージ名)を設定します。
Artifact プロジェクト名に相当するパッケージ名を指定します。
Name プロジェクトの表示名(Mavenの場合)とmainプログラムのクラス名としても使われます。Artifactと同じ名称を使用することを推奨します。
Description プロジェクトの説明を入力します。
Package Name プロジェクトのパッケージ名。通常は、Groupで指定したパッケージとArtifactで指定した名称で構成されます。
Packaging  パッケージする方法をJarもしくはWarのいずれかを選択します。通常はJarを選択しますが、作成されたものを別のWebコンテナなどで稼動させる場合にはWarを選択します。
Java Version Javaのバージョンを指定します。
Selected Dependencies  使用する各種機能を指定します。実際には、Spring BootでのStarterを指定しています。

 今回のサンプルでは、Webアプリケーションを作成することを前提としています。そのため、依存する機能として「Web」を選択するようにしてください。実際には必要な依存分をすべて追加していきますが、後から追加や変更も簡単なため、この時点ではあまり気にせず進めて問題はありません。

 項目の入力が終了したら、「Generate Project」ボタンを押すと、プロジェクトのひな型ファイルがZipファイルとしてダウンロードできます。

 また、ダウンロードしたファイルを解凍し、IDEにインポートして利用する流れになります。

IDEを使ったプロジェクトの始め方

 IDEを使って開発をしている場合には、IDEのプラグインを使えばWebツールを使わずに直接IDE上でプロジェクトを作成できます。作成の手順とUIは多少異なりますが、入力もしくは選択する項目は同じです。

 Eclipseの場合には、Spring用のプラグインのSpring Tools 4(2018/12/23現在 4.1.0.RELEASE)を追加します。

 ダウンロードしてインストールすることも可能ですが、Eclipse Marketplace(Help -> Eclipse Marketplaceを選択)からインストールすることも可能です。

 また、Spring Toolsを使ってSpring Bootのプロジェクトを作成しているときの画面が図3です。

図3:Eclipseのプラグイン(Spring Tools)を用いたプロジェクトひな型の作成
図3:Eclipseのプラグイン(Spring Tools)を用いたプロジェクトひな型の作成

 筆者はIntelliJ IDEAを主に使っています。有償版であるUltimate版の場合にはデフォルトでSpring Boot用のプラグインがインストールされていますが、Community版では同じプラグインは用意されていません。

 代わりに、Spring AssistantというプラグインをインストールすることでEclipseのプラグインと同様の流れでプロジェクトを作成可能です。

 また、Net Beansでは、NB SpringBootというプラグインで同様のことができます。

プロジェクトの構造

 Webツールを使っても、IDEを使ってもできあがるプロジェクトのディレクトリやファイル構造は同じため、どちらを使ってもその後の進め方や、メンテナンス方法が異なることはありせん。

 また、MavenとGradleのどちらの形式にするかは、利用者が好きな方を選んで問題ありません。筆者は、MavenでのXML形式よりもGradle形式の方が見やすく、そしてAndroidプロジェクトの場合にはGradleの方がよく利用されているといった理由から、Javaでのプロジェクト管理にはGradleを利用しています。

 Gradleの方がMavenよりも後発のため、同様の機能を持ちつつ、スクリプト形式を採用することで、XML形式より開発者がちょっとした作業を記述しやすくなっています。

 また、今後のサンプルなどはGradle形式で紹介していきますので、どちらにするか迷う場合には、Gradle形式を選択することをおすすめします。

Mavenを使ったときのプロジェクトの構造と実行までの流れ

 Maven形式でプロジェクトを作成すると、図4のディレクトリとファイルが作成されます。

図4:Maven形式でプロジェクトを作成したときのディレクトリとファイル一覧
図4:Maven形式でプロジェクトを作成したときのディレクトリとファイル一覧

 Maven形式でプロジェクトを作成しても、プロジェクト内にあるmvnwコマンドを使えば別途、Mavenをインストールする必要はありません。

 コンパイルやビルドなどは他のMavenでのタスクと同様に使えますが、Spring Bootのコードを実行する場合にはリスト1のようにspring-boot:runタスクで実行が可能です。

[リスト1]Mavenプロジェクトの場合の実行例
 ./mvnw spring-boot:run
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< com.coltware.spring:demo2 >----------------------
[INFO] Building demo2 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
// ・・・省略
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.1.RELEASE)

2018-12-23 17:28:28.783  INFO 17835 --- [           main] c.c.spring.demo2.Demo2Application        : Starting Demo2Application on musvia16.local with PID 17835
//  ・・・省略

Gradleを使ったときのプロジェクトの構造と実行までの流れ

 Gradle形式でプロジェクトを作成すると、図5のディレクトリとファイルが作成されます。

図5:Gradle形式でプロジェクトを作成したときのディレクトリとファイル一覧
図5:Gradle形式でプロジェクトを作成したときのディレクトリとファイル一覧

 GradleでもMavenと同様に、プロジェクト内にあるgradlewコマンドを使えば、別途、Gradleをインストールする必要はありません。

 また、コンパイルやビルドでも同様に、Spring Bootのコードを実行する場合にはリスト2のようにbootRunタスクで実行が可能です。

[リスト2]Gradleプロジェクトの場合の実行例
./gradlew bootRun
Downloading https://services.gradle.org/distributions/gradle-4.10.2-bin.zip
..........................................................................
// ・・・省略
> Task :bootRun
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.1.RELEASE)

2018-12-23 17:31:04.441  INFO 17863 --- [           main] c.c.spring.demo2.Demo2Application        : Starting Demo2Application on musvia16.local with PID 17863
// ・・・省略

Spring Bootで簡単なWeb APIを作成する

 続いて、先ほど作成したプロジェクトを使い、図6に示す簡単なWeb APIのエンドポイントを追加しつつSpring Bootでの開発の流れを紹介します。

図6:サンプルの仕様
図6:サンプルの仕様

 サンプルの仕様は、(1)のように設定ファイルがあり、その設定ファイルで変数の初期値を指定します。次に、(2)のようにその変数の値を保持するアプリケーションで1つの共有インスタンス(シングルトンインスタンス)を保持します。

 そして、(3)のようにそのインスタンスをJSON形式でGETできるAPIエンドポイントと、POSTで変更できるAPIエンドポイントがあります。リスト3はこれらのAPIを利用したときの実行例です。

[リスト3]サンプルコードに対してAPIを実行したときの例(出力は整形済み)
$curl -s http://127.0.0.1:8080/hello/world
{
  "value": "Hello sample"
}
$curl -s -H 'Content-Type:application/json' -d '{ "value" : "こんにちは" }' http://127.0.0.1:8080/hello/world
{
  "value": "こんにちは"
}
$curl -s http://127.0.0.1:8080/hello/world
{
  "value": "こんにちは"
}

 また、これらのソースが図7のようなパッケージ、もしくはフォルダ構造になっています。

図7:サンプルソースのディレクトリ構造
図7:サンプルソースのディレクトリ構造

 ここでは、必ずメインプログラムであるSampleApplicationクラスのパッケージ以下に関連クラスを作成するように気を付けてください。

 SpringBootではそれぞれのクラスに付与されたアノテーションから自動的に管理できるようにしていますが、そのためにはプロジェクトのメインパッケージ配下に置く必要があります。

 ただし、これらの制限はあくまでデフォルトの設定ではあり、これらの変更方法は次回以降説明します。現時点ではSpring Bootで特別な設定が必要ないように、こういったルールでコードを記述するようにしてください。

アプリケーションでの設定(DI)を制御する

 Springでの設定では、設定ファイルから値を取得するといった単純なものだけではなく、DIを実現するためのコードの記述もすることになります。

 前回、DIを実現する方法として、XMLを使う以外にJavaのコードでDIの設定ができると紹介しました。リスト4がSpring FrameworkのDI設定例です。

[リスト4]JavaベースでのDIの設定方法(src/main/java/com/coltware/spring/sample/config/SampleConfiguration.java)
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// (1) Javaベースの設定を示すアノテーション
@Configuration
public class SampleConfiguration {

    // (2) 設定ファイルから"sample.world"の値で設定する
    @Value("${sample.world:World}")
    String world;

    // (3) オブジェクトの作成方法を指定する
    @Bean
    public WorldModel worldModel(){
        WorldModel model =  new WorldModel();
        model.setValue(world);
        return model;
    }
}

 クラス宣言の前に(1)のように@Cofigurationアノテーションを指定します。この指定がDIのためのコードであることを指定します。続いて、(2)では設定ファイルの"sample.world"という項目の値を取得し、変数に設定しています。

 また、設定がない場合のデフォルト値の指定は、:(コロン)以降に記述します。(3)ではこのアプリケーション内でのWorldModelの共有インスタンスを示す@Beanアノテーションを指定します。

 このような流れでDIの定義をしていきます。DIの指定方法がJavaのコードになってしまったことで後から柔軟に実装を入れ替えることができなくなり、DIを使わない頃のJavaに先祖返りしてしまった印象を受けるかもしれません。

 しかし、実際にはXMLでの柔軟すぎる変更の可能性やそれに伴う複雑なXML記述というのはデメリットも多々ありました。

 そのため、Javaにすることでもう一度、開発者にコントロールを戻しています。ただし、開発者はあくまで設定という視点でわかりやすいコードを記述するように心がける必要があります。

Web APIのエンドポイントを定義する

 Web APIのサンプルコードがリスト5です。同様のことを実現する際には、一般的にはServlet APIを使いますが、Springでは特定の親クラスを継承する必要がありません。

 そのため、他のコードからの依存性を低く保ちつつ、また、テストが行いやすいコードとして記述しやすくなっています。

[リスト5]JavaベースでのDIの定義方法(src/main/java/com/coltware/spring/sample/api/HelloController.java)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

// (1) Rest用のコントローラクラスであることを宣言する
@RestController
// (2) /hello 以下のリクエストに対する処理
@RequestMapping(value = "/hello")
public class HelloController {
    private static final Logger log = LoggerFactory.getLogger(HelloController.class);

    // (3) 自動的にWorldModelオブジェクトを設定する
    @Autowired
    WorldModel model;

    // (4) GET /hello/world  に対する処理
    @GetMapping(value = "/world")
    public WorldModel world(){
        return model;
    }
    //  (5) POST /hello/world  に対する処理
    @PostMapping(value = "/world")
    public WorldModel setWorld(@RequestBody WorldModel world){
        model.setValue(world.getValue());
        log.info("set value : {}",model.getValue());
        return world;
    }
}

 (1)ではRest用のコントローラであることを宣言しています。ここでのRestとはRESTFulという意味ではなく、単純にWebアプリケーションのコントローラである、といった程度の指定です。この指定によりWebコンテナが指定のURLで、どのコントローラを起動すればよいかを管理しています。

 Springのプロジェクトの経験がある方であれば、Web用のコントローラクラスに@Controllerというアノテーションを使っていたと思いますが、Web APIのようにJSON形式のコントローラの場合には@RestControllerというアノテーションをつけることでリターン値をJSON形式のレスポンスデータとして扱うことができます。

 また、(2)ではこのコントローラが/helloというエンドポイント配下に対する処理であることを定義しています。

 続いて、(3)の@AutowiredというアノテーションはDIを実現するための指定でWorldModelのインスタンスが自動的に設定されます。

 (4)では、/hello/worldに対してGETリクエストがあったときの処理を定義し、(5)ではPOSTリクエストがあったときの処理を定義しています。@RequestBodyというアノテーションは、リクエストデータとしてWorldModelのJSONフォーマットを利用することを宣言しています。

 また、リクエストやレスポンスがJSONからJavaのオブジェクトに自動的に変換されていますが、JSONフォーマットへの変換方法にはデフォルトではJacksonを使っています。

 そのため、必ずしも自分で指定したオブジェクトが正しくJSONにならなかった場合や、希望するフォーマットにカスタマイズする際には、Jacksonの仕様について知る必要があります。

最後に

 Spring Bootを使えば、TomcatなどのWebコンテナの設定、起動、停止の方法、そして、開発したコードの設定方法などにわずらわされることなく、すぐにコードの記述、実行まで確認できます。

 これらの簡略化は、Springが提供しているさまざまなアノテーションと、それらの設定やルールをまとめたSpring BootのStarterによって実現しています。

 アノテーションの使い方やSpring特有の注意点などを覚える必要はありますが、Spring Bootはそれらを考慮しても十分使いやすくなっています。

 また、利用する開発者が非常に多いために、ドキュメントやノウハウなども十分に蓄積されていることも安心できる大きな要因です。次回からは、もう少し本格的なサンプルを作成しながら各機能の紹介をしていきます。

参考資料