サンプルアプリケーションの概要
サンプルアプリケーションは図1に示すような簡単な住所録管理アプリケーションです。
このアプリケーションでは、表1のAPIを提供します。
| エンドポイント | HTTPメソッド | 概要 |
|---|---|---|
| /contact/add | POST | 新規に連絡先データを登録する |
| /contact/list | GET | 登録してあるデータ一覧を取得する |
| /contact/item/{id} | GET | 指定したidの連絡先データ情報を取得する |
| /contact/item/{id} | POST | 指定したidの連絡先データ情報を更新する |
| /contact/item/{id} | DELETE | 指定したidの連絡先データを削除する |
サンプルアプリケーションの実行方法
サンプルコードはSpring Bootのアプリケーション(sample/java以下)とHTMLやJavaScriptなどのWebリソース(sample/web以下)の2つに分かれています。
Webリソースは既にサーバ内にApacheなどの他のWebサーバが利用できるのであればそちらを利用するとよいでしょう。
HTML側はサンプルアプリケーションがあるサーバと同じ場所でなくても動作するようになっています。その場合には、アクセスできる場所に配置できれば、どのようなパスであっても問題ありません。
また、リスト1に記載されているAPIサーバへのアクセス先URLを変更してください。
window.api = "http://localhost:8081/contact";
利用できるWebサーバがない場合には、設定ファイルをリスト2のように変更することで、アプリケーション「Tomcat」を起動し、これを通じてアクセス可能です。
ただし、起動するポート番号を変更した場合には、前述したAPIサーバへのアクセス先URLも変更する必要があります。
app.web.prefix = /web app.web.resource = <sample/webのあるフォルダ> # 設定例 ( C:¥samples/web/ 以下にsample/web以下のHTMLソースを保存した時 ) # app.web.resource = file://C:/sample/web/ # tomcatを起動するポート server.port = 8081 # (以下、省略)
起動はリスト3のように行います。起動に成功したら、http://localhost:8081/web/index.htmlにアクセスしてください。
ただし、WebリソースはES6のコードを含んでいますので、最新のES6対応のブラウザ(ChromeやEdgeなど)を利用してください。
./gradlew bootRun ( MacやLinuxの場合 ) gradlew.bat bootRun ( Windowsの場合 )
[Note]Spring Bootを使ったサーバサイドHTMLアプリケーションについて
Spring BootでのJSPを使ったアプリケーションやHTMLテンプレートエンジンを使ったHTMLアプリケーションの開発も問題なく行えます。しかし、TomcatなどのWeb Application Server上で開発する方法に比べて実績やノウハウなどの情報は多くはありません。
また、Webサイトのように日々の編集運用が必要になるものをSpring Bootを用いて開発するメリットは筆者はあまり感じませんでした。
一方、Spring Bootが持つ他のサービスなどの自動設定機能を生かしたものとしては、筆者はマイクロサービスとして利用するAPIサーバなどが利用用途としてより適していると考えています。
そのため、サンプルアプリケーションもHTML側の実装について意図的に分離してあります。また、今回はHTML側の実装については趣旨からはずれるため説明は行いません。
サンプルコードのソースコード構造
サンプルアプリケーションがどのような動作をするのかがわかったところで、実際のソースコードの説明をしていきます。
ソースコードは図2に示すように大きくわけて4つのグループで構成されていますが、処理のメインなるAPI部分の実装は、ContactControllerのみとなっています。
しかしながら、処理のイメージがつかめないソースもいくつか存在しています。今回はソースコード全体にかかわる部分について紹介し、次回、個別の内容について紹介していきます。
Beanを登録するためのアノテーション
Spring BootにおいてBean定義は、既存のサービスなどの設定でもあり、今回のAPI部分の実装などのロジックの実装でもあります。そのため、どのようなBean定義をしているのかを理解することは大変重要になります。
また、Bean定義をする際にはアノテーションを利用するので、どのようなアノテーションを使えばよいのか知る必要があります。
アノテーションは用途別に大きく分類され、また、各用途に応じて上書きするアノーテションが作られています。
例えば、サンプルアプリケーションで利用しているBean定義のためのアノテーションの構造は3のようになっています。
Bean定義に利用されるアノテーションは、表2に示すorg.springframework.stereotypeに定義してあるものが最も基本です。基本的にはこれらのアノテーションに機能的な違いはなく、管理上の慣習として使い分けが行われています。
ただし、例外的にSpring MVCやSpring Dataなどのサブプロジェクトによっては特別な機能を持つクラスとして扱われる場合もあります。
| アノーテーション | 概要 |
|---|---|
| @Component | DIコンテナにBeanとして登録するための最も基本的なアノテーションです。 |
| @Configuration | Bean定義をJavaベースで行うためのアノテーションです。 |
| @Repository | データの保存や読み込みなどを扱うためのクラスを示すアノテーションです。Spring Dataなど使いデータベースを利用する場合には、このアノテーションを指定することで自動的にテーブルにアクセスできるようにするなど、特別な意味を持つケースがあります。 |
| @Controller | MVCのコントローラクラスであることを示すアノテーションです。Spring MVCを使うWEBアプリケーションでは、このアノテーションを指定することでWebからのリクエストを処理するためのクラスとして利用されます。 |
| @Service | ビジネスロジックなどを扱うためのクラスを示すアノテーションです。 |
そして、各サブプロジェクトで特別なものとして、これらのアノーテーションを上書きして別のアノテーションが定義されます。例えば、サンプルアプリケーションでは表3のアノテーションを使っています。
| アノーテーション | 概要 |
|---|---|
| @SpringBootApplication | Spring Bootのアプリケーションのmainプログラムを指定するための慣習として利用されるアノテーションです。 |
| @RestController | REST用のコントローラとして登録するためのアノテーション。 |
| @RestControllerAdvice | 各コントローラで共通の入力データ形式の変換やエラー処理などの共通処理を定義するためのアノテーションです。 |
どんなアノテーションを利用すればよいのかといった情報は、公式ドキュメントなどを丁寧に読んでいけばわかりますが、実際には非常に大変です。
一方で、それぞれのSpringのサブプロジェクトにはどのようなアノテーションがあり、また、どのような意味を持つのか一覧として参照できる情報もありません。
そのため、網羅的にアノテーションの内容について理解することはなかなか大変な作業です。ただし、慣れてくれば利用するアノテーションはおおよそ同じものを使うことになるでしょう。
その際に、多少わからないアノテーションなどに遭遇した場合でも、よく利用されるアノテーションのセットであることが多いのでアノテーション内のコードを参照する方が早いでしょう。
例えば、@RestControllerのコードを参照すると、リスト4のようになっています。これらのコードより、@ControllerとしてのBean定義であり、@ResponseBodyも同時に定義したアノテーションであることがわかります。
package org.springframework.web.bind.annotation; // (省略) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller @ResponseBody public @interface RestController { // (省略) }
また、同一パッケージ内に同じ利用シーンで使われる別のアノテーションなども定義してあるので、これらのJavaDoc情報などを参照にすれば、どのようなアノテーションが他にあるのかなどもわかります。
Bean定義のインスタンスを利用する
Bean定義したクラスのインスタンスにアクセスする際には、@Autowiredというアノテーションを利用します。また、そのサンプルコードがリスト5です。
@RestController // (1)Bean定義である指定 @Scope("request") @RequestMapping("/contact") public class ContactController { @Autowired // (2)Bean定義されたオブジェクトを利用する ContactRepository contactRepository; // : 省略 }
(1)は、先ほど紹介したBean定義をしているアノテーションです。(2)のように@Autowiredの指定をすればどのクラスでも利用できるわけではなく、必ず、利用する際にはBean定義されているクラス内でのみ利用できます。
従って、自分でnewによって作成したオブジェクトの場合には自分で設定しなければいけません。
設定ファイルを理解する
ある程度大きなアプリケーションを作成していると、必ずと言ってよいほど外部の設定から値を読む必要が発生します。
また、Spring Bootでは既存のミドルウェアの設定の変更がBean定義からも可能ですが、環境に依存する部分などは設定ファイルからも変更できるようになっています。
しかし、Spring Bootを使う上でアノテーションと同様にどのような設定項目があるのか知ることもなかなか難しいです。
今回、サンプルアプリケーションのために用意したリスト6の内容から設定がどのように行われているのかを理解していきましょう。
また、設定ファイルはデフォルトではクラスパス上のapplication.propertiesファイルからデータを取得します。
ただし、それ以外にもさまざまな方法が用意されていますので、より詳しく知りたい場合には、リファレンスを参考にしてください。
# サンプルアプリケーション内のコードで利用している設定 app.web.prefix = /web app.web.resource = classpath:/static/ # httpのサーバポートの指定 server.port = 8081 # JDBCの設定 spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:mem:contacts spring.datasource.username=h2user spring.datasource.password= # (省略)
設定ファイルの値を個別にコード内の変数にマッピングする
設定ファイルの値をコード内で変数として利用する場合には、リスト7のように@Valueアノテーションを利用します。
@Configuration public class WebConfiguration implements WebMvcConfigurer { @Value("${app.web.prefix}") // (1)基本の利用方法 private String webPrefix; @Value("${app.web.resource:classpath:/static/}") // (2)デフォルト値を指定した設定方法 private String webResource; // (省略) }
(1)が最も基本的なプロパティ設定値を利用する方法です。ただし、この場合に設定ファイルに指定のキーがない場合には、エラーになってしまいます。
その場合には、(2)のようにコロン(:)を使ってデフォルト値を設定すれば指定がない場合にも対応が可能です。
また、@Valueはフィールド以外にもメソッドにも利用できるので、設定を加工して利用したい場合などはsetterメソッドを用意して利用すればよいでしょう。
設定グループとして値を管理する
JDBCの設定のように設定項目が多くなると設定を1つの塊として管理したくなります。その場合には、@ConfigurationPropertiesを利用します。
@Valueを多く利用するとどこでどのような設定を使っているのかの管理がすぐに難しくなってしまうため、利用する場合にも限定した利用が望ましいと思います。
実際、Spring Bootのソースを見てもほとんど@Valueは使われていません。
例えば、server.portの設定を管理しているコードであるSpring Boot内のServerPropertiesクラスのソースを見てみます。
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { // : 省略 public void setPort(Integer port) { this.port = port; } // : 省略 }
また、同様にspring.datasourceの管理をしているクラスであるDataSourcePropertiesクラスのソースを見て見ます。
@ConfigurationProperties(prefix = "spring.datasource") public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean { // : 省略 public void setDriverClassName(String driverClassName) { // (1)spring.datasource.driver-class-nameの設定 this.driverClassName = driverClassName; } // : 省略 public void setUrl(String url) { // (2)spring.datasource.urlの設定 this.url = url; } // : 省略 }
どちらにも、@ConfigurationPropertiesという指定があり、また、prefixで設定グループ名が指定されています。例えば(1)は、spring.datasource.driver-class-nameの指定であり、大文字を“-(ハイフン)”に置き換えて読み替えることができます。
また、(2)ではspring.datasource.urlの設定であり、どちらもprefixで指定したグループ以下の名称はsetterメソッドを使って設定が行われます。
こういったルールで設定できる項目がわかるので、他の設定項目もどこのソースで設定が行われているかを調べると、その設定の意味などを把握する上で参考となります。
設定項目もアノテーションと同様に網羅的な説明があるわけではありませんが、よく使われる設定などは多くの方が疑問に思うため、ブログなどにアップされている情報も多いでしょう。基本的にはそれらが参考になります。
ただし、使っているSpring Bootのバージョンによって多少変わってしまったり、設定が増えていたりといったこともまれにあるため、筆者も疑問に思ったり、具体的に他の設定はないのかを調べる際には、上記のようにソースコードを調べてしまいます。
最後に
Spring Bootを使っていると、自分が実装したいソースコードの内容以外に、どういったアノテーションを使えばよいのか、または、どういった設定をすれば希望する内容が有効(無効)になるのかをよく調べることになります。
しかし、これらすべてを理解するとなると非常に大変で、また、Spring Bootの簡単に始められるといった利点をも失ってしまいます。従って、アノテーションや設定を使いこなすことを気にせずプログラムを始めるのが、Spring Bootでは大切なことだと筆者は思っています。
ただし、問題にぶつかった時にSpring Bootの仕組みがわからないと、どこで何がおきているのかがわからないため、今回紹介した最低限の仕組みについての理解は必要だと思います。
次回は、サンプルコードのWeb APIを作成する際に必要なアノテーションやデータベース関連のアノテーションなど機能部分について紹介します。
