ユーザ認証: 単純なログイン

ユーザ認証を行ってみましょう(参考: Getting Started · Securing a Web Application)。

spring-boot-starter-security

Springにはセキュリティ関係の機能をサポートするSpring Securityがあり、またSpring Bootで利用する場合はspring-boot-starter-securityを使うことができます。build.gradleのdependenciesに追加します。

ログインフォーム

まずログインフォームを作り、アクセスできるようにしておきます。

テンプレートは、/loginにusernameとpasswordを送るようにします。

コントローラでは/loginにアクセスがあったときに上記のテンプレートが表示されるようにします。Getting Started · Securing a Web Applicationでは、WebMvcConfigurerAdapterを使ってビューを追加していますが、どちらでも構いません。

WebSecurityConfigurerAdapter

WebSecurityConfigurerAdapterを継承した設定用クラスを作り、overrideしたconfigureメソッドで設定を行います。

  • 10行目: 設定用クラスであることを指定する。
  • 11行目: Spring Securityのウェブ用の機能を利用することを指定する。
  • 14〜18行目: configureメソッドをoverrideし、ここで設定を行う。16行目ではトップページ(/)は認証無しでアクセス可、それ以外は認証が必要なことを設定している。複数のページを認証なしでアクセス可とする場合は「antMatchers(“/”, “/sample”)」のように複数指定することができる。17行目ではログインフォームのURLが/loginで、ここへのアクセスも全てのユーザがアクセス可能としている。
  • 20〜27行目: GlobalAuthenticationConfigurerAdapterを継承したクラスのinitメソッドで認証するユーザとパスワードを設定する。

ログインの確認

トップページ(/)以外のページにアクセスすると/loginにリダイレクトされます。

Login

ユーザ名・パスワードがあっていれば、元のURLに移動します。ユーザ名・パスワードが間違っている場合はエラーメッセージが表示されます。

Login error

Spring-Loadedの利用

一般に、Servlet環境での開発は、プログラムを変更したら、再デプロイをして動作を確認します。しかし再デプロイは時間がかかるため開発効率がよくありません。このため再デプロイすることなくプログラムの追加・変更を適用することができる「hot swap」や「hot deploy」と呼ばれる手法が使われることがあります。

Spring-LoadedはSpringアプリケーションのhot deployを実現するライブラリです。Spring-Loadedを利用するにはgradle.buildを次のようにします(参考: 67.6.1 Configuring Spring Loaded for use with Gradle and IntelliJ)。

  • 7行目: Spring-Loadedの利用を指定する。
  • 12行目: gradleのideaプラグインを利用する。
  • 18〜23行目: IDEAによる出力をgradleの出力先に合わせる。

Intellijの設定では、「Make Project Automatically」をonにします。

これによりbootRunで実行中にプログラムを書き直すと起動中のプログラムも修正されます。

Spring Bootの利用

これまで行ってきたように、ウェブアプリケーションの開発では様々なライブラリ/フレームワークを使います。grailsやmaven等のツールを用いることにより様々なライブラリ等が簡単に利用可能となりますが、それでも設定ファイルの作成等、面倒な作業が多く、ミスの元になったりします。

「Spring Boot」は「Spring Frameworkを使ってさらに簡単にウェブアプリケーションを作る仕組み」です。Spring Bootを使うことで標準的な設定がなされたウェブアプリケーションのベースを利用することができます。ただし、これまで紹介してきた設定の知識が不要になる、というわけではありません。自動設定(というか定義済み設定)が利用できるというだけで、自動で設定できない部分はこれまでと同様に設定する必要があります。

具体的には「Starter」を利用することになります。使いたい機能のStarterを加えることでライブラリの導入や設定が行われます。用意されているStarterの一覧は12.4 Starter POMsにまとめられています。

それでは、ここまで(掲示板の作成まで)と同等の環境をSpring Bootで構築してみましょう。

Gradle

プロジェクトはこれまでと同様にGradleを利用して作成し、build.gradleを次のように編集します(参考: 9.1.2 Gradle installation)。

  • 1〜8, 11行目: Spring Bootのgradleプラグインを利用する。
  • 21〜26行目: 利用するstarterの指定。ここではJetty(Tomcatを使わない)、Thymeleaf、Spring Data JPAを利用するように指定している。
  • 27行目: H2を利用する。

起動用のクラス

Spring Bootはウェブアプリケーションを実行する環境も用意することができます(これまでと同様にwarファイルを生成することももちろんできます)。Gradleの設定ではJettyを利用するように設定しました。Jettyを起動してウェブアプリケーションを実行するクラスを作成します(参考: 13.2 Locating the main application class)。

  • 8行目: このクラスが設定用のクラスであることを指定する。
  • 9行目: 自動設定を有効にする。
  • 10行目: このクラスのパッケージ内のクラスをDIの対象にする。
  • 13行目: ウェブアプリケーションを起動する。

設定ファイル

Spring Bootは設定が自動でされることが特徴ですが、最低限の設定はしなければなりません。またデフォルトの設定を変更したい場合もあります。その設定の方法の1つとして、application.propertiesを使う方法があります(参考: Appendix A. Common application properties)。

resourcesディレクトリにapplication.propertiesを作成します。

ここでは、データベースファイルの置き場所、ユーザ名、パスワード、ドライバを設定し、HibernateのDDL自動生成は、create-drop(削除して再作成)としている。

ディレクトリ構成

これまではWEB-INFというディレクトリがありましたが、Spring Bootのデフォルトではここは使いません。Thymeleafのテンプレートのデフォルトはresources/templatesに置きます。

Spring Bootのディレクトリ構成

実行

実行は次のようにgrablewから行います(Windowsの場合はgradlew.bat)。事前に「chmod +x grablew」として実行可能としておきます。

./gradlew bootRun

IntelliJのTerminalから実行するのがよいでしょう。

grablew bootRun

Started Applicationと表示されたら、実行中です。終了するにはキーボードからCtrl+Cを押します。

文字化け対策: CharacterEncodingFilterの利用

文字化けは様々な原因が考えられますが、Springの環境ではCharacterEncodingFilterを使うことで文字化けをなくすことができる場合があります。

CharacterEncodingFilterはweb.xmlで設定します。

掲示板を作る: Viewの作成

最後にViewを作って完成です。

Controllerの返り値として「bbs/index」を指定しているので、templatesディレクトリの中にbbsフォルダを作ってその中にindex.htmlを作成します。

  • 10行目: th:eachを使うとリストから1つずつ取り出して、要素が生成される。この場合commentListから取り出した値はcommentとして参照できる。comment.nameでcomment.getName()が実行される。
  • 12行目: actionの代わりにth:actionを指定すると@{}を使ってURLを記述することができる。@{}を使うと、contextに応じたpathに書き換えてくれる。

実行例

BBS

H2コンソールで確認すると、idが自動的に割り当てられているのがわかります。

H2console2

掲示板を作る: Controllerの作成

掲示板のControllerを作成します。

今回はこれまで作ってきたTopContorollerではなくて、掲示板用のコントローラを作成します。掲示板では、コメントの表示とコメントの投稿の2つの機能が必要ですが、これを1つのページ(URL)で実現してみます。具体的にはたんなる表示の時はGETメソッドを用い、投稿時にはPOSTメソッドを使うようにします。

  • 18行目: ベースとなるURLを「/bbs」にする。
  • 20、21行目: @AutowiredアノテーションでCommentRepositoryをDI(dependency injection、依存性の注入)することを表す。これにより、システムがCommentRepositoryをインスタンス化してくれる。
  • 23〜28行目: GETメソッドによるアクセスを処理するメソッド。25行目でデータベースから全てのデータを取得する。26行目で取得したデータをビューに渡す設定をする。
  • 30〜37行目: POSTメソッドによるアクセスを処理するメソッド。32〜34行目で、Commentクラスのインスタンスを生成し受け取ったパラメータをそれぞれセットする。35行目でCommentRepositoryを使ってセーブする。これ以降の操作はGETメソッドの場合と同様なので、indexGetを呼んでそれを返り値とする。

掲示板を作る: EntityとRepositoryの作成

データベースの利用の例として、掲示板を作成してみましょう。

まずは、EntityとRepositoryを作成します。

Entity(JPA Entity)とは、データベースにおける表の個別の行に対応するオブジェクトです。JPAではPOJO(Plain Old Java Object、ごく普通のJavaオブジェクト)にアノテーションを加えるだけで作成できます。今回は単純に、名前と本文だけを保存するようにしてみます。DatabaseConfig.javaの44行目でEntityを示すパッケージを指定しているので、そこにCommentクラスを作成します。

  • 10行目: @EntityアノテーションでEntityであることを示す。
  • 12〜14行目: JPAでは主キーが必要となる。@Idアノテーションで主キーを示す。また@GeneratedValueで値を自動生成することを示す。
  • 15行目: 名前を格納するフィールド。
  • 16行目: 本文を格納するフィールド。
  • 18〜32行目: nameとtextのgetter/setter。getter/setterはメニューから[Code]→[Generate]→[Getter and Setter]で自動生成できる。

このCommentクラスのインスタンスをデータベースに格納するには、Repositoryとよばれる、データベースへの操作を行うためのオブジェクトが必要です。RepositoryはSpring Data JPAに含まれるJpaRepositoryインターフェースを使うと簡単に作成することができます。JpaRepositoryインターフェースを継承することにより、データベースの操作に関するメソッドが自動的に生成されます。

DatabaseConfig.javaの24行目でRepositoryを示すパッケージを指定しているので、そこにCommentRepositoryインターフェースを作成します。

  • 10行目: @RepositoryアノテーションでRepositoryであることを示す。
  • 11、12行目: JpaRepositoryを継承する。型変数はEntityの型とそのEntityの主キーの型を指定する。基本的な機能(メソッド)は自動的に生成されるので、いまのところメソッド等の記述は必要ない。

データベース接続の設定

今回はJPAを使います。実装としてHibernateを利用します。

まず、Spring Data JPAHibernateH2のライブラリをdependenciesに追加します。これまでと同様に、更新とArtifactの設定を行います。

次に、設定用のクラスを作成します。Thymeleafの設定と同様に、configパッケージ内にDatabaseConfigクラスを作成します。

  • 22行目: @Configurationアノテーションで設定用のクラスであることを示す。
  • 23行目: @EnableTransactionManagementアノテーションでトランザクションの管理を有効にする。
  • 23行目: @EnableJpaRepositoriesアノテーションでJPA Repositoriesを有効にする。Repositoryが格納されるパッケージを引数とする。
  • 27〜35行目: データソースをBean登録する。設定内容はH2の設定と同じにする。
  • 37〜54行目: EntityManagerFactoryをBean登録する。44行目で対象となるentityが含まれるパッケージを指定している。48行目でdialectを設定する。これによりHibernateがデータベースに適した動作をするようになる。49行目でテーブル等の自動生成について設定している。「create-drop」はdeply時に、テーブルを削除(drop)して作りなおす(create)という設定である。他に設定可能な値として、
    none
    何もしない
    create
    テーブルがない場合に作成する
    update
    テーブルの構造が変わった時に変更する
    validate
    テーブルの構造をチェックする

    等がある。開発時にはcreate-drop、create、updateを使い、運用時にvalidateにするといった使い分けをする。

  • 56〜61行目: トランザクションマネージャーをBean登録する。
  • 63〜66行目: 例外を変換するTranslatorをBean登録する。

Springにおけるデータベースへのアクセス方法

一般に、Javaにおけるデータベース(RDBMS)へのアクセスには(代表的なものとして)下記の方法が使われます。

  • JDBC
  • HibernateやTopLink等のORMライブラリ
  • Java Persistence API (JPA)
  • Java Data Object (JDO)

JDBCはデータベースに接続し、SQLによるクエリを実行するためのAPIです。SQLは自分で書かなければいけません。

HibernaeやTopLink等のORMライブラリを利用すると、SQLを(あまり)意識することなくJavaのインスタンスをデータベースに保存できるようになります。ライブラリがSQLを自動生成・実行してくれるわけです。

JPAとJDOは「仕様」のため、様々な実装が存在します。JPAはRDBMSへの操作を抽象化するAPIです。HibernaeやTopLinkもJPAの実装として利用することができます。JDOは永続化そのものを抽象化するAPIで、RDMBS以外のデータベースも対象としています。

Springでは、これらを直接使うのではなく(直接使うこともできますが)、利用をサポートする仕組みが用意されています。例えば、JDBCの場合には、Spring Framework JDBCを使うことで、データベースの接続やトランザクション等を簡単に扱うことができます。
JPAを使う場合には、Spring Dataに含まれるプロジェクトであるSpring Data JPAを利用することで、ページング等を簡単に実現することができます。

H2の起動

データをデータベースに保存できるようにしましょう。

今回はデータベースとしてH2を利用します。

ちなみにGlassFishにはJava DB(中身はDerby)が付属しているので、こちらを利用することもできます。

zipをダウンロードしたら、適当な場所に展開し、次のようにして起動します。

% cd bin
% java -cp h2-1.4.180.jar org.h2.tools.Server &
TCP server running at tcp://XXX.XXX.XXX.XXX:9092 (only local connections)
PG server running at pg://XXX.XXX.XXX.XXX:5435 (only local connections)
Web Console server running at http://XXX.XXX.XXX.XXX:8082 (only local connections)

ブラウザが自動的に開いてH2コンソールが表示されます。各項目を入力して[保存]をクリックします。

設定名
MyFirstSpringApp (Server)
ドライバクラス
org.h2.Driver
JDBC URL
jdbc:h2:tcp://localhost/~/tmp/myfirstspringapp
ユーザ名
sa
パスワード
password

H2console

設定名はなんでもOKです。JDBC URLはアプリケーションからアクセスするときに使うURLです。この場合、起動したユーザのホームディレクトリ(~)のtmpディレクトリに、myfirstspringapp.mv.dbというファイルに保存されるということになります。ユーザ名・パスワードは任意に設定できます。

[接続]もしくは[接続テスト]をクリックして、接続できるか確かめておきます。