Spring Bootでユーザ認証を行う

ユーザ認証

ソースコード

変更(追加)

  • build.grade: spring-boot-starter-securityをdependenciesに追加

新規作成

関連文書

昨年度の資料はバージョンが古いので注意する必要があるが、参考になるはず。

大量のデータを扱えますか?

前回のまとめ等

  • 関数
    • 関数を定義するときの書式と意味をきちんと理解する
    • 戻り値(返り値)の型、関数名、引数(仮引数の型と引数名)、関数の本体(処理内容)
  • 前回、説明を省略したもの(そのうち説明する)
    • プロトタイプ宣言
    • 値渡しと参照渡し
    • 再帰呼び出し
    • etc…
  • 課題の解答例

配列を使おう

実行例と同じになるようにプログラムを修正(関数を追加するだけで、元のコードは変更しない)して実行しよう。

BMI算出

元のプログラム: bmi.c

BMIの計算は用意されている関数(calc_bmi)を使う。

三目並べ

三目並べを作ろう。石を同じところに置いた場合のチェックや入力間違いのチェックはしなくてよい。

元のプログラム: tictactoe.c

物足りない人へ

ライフゲームを作ろう。

さらに物足りない人はLangton’s loopsを作ろう。さらに物足りない人はEvoloopを作ろう。

Spring BootでJDBCを使う(アプリ開発例)

データベースのCRUD

前回は、掲示板のデータをデータベースに格納するように(永続化するように)改良した。そこでのポイントは以下の通り。

  • Javaでデータベースを扱う(接続する)方法の1つにJDBCがあり、Spring BootにおいてはSpring JDBCという仕組みが使える(他にも色々あるがまずはこれ)。
  • H2は組み込みで使えるデータベースで、Spring Bootから簡単に使える。ウェブインターフェースも使える。
  • データベースを操作するSQL
    • CREATE TABLE: テーブルを作成する
    • SELECT: テーブルからデータを取得する
    • INSERT: テーブルにデータを投入する。
  • 具体的には、JdbcTemplateのメソッドを使って、SQLを実行する。

データベースを使った永続化の扱いの基本はCRUDと言われている。
今回はオンラインメモ帳の開発を通してCRUDを一通り実装してみよう。また、Spring Bootにおけるウェブアプリ開発で使われる基本を紹介する。

ソースコード

ポイント

テーブルの作成

前回、テーブルの作成はH2のウェブインターフェースから行ったが、これもプログラムから実行できる。下記はテーブルを作成するプログラムであるが、「IF NOT EXISTS」をつけることによって、テーブルが存在している場合は実行されない(テーブルがない時だけ実行される)。これをコントローラのコンストラクタで実行している。(Lect11Controller.javaの34〜41行目)

レコードの編集(更新)

レコードを更新するにはUPDATEを使う。更新するカラムを「カラム名 = 値」で指定する。WHEREで更新するレコードを限定する。(Lect11Controller.javaの103行目)

フォームのデフォルト値

フォームのデフォルト値はほとんどの場合、value属性で設定することができる。これをTymeleafで設定するには「th:value=”${変数}”』をタグにつければ良い。ただし、textareaタグはタグによって挟まれたところ(textareaの子となるテキストノード)がデフォルト値となるので「th:text」を使う。

非表示でもフォームで送信

画面上に表示させないが、フォームで値を送信したい場合、type属性の値として「hidden」を指定する。(edit.htmlの14行目)

レコードの削除

レコードを削除するにはDELETEを使う。WHEREで更新するレコードを限定する。(Lect11Controller.javaの112行目)

レコードの並び順

SELECTでレコードを取得するときには並び順を指定することができる。「ORDER BY カラム名 順番」を付加する。順番はASC(昇順)かDESC(降順)を指定する。(Lect11Controller.javaの50行目)

改行を含む文字列の表示

HTMLにおいて改行はスペースと同様の扱いになる(基本的には。例外はpreタグ等)。このため改行がある場合は、brタグを挿入する等の処理が必要である。色々な方法が考えられるが、今回のコードでは下記のような処理を行なっている。

  • Note.javaにフィールドbodyを改行区切りのListで返すメソッドを追加(Note.javaの20〜30行目)
  • テンプレートでは1行づつ取得し、行末にbrタグを付加して表示(view.htmlの19〜22行目)

リンクの動的な生成

index.htmlでは操作に関するリンクを動的に生成している。

URLの一部を変数として扱う

マッピングの指定(@GetMapping、@PostMapping、@RequestMapping)で「{}」を使うと、その部分を変数として利用することができる。

Lect11Controller.javaの119行目を見てみよう。ここでは「/view/{id}」となっている。これは、/view/1や/view/2といったURLに対応する。
「{id}」の部分を取得するには、メソッドの引数に、カッコ内と同じ文字列(ここではid)を指定して@PathVariableアノテーションを付加する(Lect11Controller.javaの120行目)。

Javaで永続化

Javaで永続化

本日の内容: https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/html/boot-features-sql.html

永続化とは

これまで作ったウェブアプリは、起動し直すとそれまでに入力したデータ(例えば掲示板のコメント等)は消えてしまっていた。今回は、入力されたデータを保存することを考えよう。このように、プログラムの実行を終了してもデータが存続する特性を永続性(Persistence)といい、永続性を持たせることを永続化という。

Javaプログラムにおける永続化の方法

色々な方法がある。

  • テキストファイルとして保存
    • 独自の書式(フォーマット)を開発・利用
    • 既存のフォーマットを利用
      • CSV
      • HTML、XML(をベースとしたマークアップ言語)
      • JSON(JavaScript Object Notation)
      • YAML
      • OpenDocument
      • etc…
  • バイナリファイルとして保存
    • 独自の形式を開発・利用
    • 既存のフォーマットを利用
      • Rich Text Format
      • PNG、JPEG、TIFF、MPEG
      • PDF
      • etc…
  • データベースシステムを利用
    • 独自のシステムを開発・利用
    • リレーショナルデータベースベース管理システム(relational database management system, RDBMS)を利用
    • RDBMS以外のデータベース(NoSQL、オブジェクトデータベース等)を利用
  • etc…

掲示板のデータをRDBMSを使って永続化する

本講義はJavaに関する講義であるが、RDBMSは知っておいた方がいい。実際、ウェブアプリ開発ではRDBMSがめちゃくちゃ使われている。

RDBMSはSQLという言語を使う。様々なRDBMSが存在するが、どれもSQLを使うので、これを知っておけばどのRDBMSでも基本的な操作はできるようになる。

Spring Bootでデータベースを使う準備

まずはRDBMSを選定しよう。今回は、組み込みで使える(アプリケーションの中に入れてしまうことができる)H2を使う。

次にJavaのプログラムからどのような方法を使ってデータベースにアクセスするかを決めよう。その方法は主に次の2つがある。

JDBCは、SQLをJavaプログラムの中で使ってデータベースを操作する方法で、JPAはO/Rマッパーというもので、Javaのインスタンスをデータベースに格納できる形に変換してデータベースにアクセスする方法(データベースにアクセスするSQLを自動生成する方法)である。

こう説明すると「JPAを使えばJavaだけでOK」と思えるかもしれないが、現状、JPAはSQLをよく知らないと使いこなすことはできない。

というわけで、本講義では、JDBCを使っていく。

build.gradleのdependenciesに下記の2行を追記して「Reload Project」を実行する。

これで、必要なファイル等が追加される。

ウェブインターフェースでデータベースに接続する

H2には、ブラウザからデータベースを操作できるインターフェースが内蔵されている。これはSpring Bootアプリケーションに組み込んだ状態でも利用することができる。

ウェブインターフェースを利用可能にするため、下記の1行をapplication.propertiesに加えよう。

bootRunで実行し、http://localhost:18080/h2-consoleにアクセスする。

h2-console

次に各設定項目を入力しよう。

  • JDBC URL: データベースの接続を表すURL。これにはどのディレクトリにデータを置くか、という情報が含まれる。今回は、ホームディレクトリに「webappdb」というディレクトリを作り、その中に「database」というファイル名で作るということを指定する。この場合、JDBC URLは「jdbc:h2:~/webappdb/database」となる(実際には「database.mv.db」等のファイルが作られる)。
  • User Name: データベースに接続する時のユーザ名を表す。今回はデフォルトのまま「sa」とする。
  • Password: データベースに接続する時のパスワードを表す。今回は「sa」とする。

入力して、Connectボタンをクリックすると、SQLの入力画面となる。

テーブルを作成する

掲示板のコメントを格納するためのテーブルを作成しよう。

次のSQL文を入力して、Runボタンをクリックするとテーブルが作成される。

「bbs_comment」はテーブル名。Javaのクラスに例えるとクラス名に相当する。

id、comment、name、dateはカラム名。Javaのクラスに例えるとフィールド名に相当する。

INT、TEXT、TIMESTAMPは型で、それぞれJavaのint、String、Dateに対応している(参考: Data Types)。

AUTO_INCREMENTは、自動的に番号をつけることを意味している。だから、保存するときにidには値を入れないで良い。保存されたときに自動的に番号がつく。PRIMARY KEYは、そのレコード(Javaでいうところのインスタンス)における「テーブルの中に保存されているデータのある1行を識別するために必要な情報」を表し、主キーという。Javaにはそういうものはないが(無理やりこじつけるとすればhashCodeかな?)、データベースではレコードを区別するためにあったほうが良い(ほとんどの場合設定するが、なくても大丈夫)。

左側に表のアイコンがついた「BBS_COMMENT」というのができれば作成成功。

テーブルにレコードを登録する

登録するには、INSERT命令を使う。

うまくいったら、「Update count: 1」と表示される。適当に値を変えて、さらにデータを入力してみよう。

テーブルからレコードを検索・取得して表示する

データの検索・取得には、SELECTを使う。先ずは全件取得してみよう。

「*」は全てのカラムの情報(ここでは、id、name、comment、date)を取得することを示す。

一部のデータを表示(検索)するには、WHERE節を追加する。

これは、nameカラムの値が「たろう」であるレコードだけが表示される。

プログラムから扱う

プログラムから扱うために、接続についての情報をapplication.propertiesに加えよう。ウェブインターフェースでデータベースに接続する時の情報と同じにする。

コントローラは次のようになる: Lect10Controller.java)。
ベースとなっているLect05Controllerと比較しながらみていこう。

18〜26行目

プログラムからJDBCを使いデータベースにアクセスするには、JdbcTemplateクラスを用いる。このクラスのインスタンスを用意し、データベースにアクセスするための各種メソッドを利用すれば良い。

この「JdbcTemplateクラスのインスタンス」をどのようにして用意すればいいだろうか?これまでと同様にnew演算子を使えばいいのだろうか?

Spring Bootの環境においては、一部のクラスは、自分でnew演算子を使ってインスタンス化するのではなくシステムにインスタンス化してもらって埋め込むという「依存性注入(dependency injection、DI)」によって行う。

JdbcTemplateクラスのインスタンスはDIで用意する。これを行なっているのが、コンストラクタである。コンストラクタに@Autowiredをつけると、引数はDIコンテナによってインスタンス化されたものが渡される。それをフィールドとして保持する。

49〜54行目

postされたデータをデータベースに登録する。

データを登録するINSERT文を実行するには、updateメソッドを利用する。

第1引数にSQL文を指定する。SQL文の中に「?」をかくと、そこには変数を埋め込むことができる。この「?」をプレースホルダ(placeholder)という。

第2引数以降はプレースホルダに対応した変数を指定する。

最後に、同一サーバの「/lect10/bbs」にリダイレクトする。

31〜44行目

データベースからデータを全件取り出して表示する。

データを取り出すSELECT文を実行するには、queryForListメソッドを利用する。このメソッドの戻り値は、レコードのListである。レコードは、カラム名がキーでデータが値となるMapの形となっている。よって、queryForListの戻り値の型は「List<Map<String, Object>>」となる。

取り出したデータからBbsCommentのインスタンスを生成し、表示用のリストに入れていく。

C言語の関数を定義できますか?

前回のまとめ等

  • if
  • for
  • ソースコードの整形(主にインデント)について
    • まともなエディタを使おう。
    • indent、astyle等の整形ツール
  • 課題の解答例

関数を定義しよう

実行例と同じになるようにプログラムを修正(関数を追加するだけで、元のコードは変更しない)して実行しよう。

BMI算出

元のプログラム: bmi.c

身長[cm]は?: 170
体重[kg]は?: 60
BMIは20.761246です。

「170」と「60」はキーボードからの入力。BMIの計算方法はBMIと適正体重(keisanサービス)が参考になる。

任意の範囲の数値の合計を求める

元のプログラム: sum.c

10から40までの数の合計は775です。

パラメータが指定できるFizzBuzz

元のプログラム: fizzbuzz.c

5の倍数のときFizz、9の倍数のときBuzzを表示するFizzBuzzを400以上500未満で実行する
Fizz 401 402 403 404 FizzBuzz 406 407 408 409 Fizz 411 412 413 Buzz Fizz 416 417 418 419 Fizz 421 422 Buzz 424 Fizz 426 427 428 429 Fizz 431 Buzz 433 434 Fizz 436 437 438 439 Fizz Buzz 442 443 444 Fizz 446 447 448 449 FizzBuzz 451 452 453 454 Fizz 456 457 458 Buzz Fizz 461 462 463 464 Fizz 466 467 Buzz 469 Fizz 471 472 473 474 Fizz 476 Buzz 478 479 Fizz 481 482 483 484 Fizz Buzz 487 488 489 Fizz 491 492 493 494 FizzBuzz 496 497 498 499

C言語でプログラムを作成、実行できますか?

プログラミングが身についているか確認しよう

実行例と同じになるようにプログラムを作成、実行しよう。

[課題1] BMI算出

身長[cm]は?: 170
体重[kg]は?: 60
BMIは20.761246です。

「170」と「60」はキーボードからの入力。BMIの計算方法はBMIと適正体重(keisanサービス)が参考になる。

[課題2] 100以上200未満の数のうち、3の倍数でないものを空白区切で表示せよ

100 101 103 104 106 107 109 110 112 113 115 116 118 119 121 122 124 125 127 128 130 131 133 134 136 137 139 140 142 143 145 146 148 149 151 152 154 155 157 158 160 161 163 164 166 167 169 170 172 173 175 176 178 179 181 182 184 185 187 188 190 191 193 194 196 197 199

[課題3] 200以上300未満でFizzBuzz、空白区切

3の倍数の時に「Fizz」、5の倍数の時に「Buzz」と表示する。ただし、3と5の両方の倍数の時には「FizzBuzz」と表示する。3もしくは5の倍数でない時にはその数字を表示する。

Buzz Fizz 202 203 Fizz Buzz 206 Fizz 208 209 FizzBuzz 211 212 Fizz 214 Buzz Fizz 217 218 Fizz Buzz 221 Fizz 223 224 FizzBuzz 226 227 Fizz 229 Buzz Fizz 232 233 Fizz Buzz 236 Fizz 238 239 FizzBuzz 241 242 Fizz 244 Buzz Fizz 247 248 Fizz Buzz 251 Fizz 253 254 FizzBuzz 256 257 Fizz 259 Buzz Fizz 262 263 Fizz Buzz 266 Fizz 268 269 FizzBuzz 271 272 Fizz 274 Buzz Fizz 277 278 Fizz Buzz 281 Fizz 283 284 FizzBuzz 286 287 Fizz 289 Buzz Fizz 292 293 Fizz Buzz 296 Fizz 298 299

詳細はFizz Buzz (Wikipedia)を参照。

その他

プログラムを作ってみよう。

Map(コレクション)の基礎

前回のまとめ

  • 「コレクション」とはデータの集合のこと。Javaではコレクションを扱うためのコレクションフレームワークが標準で含まれている。
  • Listは順序性があるコレクション
  • 教科書: P.178, P.190-200
  • サンプル
  • Thymeleafで繰り返し処理はth:eachを使う。Javaの拡張for文のようなものと思えば良い。

Spring Boot 2.0.2

Spring Boot 2.0.2がリリースされた。
自分のプロジェクトもupdateしよう。build.gradleを書き換えればよい。


JavaのMapの基礎

英和辞書を作ろう

ポイント:

  • テンプレート:
    • 共通部分はth:fragmentで定義し、th:include等で呼び出すことができる。Thymeleaf 3からはth:includeは非推奨とのことなので、th:insertかth:replaceを使おう。
    • th:ifを使うと条件によって表示することができる。
  • コントローラ:
    • 辞書を表すマップをコントローラのフィールドとして作る。インスタンス化が必要なことに注意する。
    • マップにキーと値を追加する(27行目)。
    • マップから値を取得する(38行目)。

List(コレクション)の基礎

前回のまとめ

前回の「ポイント」を再掲

  • テンプレート:
    • form要素の内側でinput要素を使う。
    • form要素のaction属性で値をどこにリクエストするか指定する。
    • form要素のmethod属性の違い: getはフォームの値がURLに含まれる。postはURLに含まれない(リクエストボディに記述される)
    • input要素のtype属性で種類が指定できる: textはテキストフォーム、submitは送信ボタン。
    • input要素の区別はname属性で行う。
  • コントローラ(主に14〜26行目):
    • フォームからの値を受け取るには、メソッドに引数を加え、@RequestParamアノテーションをつける。
    • @RequestMappingアノテーションはgetでもpostでも動作する。

JavaのListの基礎

掲示板を作る

コメントだけの掲示板

ポイント:

  • テンプレート:
  • コントローラ(主に16〜51行目):
    • コメント(文字列)を格納するリストをコントローラのフィールドとして作る。インスタンス化が必要なことに注意する。
    • リストにコメントを追加する(48行目)。
    • 「コメントを追加しました。」のページが必要なければ、リダイレクトさせることができる(49行目をコメントにして、50行目のコメントを外す)。

名前と投稿時刻を加えた掲示板


予習

Javaのコレクション(特に下記)調べよう。

  • Mapを使いたい(教科書P.215)
  • Mapに要素を追加したい(教科書P.218)
  • Mapの値を取得したい(教科書P.221)

フォームの基礎

前回のまとめ

  • @ResponseBodyアノテーションをつけない場合はテンプレートエンジンを使う設定なる。
  • 使うテンプレートはメソッドの戻り値で指定する。
  • テンプレートに値を渡すには、ModelMapクラスを使う。
  • テンプレートで文字列を埋め込むには、要素(タグ)の属性として「th:text=”${モデルの名前}”」を指定する。

フォームを使う

「BMIの計算」を例として、「ブラウザから何か入力して、サーバで処理を行い、結果をブラウザで表示する」ということを行ってみよう。サーバに何か送るにはフォーム(HTMLのformタグとその関連タグ)を使う。

処理の流れを次のシーケンス図に示す。

sequence

テンプレートとコントローラを作成しよう。

ポイント:

  • テンプレート:
    • form要素の内側でinput要素を使う。
    • form要素のaction属性で値をどこにリクエストするか指定する。
    • form要素のmethod属性の違い: getはフォームの値がURLに含まれる。postはURLに含まれない(リクエストボディに記述される)
    • input要素のtype属性で種類が指定できる: textはテキストフォーム、submitは送信ボタン。
    • input要素の区別はname属性で行う。
  • コントローラ(主に14〜26行目):
    • フォームからの値を受け取るには、メソッドに引数を加え、@RequestParamアノテーションをつける。
    • @RequestMappingアノテーションはgetでもpostでも動作する。

formt要素のaction属性を書かない場合は、同じURLにリクエストを送ることになる。action属性を使わない例は次のようになる。

ポイント:

  • テンプレート:
    • form要素のaction属性を書かない場合は同じURLにリクエストする。
  • コントローラ(主に28〜40行目):
    • @GetMappingアノテーションはgetだけで動作し、@PostMappingアノテーションはpostだけで動作する。
    • @GetMappingアノテーションと@PostMappingアノテーションで同じパスを指定することができる。

復習

テンプレートを使う

前回のまとめ

  • Spring BootのアプリケーションはSPRING INITIALIZRでプロジェクトの雛形を作成することができる。
  • @Controllerアノテーション: クラスに付与するアノテーションで、そのクラスがコントローラであることを示す。「コントローラとは何か」は今回解説する。
  • @RequestMappingアノテーション: アクセス先のパス(URLの後ろ側)を表す。クラスとメソッドにそれぞれつけることができ、結合したものが最終的なパスを表す。
  • @ResponseBodyアノテーション: メソッドに付与するアノテーションで、戻り値をそのままブラウザに返すことを表す。
  • サーバのポート番号はデフォルトで8080だが、application.propertiesファイルに設定を記述することで変えることができる。

初学者のためのFAQ

 

  • Q: これまでクラスを作った(書いた、定義した)ら、new演算子でインスタンス化しないと使えなかったけど、コントローラのインスタンス化は?

    A: フレームワークがインスタンス化してくれる。フレームワークとは「全体の処理・流れ定義(実装)されており、その中の一部に自分のコードを組み込んでいくシステム」のこと。わかりやすい解説としてSoftware frameworkソフトウエアのフレームワークとはなにか等。


テンプレートを使う

前回は、文字をブラウザに表示したが、これでは表現力がなさすぎる。HTMLで表示するようにしてみよう。もちろん、コントローラからHTMLで出力するようにしてもいいが、ものすごく大変なので、テンプレートを用意しそこに文字をはめ込んで表示するようにしよう。

Spring Web MVC framework

これから作るウェブアプリケーションはSpringのWeb MVCフレームワークを利用している。このフレームワークにおける処理の流れを次の図に示す(http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-servletより引用)。

Mvc

フロントコントローラがリクエストを適切なコントローラに渡し、コントローラが出力するデータをビュー(テンプレート)が表示するという仕組みだ。このうち、自分で作るのは、「コントローラ」と「ビューテンプレート」である。コントローラからビューに「モデル(要するにデータ)」を渡すことによって表示内容を動的に(つまりメソッド実行時に)変えることができる。

テンプレートエンジン(テンプレートに関する処理を行うソフトウェア)は、前回、SPRING INITIALIZRでプロジェクト作成時に指定したThymeleafが使われる。

コントローラ

テンプレートを利用するコントローラを作成しよう。

前回との違い:

  • メソッドに@ResponseBodyがつかなくなること。これによりメソッドのreturnで指定した文字列がブラウザに直接送られるのではなく、テンプレートを使うようになる。メソッドのreturnで指定する文字列は「どのテンプレートを使うか」を指定するために使う。
  • テンプレートに値を渡すには、ModelMapクラスを使う。メソッド引数としてModelMapを指定すると使えるようになる(フレームワークがテンプレートに引き渡すためのインスタンスを作ってくれる)。ModelMapのaddAttributeメソッドでテンプレートに渡すモデルの「名前」と「値」を指定する。

テンプレート

テンプレートを置く場所(基点)はResourcesのtemplatesだ。コントローラで「lect02/hello」とした場合、templatesの中にlect02というディレクトリを作り、その中にhello.htmlというファイルを作る。

NetBeansのパッケージの表示の仕方によっては、作業が難しい。プロジェクトウィンドウの背景部分を右クリックし、「Javaパッケージの表示方法」を「ツリー」にすると階層構造がわかりやすい。または、プロジェクト表示ではなく、ファイル表示にするとわかりやすい。

templates

コントローラでは3つのテンプレートを指定している。それぞれ作成しよう。

ポイント

  • 単に表示をするだけの場合は素のHTMLで良い。Thymeleafの機能を使う場合は「th:」から始まる要素(タグ)や属性を使う。
  • htmlタグの属性に追加した「xmlns:th=”http://www.thymeleaf.org”」は名前空間の指定。最近のThymeleafならなくても動くが、つけておいたほうが良い。
  • 文字列を埋め込む場合は、要素(タグ)の属性として「th:text=”${モデルの名前}」を指定する。子ノード(要するにタグに挟まれたところ)がモデルの値で置き換わる。他にも指定方法がある。counter.htmlにいくつか例を示す。

実行・確認

実行して、確認しよう。

どのようなHTMLが出力されているかはChromeのデベロッパーツール等を使うと良い。


復習