SpringBoot2チートシート

#はじめに
　Springを業務で使う筆者が、「[SpringBoot2 プログラミング入門](https://www.amazon.co.jp/Spring-Boot-2-プログラミング入門-掌田津耶乃/dp/4798053473)」を勉強して、まとめたチートシート・読書メモのようなもの。
　対象読者は、Javaの基礎が身についていて、SpringBoot未経験者〜基礎を勉強し始めた位の層。
　言語はJava、
　ビルドツールはMaven、
　テンプレートエンジンはThymeleafです。

#SpringBootとは
　SpringFrameworkの提供するライブラリとSpringMVC（フレームワーク）を高速なWEBアプリ開発向けに組み合わせてできたフレームワーク（群）
#１． Spring開発のセットアップ
　本記事をチートシート的用途とするため、ここでは割愛。
#２． Groovyによる超簡単アプリケーション開発
　GroovyはJavaでの本格的な開発前にプロトタイプを短時間で作ることに向いている言語。Groovyについてはここでは割愛。
###@ RestController
　外部からアクセスして必要な情報などを取り出すシステムを構築するのに用いられる。
アクセスしたら必要な情報などをテキストやXML形式で送り返すといった用途。
###@ RequestMapping
　このアドレスにアクセスされたらこのメソッドを実行するといった意味。
`@RequestMapping("/")`のように表記し、引数にパスを指定する。
指定パスにアクセスしたらこのアノテーションがつけられたメソッドが実行されるようになる。

```java:SampleController.java
@RestController
public class SampleController {

  @RequestMapping("/")
  public String index() {
    return "Hello SpringBoot World";
  }
}
```
##　Thymeleafを利用する
　HTMLのタグに、追記して使うことができるテンプレートエンジン。
特徴は、

- タグの中に「th:◯◯」の独自属性を用意
- 「${}」の形をとって変数名を記述して、その場所に値を埋め込む

```html:home.html
<body>
  <h1>Hello!</h1>
  <p class="msg" th:text="${msg}">this is sample.</p>
</body>
```
テンプレートエンジンとしてのGroovyでHTMLを書くことも可能だが、用途の都合上ここでは割愛。

[@Controllerについては、3章に記載](#-controller)
###@ ResponseBody
`@ResponseBody`をつけたメソッドは戻り値がそのままレスポンスのコンテンツになる。
`@RestController`をつけたコントローラーのメソッドは、`@ResponseBody`を付けなくても、戻り値がコンテンツになる。
`@Controller`がついたコントローラークラス内のメソッドでは、ModelAndViewクラスを返すことが多いが、例外的に、JSONやXMLを返す必要があるときに、`@ResponseBody`をコントローラーに付けることで、コンテンツそのものを返すことができる。
#３． JavaによるSpringBoot開発の基本
##SpringBootアプリケーションの仕組み
　SpringBootは内蔵されているJavaサーバーを使ってアプリを実行するので、デプロイが不要。
　クラウドサービスのような、サーバー内でプログラムを実行するものに相性がいい。
　　ファイルサイズが肥大化するデメリットもあるが、JavaでWeb開発を行うデファクトスタンダードになりつつある。
##Spring Starter Projectのpom.xml
parentの定義は以下

```
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.3.0.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>
```
dependenciesの定義は以下

```
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>      
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>
```
buildおよびpluginの定義は以下

```
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>
```
##RestControllerを利用する
Spring Tool Suite(以下、STS)でSpringStarterプロジェクトを作成すると、デフォルトで`MyBootAppApplication.java`というファイルが作成される。
　@ SpringBootApplicationをつけると、SpringBootの起動時に呼び出されるクラスになる。
　アノテーションをつけたクラスをSpringApplication.runすると、アプリが起動する。
　「run」はアプリケーションを起動するためのメソッド。引数には、実行するクラスのClassインスタンスと、パラメータとして渡すデータを用意する。

```java:MyBootAppApplication.java
@SpringBootApplication
public class MyBootAppApplication {

  public static void main(String[] args) {
    SpringApplication.run(MyBootAppApplication.class, args);
  }
}
```
###MVCアーキテクチャについて
|アーキテクチャ|役割|
|:--|:--|
|Model|アプリケーションで使うデータを管理する|
|View|画面の表示を扱う|
|Controller|全体の処理の制御を行う|

###パラメータを渡す
`@RequestMapping("/{param}")`の形でパス変数を利用することで、アドレス以下のパス部分に渡された値を変数として受け取ることができる
[@RequestMappingとは](#-requestmapping)

###パス変数と@ PathVariable
　パス変数によって値が渡されるものであることを示す。

```java
@RequestMapping("/{num}")
public String index(@PathVariable int num){
  int res = 0;
  for(int i = 1; i<= num; i++){
    res += i;
  }
  return "total:" + res;
}
```


###オブジェクトをJSONで出力する
RESTのサービスはString以外の戻り値として、クラスを戻すこともできる。returnされたインスタンスは、JSON形式に変換される。

```java
//DataObjectクラスを別途定義しておく
public DataObject index(@PathVariable int id) {
  return new DataObject();
}
```

##ControllerによるWebページ制作
　通常のWebページを利用する場合は、コントローラークラスの前に`@Controller`を付ける。
本記事においては、テンプレートにThymeleafを使用したいので、以下のようにして、依存関係をpom.xmlに追加する。

```
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
```
###@ Controller
　テンプレートを利用してHTMLページをレンダリングし、表示するのに用いられる。

```java:SampleController.java
@Controller
public class SampleController {
  @RequestMapping("/")
  public String home(){
    return "home";
  }
}
```
###Modelクラスの利用
　`Model`はWebページで利用するデータを管理するためにクラス。
この`Model`にテンプレートで利用する値を設定しておくことで、データを渡すことができる。
`addAttribute`で値を設定する。第1引数には値の名前を、第2引数には補完する値をそれぞれ指定する。
以下のサンプルに倣うと、テンプレート側で`${msg}`という形で変数msgの値を取り出すことができる。
戻り値を`Model`として使うことができない（テンプレートの情報を持っていないから）。

```java
@RequestMapping("/{num}")
public String home(@PathVariable int num, Model model) {
  ...
  model.addAttribute("msg", "total:" + res);
  return "home";
}
```
###ModelAndViewクラスの利用
　テンプレートで利用するデータ類と、ビューに関する情報（テンプレート名など）を管理する。この`ModelAndView`を戻り値として返すことで設定されたテンプレートを利用するようになる。オブジェクトを`addObject(String entitySetName, Object entity)`というように設定し、使用するビューの名前を`setViewName(String viewName)`で設定する。

```java
@RequestMapping("/{num}")
public ModelAndView index(@PathVariable int num, ModelAndView mav) {
  ...
  mav.addObject("msg",  "total:" + res);
  mav.setViewName("home");
  return mav;
}
```
- `Model`
　テンプレートで利用するデータ類をまとめて管理するものであるが、ビュー関連の情報は持っていないので、`Model`を戻り値として使うことはできない。

- `ModelAndView`
 テンプレートで利用するデータ類と、ビューに関する情報をすべてまとめて管理する。`ModelAndView`を戻り値として返すことで設定されたテンプレートを利用するようになる。

　
###フォームを利用する
　`<form method="POST" action="/">`でフォームを用意、送信先は同じ`"/"`で、POST送信する。`input type="text"`タグでは、`th:text="${value}"`のようにして、$valueの値を入力フィールドに表示させている。
　`@RequestMapping(value="/", method=RequestMethod.POST)`のように`@RequestMapping`の引数が複数ある場合は、マッピング先を`value="/"`のように引数名を省略せずに書く必要がある。サンプルは同じアドレスで、メソッドについて`GET`と`POST`で区別している。
　フォームから送信された値は、sendメソッドで処理している。`@RequestParam`は、フォーム送信された値を指定するためのアノテーションで、これによってフォームの`name="text1"`に入力された値がこの引数`str`に渡される。

【コンロトーラー側】

```java:SampleController.java
@Controller
public class SampleController {
  @RequestMapping(value="/", method=RequestMethod.GET)
  public ModelAndView index(ModelAndView mav) {
    mav.setViewName("form");
    mav.addObject("msg", "please put and send your name.");
    return mav;
  }

  @RequestMapping(value="/", method=RequestMethod.POST)
  public ModelAndView send(@RequestParam("text1")String str, ModelAndView mav) {
    mav.addObject("msg", "こんにちは");
    mav.addObject("value", "message");
    mav.setViewName("form");
    return mav;
}
```
【テンプレート側】

```html:form.html

<body>
    <h1>Sample Form</h1>
    <p th:text ="${msg}">ここはmsgと置き換わる</p>
    <form method="POST" action="/">
        <input type="text" name="text1" th:value="${value}"/>
        <input type="submit" value="Click" />
    </form>
</body>
```
###その他フォームコントロールテンプレート例
　フォームから送信された値は`send`メソッドで受け取っている。メソッドにはフォームからの値を受け取れるように、`@RequestParam`をつけた引数が4つ用意されている。`value`でパラメータの名前を指定し、`required`で値のnull制約を指定する。
【コントローラー側】

```java:SampleController.java
@Controller
public class SampleController {
    @RequestMapping(value="/", method=RequestMethod.GET)
    public ModelAndView index(ModelAndView mav) {
    //GETリクエスト省略
    }
  
    @RequestMapping(value="/", method=RequestMethod.POST)
    public ModelAndView send(
        //チェックボックス：値は選択状態をboolean値として得ることができる
        @RequestParam(value="check1", required=false)boolean check1,
        //ラジオボタン：選択した項目のvalueをString値として渡すが未選択の場合はnull
        @RequestParam(value="radio1",required=false)String radio1,
        //選択リスト：単一項目の選択時はvalueをString値として渡すが、複数項目が選択できる場合はString配列として渡し、未選択の場合null
        @RequestParam(value="select1", required=false)String select1,
        @RequestParam(value="select2", required=false)String[] select2, 
        ModelAndView mav) {
      String res = "";
      //処理省略
      ...
      //resをmsgに埋め込む
      mav.addObject("msg", res);
      mav.setViewName("form");
      return mav;
    }
}

```

【テンプレート側】

```html
<body>
    <h1>Form Controll Example</h1>
    <form method="POST" action="/">
        <div>
        <input type="checkbox" id="check1" name="check1" />
        <label for="check1">チェックボックス</label>
        </div>
        <div>
        <input type="radio" id="radioA" name="radio1" value="male" />
        <label for="radioA">男性</label>
        </div>
        <div>
        <input type="radio" id="radioB" name="radio1" value="female" />
        <label for="radioB">女性</label>
        </div>
        <div>
        <select id="select1" name="select1" size="4">
            <option value="Red">赤</option>
            <option value="Blue">青</option>
            <option value="Yellow">黄</option>
        </select>
        <select id="select2" name="select2" size="4" multiple="multiple">
            <option value="SmartPhone">スマホ</option>
            <option value="Tablet">タブレット</option>
            <option value="Laptop">ラップトップ</option>
        </select>
        </div>
        <input type="submit" value="Click" />
    </form>
</body>
```
###リダイレクト
　あるアドレスにアクセスしたとき、必要に応じて別のアドレスに移動させたいケースのやり方として**フォワード**と**リダイレクト**がある。

+ **フォワード**：サーバー内部で別のページを読み込み、表示する。アクセスするアドレスはそのままで、表示内容だけが別のページに差し替えられる。
+ **リダイレクト**：クライアント側に送られた後で別のページに移動させる。なのでアクセスしているアドレスも移動先のものに変更される。

【コントローラー側】

```java:SampleController.java
@Controller
public class SampleController {
    @RequestMapping("/")
    public ModelAndView index(ModelAndView mav) {
        mav.setViewName("home");
        return mav;
    }
    //"/other"はアドレス自体が、"/"に変更されて、表示内容も"/"のものになる。 
    @RequestMapping("/other")
    public String other() {
        return "redirect:/";
    }
    //"/home"にアクセスすると、アドレスはそのままに、表示内容が"/"のものを見せる。
    @RequestMapping("/home")
    public String home() {
        return "forward:/";
    }
}
```

【テンプレート側】

```html:home.html
<body>
  <h1>Home Page</h1>
</body>
```



#４． テンプレートエンジンを使いこなす
##Thymeleafいろいろ
###ユーティリティオブジェクト
　よく使われるクラスを「**#名前**」という定数として定数式の中に直接記述して利用できる。クラスの定数なので、直接クラスメソッドなどを呼び出して利用することができる。「#dates.クラスメソッド」というように。以下例

|ユーティリティオブジェクト|定数|
|:--|:--|
|#strings|Stringクラスの定数|
|#numbers|Numberクラスの定数|
|#Bools|Booleanクラスの定数|
|#dates|Dateクラスの定数|
|#objects|Objectクラスの定数|
|#arrays|Arrayクラスの定数|
|#lists|Listクラスの定数|
|#sets|Setクラスの定数|
|#maps|Mapクラスの定数|

Dateクラス定数`#dates`の`format`メソッドを使い、第1引数にDateクラスのオブジェクトを作成し、第2引数で`yyyy/MM/dd HH:mm:ss`という形式を指定。

```html
    <p th:text="${#dates.format(new java.util.Date(), 'dd/MMM/yyyy HH:mm')}"></p>
```
Numberクラスの定数`#numbers`の`formatInteger`メソッドを使い、第1引数に整数を、第2引数の桁表示で、第3引数でカンマ区切りにしている

```html
    <p th:text="${#numbers.formatInteger(10000000, 3, 'COMMA')}"></p>
```
Stringクラスの定数`#strings`の`toUpperCase`は引数のテキストをすべて大文字に変換するメソッド

```html
    <p th:text="${#strings.toUpperCase('show uppercase')}"></p>
```
###パラメータへのアクセス
`{param.id}`のように書くことで、「id=○○」のような形で送られてきた値を受け取り、コントローラー通さず、直接テンプレート内でパラメータを利用することができる。ただし、得られる値は配列なので、値を取り出して使う。

```html
<!--/?id=hoge&name=fugaのようにして渡す-->
<p th:text="'from parameter.. id=' + ${param.id[0] + ',name=' + param.name[0]}"></p>
```
##メッセージ式
プロパティファイルから値を取り出し、テンプレート内で利用する。記述方法は、`#{値の指定}`

```message.properties
article.title=this is home page.
article.message=this message from properties.
```
```html
<h1 th:text="#{article.title}"></h1>
<p th:text="#{article.message}"></p>
```
###リンク式とhref
`/?id=fuga`とアクセスすると、linkには**/hoge/fuga**が設定される。

```html
<p><a href="home.html" th:href="@{/hoge/{id}(id=${param.id})}">link</a></p>
```

###選択オブジェクトへの変数式
変数式は、数値やテキストだけでなく、オブジェクトを利用することができる。やり方としては、オブジェクトを指定し、選択されたオブジェクト内の値を取り出すため`*{value}`を使う。

```html
  <table th:object="${object}">
    <tr><th>ID</th><td th:text="*{id}"></td></tr>
    <tr><th>NAME</th><td th:text="*{name}"></td></tr>
    <tr><th>MAIL</th><td th:text="*{value}"></td></tr>
  </table>
```

###リテラル置換
　テキストの前後を「|」で囲むと、変数式を直接書き込んで文字列結合ができる。

```html
<p th:text="|My name is *{name}. Mailaddress is *{value}.|"></p>
```

###HTMLコードの出力
　Thymeleafでは、変数式でテキストを出力する際、安全のためにHTMLタグを全てエスケープするので、
`th:utext`を使うことで、エスケープを解除できる。ただし、値にHTMLタグが含まれているとそれがそのまま機能してしまうので、ユーザーから送信された情報を元にテキストを作成する場合、XSSなどの攻撃に対して無防備になってしまう。

【コントローラー側】

```java
@RequestMapping("/")
public ModelAndView index(ModelAndView mav) {
    mav.setViewName("home");
    mav.addObject("msg", "message 1<hr/>message 2<br/>message3");
    return mav;
} 
```
【テンプレート側】

```html
<p th:utext="${msg}">message.</p>
```
##構文・インライン・レイアウト
###条件式

* 三項演算子(条件文 ? 値1 : 値2)

　予め用意した真偽値の結果に応じて出力する内容を変更する。

【コントローラー側】

```java
@RequestMapping("/{id}")
public ModelAndView index(@PathVariable int id,
		ModelAndView mav) {
	mav.setViewName("check");
	mav.addObject("id",id);
	mav.addObject("num",id % 2 == 0);
	mav.addObject("even","Even number!");
	mav.addObject("odd","Odd number...");
	return mav;
}
```

【テンプレート側】

```html:check.html
<p th:class="${num} ? 'even' : 'odd'"></p>
```

* th:if

　値として設定したものが`true`（ゼロ以外の数値、"0",
"off",　"no"といった値以外のテキストも含む）の場合に、このタグ及びその内部にあるタグを表示する。

* th:unless

値として設定されたものが`false`（数値のゼロ、"0", "off", "no"といったテキストも含む）の場合に、このタグ及び内部のタグを表示する。

【コントローラー側】

```java
@RequestMapping("/{id}")
public ModelAndView index(@PathVariable int id,
		ModelAndView mav) {
	mav.setViewName("check");
	mav.addObject("id",id);
	mav.addObject("num",id >= 0);
	mav.addObject("trueVal","POSITIVE!");
	mav.addObject("falseVal","negative...");
	return mav;
}
```

【テンプレート側】

```html:check.html
	<p th:if="${num}" th:text="${id} + ' is ' + ${trueVal}"></p>
	<p th:unless="${num}" th:text="${id} + ' is ' + ${falseVal}"></p>
```

* th:switch

　指定された条件式の値をチェックし、その内側にある`th:case`から同じ値のものを探してそのタグだけを出力する。
　`th:case="*"`はワイルドカードで、どの条件にも当てはまらなかったものをキャッチする。

【コントローラー側】

```java
@RequestMapping("/{month}")
public ModelAndView index(@PathVariable int month,
		ModelAndView mav) {
	mav.setViewName("index");
	int m = Math.abs(month) % 12;
	m = m == 0 ? 12 : m;
	mav.addObject("month",m);
	mav.addObject("check",Math.floor(m / 3));
	return mav;
}
```

【テンプレート側】

```html
<div th:switch="${check}">
    <p th:case="0" th:text="|${month} - Winter|"></p>
    <p th:case="1" th:text="|${month} - Spring|"></p>
    <p th:case="2" th:text="|${month} - Summer|"></p>
    <p th:case="3" th:text="|${month} - Autumn|"></p>
    <p th:case="4" th:text="|${month} - Winter|"></p>
    <p th:case="*">...?</p>
</div>
```

* th:each

　`th:each`では、配列やコレクションなどを値として用意し、`value : ${list}`のように拡張for文の要領で記述する。これにより、コロンのあとにあるリストから順に値を取り出して、コロンの前の変数に代入するようになる。

【テンプレート側】

```html
<table>
    <tr>
        <th>NAME</th>
        <th>MAIL</th>
        <th>TEL</th>
    </tr>
    <tr th:each="obj:${data}">
        <td th:text="${obj[0]}"></td>
        <td th:text="${obj[1]}"></td>
        <td th:text="${obj[2]}"></td>
    </tr>
</table>
```

###プリプロセッシング

　`__${変数}__`の形で宣言すると、事前に評価され、変数式が実行されるようになる。

【コントローラー側】

```java
ArrayList<Pockemon> monsters = new ArrayList<>();
monsters.add(new Pockemon(0,"Hitokage","Fire"));
monsters.add(new Pockemon(1,"Fushigidane","Grass"));
monsters.add(new Pockemon(2,"Zenigame","Water"));
mav.addObject("num", 1);
mav.addObject("monsters",monsters);
return mav
```

【テンプレート側】

```html
<div th:object="${monsters.get(${num})}">
    <p th:text="*{id}"></p>
</div>
```

###インライン処理

`th:text`のような属性の形で用意しなくても（Thymeleafが機能していなくてもページ表示に影響を与えないようにしている面あり）、HTMLタグとタグの間に直接Thymeleafの変数式を書き込むことができる。タグに`th:inline="text"`のように記述するとその内部で`[[${変数}]]`のように変数式を書くことで、インライン処理が可能になる。

【コントローラー側】

```java
ArrayList<Pockemon> monsters = new ArrayList<>();
monsters.add(new Pockemon(0,"Hitokage","Fire"));
monsters.add(new Pockemon(1,"Fushigidane","Grass"));
monsters.add(new Pockemon(2,"Zenigame","Water"));
mav.addObject("monsters",monsters);
return mav
```

【テンプレート側】

```html
<tr th:inline="text" th:each="monster : ${monsters}">
    <td>[[${monster.id}]]</td>
    <td>[[${monster.name}]]</td>
    <td>[[${monster.type}]]</td>
</tr>
```

###JavaScriptによるインライン処理

`<script th:inline="javascript">`と`inline`に`"text"`ではなく`"javascript"`と値を指定し、変数式は、`/*[[${変数式}]]*/`とコメントアウト形で記述することで、スクリプトの中に埋め込んで利用することができる。

```html:
<script th:inline="javascript">
   console.log(/*[[$(変数)]]*/);   
</script>
```
###テンプレートフラグメント
　複数のファイルを組み合わせてページを構成する**テンプレートフラグメント**というやり方。ファイルの中に**フラグメント**としてそこだけ切り取って扱えるようにした部品として記述されている部分を別のテンプレートの指定した場所にはめ込む。

【部品となるテンプレート】

```html:part.html
<p th:fragment="frag_body">
```

【組み込む側】

```html
<p th:include="part::frag_body">
```
##そのほかのテンプレートエンジン
SpringにおいてはJSP, Groovyもテンプレートエンジンとして使用できるが都合上割愛

#５． モデルとデータベース
　JavaではJPA（JavaPersistence API 永続化のためのAPI）を使ってDBを利用する。SpringにおいてもSpringBootStarterDataJPAを利用してDBアクセスを行う。

Mavenでプロジェクトを管理している場合、pom.xmlに、以下のdependencyを追加して使用する。

```xml
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
```

JPAを利用する場合、データとなる部分は**エンティティ**と呼ばれるクラスとして定義される。DB内にテーブルを定義して、そこにレコードとしてデータを保管していくが、エンティティはこの一つ一つのレコードをJavaオブジェクトとして保管したものと考えていい。

以下、モデルとなる**Entity**クラスのサンプル

```java
@Entity
@Table(name="mydata")
public class MyData {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	private long usrId;
	@Column(length = 50, nullable = false)
	private String usrName;
	@Column(length = 200, nullable = true)
	private String usrAddress;
	@Column(nullable = true)
	private Integer age;
	@Column(nullable = true)
	private String comment;

	public long getUsrId() { return usrId; }
    public void setUsrId(long usrId) { this.usrId = usrId; }
    
	public String getUsrName() { return usrName; }
    public void setUsrName(String usrName) { this.usrName = usrName; }
    
    public String getUsrAddress() { return usrAddress; }
    public void setUsrAddress(String usrAddress) { this.usrAddress = usrAddress; }
    
	public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
	public String getComment() { return comment; }
	public void setComment(String comment) { this.comment = comment; }
}
```
###@ Entity
　エンティティクラスであることを示すアノテーション
###@ Table(name="mydata")
　このエンティティクラスに割り当てられるテーブルを指定する。`name`を省略した場合、クラス名がテーブル名として利用される。
###@ Id
　プライマリキーの指定
###@ GeneratedValue(strategy = GenerationType.AUTO)
　プライマリキーのフィールドに対して値を自動生成する。`strategy`に生成方法を指定し、サンプルでは`GenerationType.AUTO`と列挙型の値を自動的に割り振るように指定している。
###@ Column
　フィールドに割り当てられるカラム名を指定。`name`を省略した場合、フィールド名がそのままカラム名と利用される。

|@ Colomnの引数|説明|
|:--|:--|
|name|カラム名の指定|
|length|最大の長さ(Stringでは文字数)を指定|
|nullable|nullを許可するかどうかの指定|

##リポジトリについて
エンティティ -> テーブルに保管されるデータをJava内でオブジェクトとして扱えるようにするためのクラス
リポジトリ -> インターフェースとして用意、汎用的なDBアクセスの処理を自動的に生成して実装するのでほとんどコードを書く必要がない。

JpaRepositoryを継承して作成される
###@ Repository
　このクラスがデータアクセスのクラスであることを示す。

```java
@Repository
public interface MyDataRepository extends JpaRepository<MyData, Long> {

}
```
###@ Autowired
サンプルでは、`@Autowired`でMyDataRepositoryインスタンスをフィールドにインジェクションしている。
インスタンス変数の前に`@Autowired`をつけると、`@Component`のついたクラスの中から該当するものを探し、newしてフィールドに突っ込んでくれる。`@Component`とあるがレイヤによって、`@Controller`,`@Repository`,`@Service`が使い分けられる。

###findAllメソッド
継承元である、JpaRepositoryに用意されているメソッドでこれによってエンティティが全て自動的に取り出すことができる。

```java
@Controller
public class SampleController {

  @Autowired
  MyDataRepository repository;

  @RequestMapping("/")
  public ModelAndView home(ModelAndView mav) {
    mav.setViewName("home");
    Iterable<MyData> list = repository.findAll();
    mav.addObject("data", list);
    return mav;
  }
}
```

##エンティティのCRUD
　「Create」「Read」「Update」「Delete」
###@ ModelAttribute
　エンティティクラスのインスタンスを自動的に用意するのに用いられる。引数には、インスタンスの名前を指定。
　　GETアクセスの際のindexメソッドでは、MyDataの引数にはnewされたインスタンスが作成されて、割り当てられる（値などは全て初期値）
　POSTアクセスで呼ばれるformメソッドでは、送信されたフォームの値が自動的にMyDataインスタンスにまとめられて渡される。

###SaveAndFlushによる保存
`repository.saveAndFlush(mydata);`

用意されたエンティティは、JpaRepositoryに用意されている`saveAndFlush`メソッドの引数に指定されて、永続化される。
###@ Transactional
`@Transactional`アノテーションは、トランザクション機能のためのもので、これをメソッドにつけることで、メソッド内で実行されるDBアクセスが一括して実行されるようになる。
　データの書き換えを行うような処理の場合に、途中で外部からDBがアクセスされてデータの整合性に問題を生じさせないようにするなどトランザクションは重要な処理。

引数の`readOnly=false`は文字通り、「読み込みのみ（書き換え不可）」であることを示す。
`readOnly=false`とすると読み込みのみのトランザクションから保存などデータの更新を許可するトランザクションに変わる。

```java:SampleController.java
@Controller
public class SampleController {
  @Autowired
  MyDataRepository repository;

  @RequestMapping(value = "/", method = RequestMethod.GET)
  public ModelAndView index(@ModelAttribute("formModel") MyData mydata,
      ModelAndView mav) {
    mav.setViewName("index");
    mav.addObject("msg", "this is sample content.");
    Iterable<MyData> list = repository.findAll();
    mav.addObject("datalist", list);
  }

  @RequestMapping(value = "/", method = RequestMethod.POST)
  @Transactional(readonly = false)
  public ModelAndView form(@ModelAttribute("formModel") MyData mydata,
      ModelAndView mav){
    repository.saveAndFlush(mydata);
    return new ModelAndView("redirect:/");        
  }
}
```

```html
<body>
  <table>
  <form method="post" action="/" th:object="${formModel}">
    <tr>
      <td><label for="name>名前</label></td>
      <td><input type="text" name="name" th:value="*{name}" /></td>
    </tr>
    <tr>
      <td><label for="name>年齢</label></td>
      <td><input type="text" name="age" th:value="*{age}" /></td>
    </tr>
    <tr>
      <td><label for="name>メール</label></td>
      <td><input type="text" name="mail" th:value="*{mail}" /></td>
    </tr>
    <tr>
      <td><label for="name>メモ</label></td>
      <td><textarea name="memo" th:value="*{memo}" cols="20" rows="5"></textarea></td>
    </tr>
  </form>
  </table>
  <hr/>
  <table>
    <tr>
      <th>ID</th>
      <th>名前</th>
    </tr>
    <tr th:each="obj : ${datalist}">
      <td>${obj.id}</td>
      <td>${obj.name}</td>
    </tr>
  <table>
</body>
```
###@ PostConstruct
　コンストラクタによりインスタンスが生成された後に呼び出されるメソッドであることを示す。コントローラーは最初に一度だけインスタンスが作成され、以降はそのインスタンスが保持される。

```java:SampleComtroller.java
@PostConstruct
public void init(){
	MyData d1 = new MyData();
	d1.setName("tuyano");
	d1.setAge(123);
	d1.setMail("syoda@tuyano.com");
	d1.setMemo("this is my data!");
	repository.saveAndFlush(d1);
	MyData d2 = new MyData();
	d2.setName("hanako");
	d2.setAge(15);
	d2.setMail("hanako@flower");
	d2.setMemo("my girl friend.");
	repository.saveAndFlush(d2);
	MyData d3 = new MyData();
	d3.setName("sachiko");
	d3.setAge(37);
	d3.setMail("sachico@happy");
	d3.setMemo("my work friend...");
	repository.saveAndFlush(d3);
}
```
###Dataの更新
【テンプレート】
`<form>`には`th:object="${formModel}"`が指定されているが、この`formModel`に編集するエンティティが設定されていれば、`type="hidden"`によってそのIDが非表示フィールドに格納される。

```html
<body>
	<h1 th:text="${title}">Edit page</h1>
	<table>
	<form method="post" action="/edit" th:object="${formModel}">
		<input type="hidden" name="id" th:value="*{id}" />
		<tr><td><label for="name">名前</label></td>
			<td><input type="text" name="name" th:value="*{name}" /></td></tr>
		<tr><td><label for="age">年齢</label></td>
			<td><input type="text" name="age"  th:value="*{age}" /></td></tr>
		<tr><td><label for="mail">メール</label></td>
			<td><input type="text" name="mail"  th:value="*{mail}" /></td></tr>
		<tr><td><label for="memo">メモ</label></td>
			<td><textarea name="memo"  th:text="*{memo}" 
			cols="20" rows="5"></textarea></td></tr>
		<tr><td></td><td><input type="submit" /></td></tr>
	</form>
	</table>
</body>
```
　IDでエンティティを検索して取り出す処理をリポジトリに実装する。
`findById`はID番号を引数にして、MyDataインスタンスを取り出すメソッド。

```java:MyDataRepository.java
@Repository
public interface MyDataRepository extends JpaRepository<MyData, Long> {
    public MyData findById(Long name):
}
```
　GETアクセス時に呼ばれるeditメソッドでは、クエリで送られたIDを引数とする`findById`によってエンティティを取得して、その`get`を使い、`formModel`と名前を指定して`addObject`している。
　フォームが`/edit`に送信されるとupdateメソッドが呼び出される。送られたフォームのデータを元にエンティティの保存を行う際にも、新たにデータを保存すりのと同じ`saveAndFlush`で更新をする。新規保存と更新の違いは、引数のエンティティにIDが指定されているかどうか。

```java:SampleController.java
@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
public ModelAndView edit(@ModelAttribute MyData mydata, @PathVariable int id, ModelAndView mav) {
	mav.setViewName("edit");
	mav.addObject("title","edit mydata.");
	MyData data = repository.findById((long)id);
	mav.addObject("formModel",data.get());
	return mav;
}
@RequestMapping(value = "/edit", method = RequestMethod.POST)
@Transactional(readOnly=false)
public ModelAndView update(@ModelAttribute MyData mydata, ModelAndView mav) {
	repository.saveAndFlush(mydata);
	return new ModelAndView("redirect:/");
}
```
###エンティティの削除
　`/delete`にGETアクセスした際の`delete`メソッドと、POSTアクセスを処理する`remove`メソッドを用意している。
　`delete`メソッドでは指定IDのエンティティを`findById`で検索しｔ表示させる。その後POST送信されたremoveメソッドで送られたエンティティの削除を行う。`delete`もDBの変更を伴うのでメソッドに`@Transactional`アノテーションをつけることを忘れない。

```java
@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
public ModelAndView delete(@PathVariable int id, ModelAndView mav) {
  mav.setViewName("delete");
  mav.addObject("title", "delete mydata.");
  MyData data = repository.findById((long)id);
  mav.addObject("formModel", data);
  return mav;
}
@RequestMapping(value = "/delete", method = RequestMethod.POST)
@Transactional(readOnly = false)
public ModelAndView remove(@RequestParam long id, ModelAndView mav){
  repository.delete(id);
  return new ModelAndView("redirect:/");
}
```
###リポジトリのメソッド自動生成
JpaRepositoryには辞書によるコードの自動生成機能が組み込まれている。JpaRepositoryは、JPQLによるクエリテキストの生成と実行が行われている。

```
findById(引数)
　　　↓
"find" "by" "id" 引数
　　　↓
"select * from テーブル where id = 引数"というクエリの実行
```

###JPQLの使い方
####And
　2つの項目の値の両方に合致する要素を検索するような場合に用いられる。
それぞれの項目の値として引数を2つ用意する。

```
findByIdAndName
   ↓
from MyDataEntity where id = ?1 and name = ?2
```
####Or
　2つの項目の値のどちらか一方に合致する要素を検索するような場合に用いられる。
それぞれの項目の値として引数を2つ用意する。

```
findByIdOrName
　　　　↓
from MyDataEntity where id = ?1 or name = ?2
```
####Between
　2つの引数を値で渡し、両者の間の値を検索するような時に用いられる。指定の項目が一定範囲内の要素を検索する。

```
findByAgeBetween
　　　↓
from MyDataEntity where age between ?1 and ?2
```
####LessThan
　数値の項目で、引数に指定した値より小さいものを検索する。

```
findByAgeLessThan
　　　↓
from MyDataEntity where age < ?1
```
####GreaterThan
数値の項目で引数に指定した値より大きいものを検索する。

```
findByAgeGreaterThan
　　　↓
from MyDataEntity where age > ?1
```
####IsNull
　指定の項目の値がnullのものを検索する。

```
findCommentIsNull
　　　↓
from MyDataEntity where comment is null
```
####IsNotNull, NotNull
　指定の項目の値がnullでないものを検索する。`NotNull`でも理解する

```
findByCommentNotNull,
findByCommentIsNotNull
　　　↓
from MyDataEntity where comment not null
```
####Like
　テキストのLIKE検索を行う。指定の項目から値を曖昧に検索する。引数に渡す値にワイルドカードをつけて使用することができる。

```
findByNameLike
　　　↓
from MyDataEntity where name like　?1
```
####NotLike
　検索文字列をふくまないものを曖昧に検索。引数に渡す値にワイルドカードをつけて使用することができる。

```
findByNameNotLike
　　　↓
from MyDataEntity where name not like ?1
```

####OrderBy
　並び順の指定。通常の検索メソッド名の後につけられる。項目名の後に`Asc`や`Desc`をつけることで昇順か降順かを指定できる。

```
findByNameOrderByAgeAsc
　　　↓
from MyDataEntity where name = ?1 order by age Asc
```
####Not
　指定の項目が引数の値と等しくないものを検索する。

```
findByNameNot
　　　↓
from MyDataEntity where name <> ?1
```

####In
　指定の項目の値が、引数のコレクションに用意された値のどれかと一致すれば検索する

```
findByNameIn(Collection<String> name)
　　　↓
from MyDataEntity where name in ?1
```

####NotIn
　指定の項目の値が引数のコレクションに用意されたどの値とも一致しないものを検索する

```
findByNameNotIn(Collection<String> name)
　　　↓
from MyDataEntity where name not in ?1
```
####JpaRepositoryのメソッド実装例
```java
@Repository
public interface MyDataRepository  extends JpaRepository<MyData, Long> {

	// "%" + str + "%"のようにワイルドカード指定必要
	public List<MyData> findById(Long name);
	public List<MyData> findByNameLike(String name);
	public List<MyData> findByIdIsNotNullOrderByIdDesc();
	public List<MyData> findByAgeGreaterThan(Integer age);
	public List<MyData> findByAgeBetween(Integer age1, Integer age2);

}
```

* メソッド名はキャメル記法
* メソッド名の単語の並び重要`find[By○○][その他の検索条件][OrderByなど]`
* 引数の型が一致しているか確認する

**単純な検索は全て自動生成メソッドで。複雑な検索処理だけ、DAOで定義して利用する**
##エンティティのバリデーション
　バリデーションをモデルに予め用意しておくことで、入力される各項目にルールが設定され、入力値が違反していないかチェックできる。
###@ Validated
　これがエンティティの値をバリエーションチェックする。これをつけることで、エンティティの各値を自動的にチェックするようになる。

###@ BindingResult
　バリデーションチェックの結果は、その次の`BindingResult`という引数で受け取る。
エラーが発生しているかどうかは、`hasErrors`メソッドで調べられる。`true`ならばエラーあり、`false`ならエラーなしなので、下の場合、`if(!result.hasErrors())`の中でエラーがない場合の処理（データの保管など)をしていく。

```java
if(!result.hasErrors()) {...}
```
###エラーメッセージの出力
　th:eachに`${#fields.detailedErrors()}`に変数式が設定されているのは、`#fields`にエンティティの各フィールドをバリデーションチェックした結果などがまとめられたオブジェクトで、`detailedErrors`メソッドは、発生したエラーに関する情報をひとまとめのリストとして返すもの。`th:each`では、リストから順にエラーのオブジェクトを取り出して変数`error`に設定する。

```html
<li th:each="error : ${#fields.detailedErrors}" class="err" th:text="${error.message}">
```
`error`には`message`というプロパティがあり、これで発生したエラーのメッセージが得られる。`th:text="${error.message}"`という形で出力される。

【テンプレート】

```html
<form method="post" action="/" th:object="${formModel}">
	<ul>
		<li th:each="error : ${#fields.detailedErrors()}"
			class="err" th:text="${error.message}" />
	</ul>
	<tr><td><label for="name">名前</label></td>
		<td><input type="text" name="name" 
			th:field="*{name}" /></td></tr>
	<tr><td><label for="age">年齢</label></td>
		<td><input type="text" name="age"
			th:field="*{age}" /></td></tr>
	<tr><td><label for="mail">メール</label></td>
		<td><input type="text" name="mail" 
				th:field="*{mail}" /></td></tr>
	<tr><td><label for="memo">メモ</label></td>
		<td><textarea name="memo" th:field="*{memo}" 
			cols="20" rows="5" ></textarea></td></tr>
	<tr><td></td><td><input type="submit" /></td></tr>
</form>
```
【エンティティ】

```java
@Entity
@Table(name = "mydata")
public class MyData {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 50, nullable = false)
	@NotEmpty
	private String name;

	@Column(length = 200, nullable = true)
	@Email
	private String mail;

	@Column(nullable = true)
	@Min(0)
	@Max(200)
	private Integer age;

	@Column(nullable = true)
	private String memo;

	// ……アクセサは省略……
}
```

【コントローラー】
　エンティティで設定したバリデーションに入力値が違反していないかチェックし、ルールを満たしている場合のみ値の保管を行えるようにするサンプル

```java
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(
	@ModelAttribute("formModel") MyData mydata, 
		ModelAndView mav) {
	mav.setViewName("index");
	mav.addObject("msg","this is sample content.");
	mav.addObject("formModel",mydata);
	Iterable<MyData> list = repository.findAll();
	mav.addObject("datalist",list);
	return mav;
}

@RequestMapping(value = "/", method = RequestMethod.POST)
@Transactional(readOnly=false)
public ModelAndView form(
    @ModelAttribute("formModel") @Validated MyData mydata, 
    BindingResult result,
    ModelAndView mov) {

	ModelAndView res = null;
	if (!result.hasErrors()){
		repository.saveAndFlush(mydata);
		res = new ModelAndView("redirect:/");
	} else {
		mov.setViewName("index");
		mov.addObject("msg","sorry, error is occured...");
		Iterable<MyData> list = repository.findAll();
		mov.addObject("datalist",list);
		res = mov;
	}
	return res;
}
```
###各入力フィールドにエラーを表示
```html
<input type="text" name="name" th:value="*{name}" th:errorclass="err" />
```
　`th:value="*{name}"`としてオブジェクトの`name`プロパティを値に設定している。`th:errorclass`という属性が用意されていて、エラーが発生した際に適用されるクラス名を指定する。これによってエラーが発生したときのみの処理を適用している。

```html
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}" th:errorclass="err">
```
`hasErrors`は引数に指定したフィールドにエラーが発生しているかどうかを`th:if`を使って`true`の時だけダグを表示させている。

エラーメッセージの表示は`th:errors`という属性を利用し、サンプルでは、`*{name}`を指定している。

【テンプレート】

```html
<form method="post" action="/" th:object="${formModel}">
		<tr><td><label for="name">名前</label></td>
			<td><input type="text" name="name"
				th:value="*{name}" th:errorclass="err" />
			<div th:if="${#fields.hasErrors('name')}" 
				th:errors="*{name}" th:errorclass="err">
				</div></td></tr>
		<tr><td><label for="age">年齢</label></td>
			<td><input type="text" name="age"
				th:value="*{age}" th:errorclass="err" />
			<div th:if="${#fields.hasErrors('age')}" 
				th:errors="*{age}" th:errorclass="err">
				</div></td></tr>
		<tr><td><label for="mail">メール</label></td>
			<td><input type="text" name="mail" 
				th:value="*{mail}" th:errorclass="err" />
			<div th:if="${#fields.hasErrors('mail')}" 
				th:errors="*{mail}" th:errorclass="err">
				</div></td></tr>
		<tr><td><label for="memo">メモ</label></td>
			<td><textarea name="memo" th:text="*{memo}" 
				cols="20" rows="5" ></textarea></td></tr>
		<tr><td></td><td><input type="submit" /></td></tr>
	</form>
```
###javax.validationによるアノテーション
|バリデーションアノテーション|内容|
|:--|:--|
|@ Null|値がnullであることのチェック|
|@ NotNull|値がnullであることを認めない|
|@ Min(int num)|数値（整数）を入力する項目で入力可能な最小値を指定する|
|@ Max(int num)|数値（整数）を入力する項目で入力可能で最大値を指定する|
|@ DecimalMin(String num)|BigDecimal,BigInteger,String値で値を設定する場合の最小値の指定　intもOK|
|@ DecimalMax(String num)|BigDecimal,BigInteger,String値で値を設定する場合の最大値の指定　intもOK|
|@ Degits(integer=5, fraction=10)|整数部分と小数部分の桁数制限|
|@ Future|現在より未来の日時のみを受け付けるようにする|
|@ Past|現在より過去の道時のみを受け付けるようにする|
|@ Size(min=1, max=10)|Stringのほか、配列、コレクションクラスなどのオブジェクトの保管される要素数の指定|
|@ Pattern(regexp="[a-zA-Z]+")|正規表現のパターンを指定して入力チェックを行う|

###HiberinateValidatorによるアノテーション
|バリデーションアノテーション|内容|
|:--|:--|
|@ NotEmpty|nullも空文字も認めない|
|@ Length(min=5, max=10)|Stringtに使用される文字列の長さの範囲を指定するアノテーション|
|@ Range|最小値、最大値をの範囲指定をするために数値項目で使用される。@ Minと@ Maxをまとめられる|
|@ Email|入力された値が電子メールアドレスかどうかをチェックする|
|@ CreditCardNumber|クレカ番号形式かどうかのチェックをするために数値かString値で数値で入力される項目で用いる。|
|@ EAN|バーコード識別番号の規格|
###エラーメッセージについて
英語で表示されるエラーメッセージをカスタマイズする方法
エンティティクラスでバリデーションのためアノテーションを用意する際に`message`という値を使って表示メッセージを指定する

```java
@NotEmpty(message="空白は不可")

@Email(message="メールアドレスのみ")

@Min(value=0, message="ゼロ以上")
@Max(value=200, message="200以下")
```
###プロパティファイルの利用
実際の開発ではメンテナンス性が悪いのでメッセージは、プロパティファイルを用意して管理すべき
resourceフォルダに「ValidationMessages.properties」という名前でテキストファイルを作成することで対応できる
###オリジナルのバリデータを作成する
バリデータの自作には

* アノテーションクラス 
* バリデータクラス
が必要

アノテーションクラスは、
　@ interfaceの後に名前を記述するアノテーション型のクラスを作成
バリデータクラスは、javax.validation.ConstraintValidatorインターフェースを実装して定義する。`ConstraintValidator`には`initialize`と`isValid`の2つのメソッドがあり、これらを実装して必要な処理を記述する。

* `intialize`メソッド

初期化メソッド
引数には総称型で指定したアノテーションクラスが渡される
必要に応じてアノテーションに関する情報を取得する

* `isValid`メソッド

バリデーション処理を行う部分
引数には入力された値（String）と`ConstraintValidator`インスタンスが渡される。
ここで値をチェックしてバリデーションの正否に応じて`boolean`値を返す。

【アノテーションクラス】

```java
@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@ReportAsSingleViolation
public @interface Phone {
  String message() default "Please input a phone number.";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() dedault {};
}
```
【バリデーションクラス】

```java
public class PhoneValidator implements ConstraintValidator<Phone, String> {

  @Override
  public void initialize(Phone phone){
  }

  @Override
  public boolean isValid(String input, ConstraintValidatorContext cxt){
    if(input == null){
      return false;
    }
    return input.matches("[0-9()-]*");
  }

}
```

#６． データベースアクセスを掘り下げる
　リポジトリを用意することで、ほぼコードを書くことなくDBアクセスが可能であるが、限界があるので、SpringDataJPAに用意されているDBアクセスの機能をSpringBootアプリケーション内から利用する方法について考える。

##DataAccessObject
　DBを利用する場合、データを表示するページにアクセスしたら、そのコントローラーのリクエストハンドラ内でデータを取り出して、ビューに表示する処理を用意すること。つまり、コントローラーの各リクエストハンドラに、必要なDBアクセスの処理を用意する。

リクエストごとに処理を書くとコントローラーが肥大化するので、データアクセスとロジックは分離させる。よってDBアクセスする手段を提供するDAO(DataAccessObject)というオブジェクトを用意する。これらをコントローラーから呼び出して必要な処理を行う。


`EntityManager`クラスを保管するためのフィールドを用意することで、エンティティを利用するために必要な機能を提供する。


###createQueryによるクエリの作成

　`Query`はSQLでデータを問い合わせるためのクエリ一文に相当する機能を持つオブジェクト
　JPQLによるクエリとなるのが`Query`インスタンス
　EntityManagerの`createQuery`は引数にJPQLによるクエリ一文を指定して呼び出すとクエリを実行するためのQueryインスタンスが生成される。
サンプルの`from MyData`とは`select * from mydata`に相当するJPQLのクエリ一文

```java
Query query = entityManager.createQuery("from MyData");
```
###Queryから結果を取得する

　作成されたQueryがもつ`getResultList`メソッドにより、クエリに実行結果をインスタンスとして取得できる。

```java
List<MyData> list = query.getResultList();
```
###@ SuppressWarnings
 サンプルでは`list`変数に付けられているアノテーションでコンパイル時の警告を抑制する。`unchecked`を引数にすることで、メソッドの戻り値が格納先の変数の型の値として得られているかチェックを行う。動作そのものには関係がなく、**ビルド時に警告が出ないようにする**もの

```java
@SuppressWarnings("unchecked")
```

【DAOインターフェース】

```java
public interface MyDataDao <T> extends Serializable {	
	public List<T> getAll();	
}
```

【DAOの実装クラス】

```java
@Repository
public class MyDataDaoImpl implements MyDataDao<MyData> {
	private static final long serialVersionUID = 1L;
	
	private EntityManager entityManager;
	
	public MyDataDaoImpl(){
		super();
	}
	public MyDataDaoImpl(EntityManager manager){
		this();
		entityManager = manager;
	}
	
	@Override
	public List<MyData> getAll() {
		Query query = entityManager.createQuery("from MyData");
		@SuppressWarnings("unchecked")
		List<MyData> list = query.getResultList();
		entityManager.close();
		return list;
	}
	
}
```
###コントローラーの実装
　DAOでエンティティを利用するコントローラーを作成する。

###@ PersistenceContext
　`@PersistenceContext`は、`EntityManager`のBeanを取得してフィールドに設定する。
　SpringBootでは`EntityManager`が自動的にBeanとしてインスタンスが登録されているので、これを`@PersistenceContext`でコントローラーのフィールドに割り当てる。
　`@PersistenceContext`を使ったBeanのバインドは、「**1クラスにつき1インスタンス**」までしか置けない

```java
@PersistenceContext
EntityManager entityManager;
```
　DAO経由でエンティティからリストを取得してビューのテンプレート名の設定と同時にテンプレート側にリストのオブジェクトを渡している。DAOにエンティティへのアクセスの処理をまとめておけば、コントローラー側で簡単にアクセス処理が呼び出せる。

```java
Iterable<MyData> list = dao.getAll();
mav.addObject("datalist", list);
```
```java
public class SampleController {
  // リポジトリ
  @Autowired
  MyDataRepository repository;

  // エンティティ
  @PersistenceContext
  EntityManager entityManager;

  // DAO
  MyDataDaoImpl dao;

  @PostConstruct
  public void init() {
    dao = new MyDataDaoImpl(entityManager);
    MyData md = new MyData():
    md.setHoge("fuga");
    md.setNumber(123);
    repository.saveAndFlush(md);
  }

  @RequestMapping(value = "/", method = RequestMethod.GET)
  public ModelAndView index() {
    mav.setViewName("index");
    mav.addObject("msg", "MyDataのサンプルです。");
    Iterable<MyData> list = dao.getAll();
    mav.addObject("datalist", list);
    return mav;
  }
}
```

###DAOに検索メソッドを追加する

【DAOインターフェース】

```java
public interface MyDataDao<T> extends Serializable {
	
    public List<T> getAll();
    // IDを引数にしてエンティティを検索して返す
    public T findById(long id);
    // 名前からエンティティを検索して返す
    public List<T> findByName(String name);
}
```
【DAO実装クラス】

`"from MyData where id = "` -> JPQLのクエリ（idを引数にしてエンティティを取得）
`getSingleResult`は`Query`から得られるエンティティを1つだけ取り出して返すもの
**１つのエンティティしか検索されない**ようなもの（IDとか）については、Listで返すより、得られたエンティティをそのまま返した方が良い

```java
@Override
public MyData findById(long id) {
	return (MyData)entityManager.createQuery("from MyData where id = " 
		+ id).getSingleResult();
}
```
`"from MyData where name = "` -> JPQLのクエリ（名前を引数にしてエンティティを取得）
`getResultList`はListを返すので`findByName`は`List<MyData>`が戻り値の型

```java
@SuppressWarnings("unchecked")
@Override
public List<MyData> findByName(String name) {
	return (List<MyData>)entityManager.createQuery("from MyData where name = " 
		+ name).getResultList();
}
```

##JPQLを利用する
JPQLは、SQLのクエリと似たクエリ文を実行することでJPAがSQLクエリを生成し、DBを操作する簡易言語

###HttpServletRequest

　フォームを`POST`で受け取るメソッドなど、送信された値を受け取って処理を行うときには`@RequestParam`を引数に使ってきたが、`HttpServletRequest`を引数に使うこともできる。
　実は、`@RequestParam`のパラメータは`HttpServletRequest`の`getParameter`を呼び出してパラメータを受け取る操作を自動的に行って、その結果を引数に設定するもの
　`HttpServletResponse`も引数に指定することができる

```java
@RequestMapping(value = "/find", method = RequestMethod.POST)
public ModelAndView search(HttpServletRequest request,
		ModelAndView mav) {
	mav.setViewName("find");
	String param = request.getParameter("fstr");
	if (param == ""){
		mav = new ModelAndView("redirect:/find");
	} else {
		mav.addObject("title","Find result");
		mav.addObject("msg","「" + param + "」の検索結果");
		mav.addObject("value",param);
		List<MyData> list = dao.find(param);
		mav.addObject("datalist", list);
	}
	return mav;
}
```

###DAOへのfindメソッドの追加（名前付きパラメータを使う）

クエリ「`"from MyData where id = :fstr"`」の`:fstr`のような形式でJPQLのクエリ文に書かれたものは**パラメータ用の変数**として扱われる。
　その後に続く、`Query`インスタンスの`setParameter`が、第1引数の変数に第2引数の値を設定して直前の`:fstr`に値を代入してクエリを作る
　
【DAOインターフェース】

```java
public List<T> find(String fstr);
```
【DAO実装クラス】

```java
@Override
public List<MyData> find(String fstr){
	List<MyData> list = null;
	String qstr = "from MyData where id = :fstr";
	Query query = entityManager.createQuery(qstr)
		.setParameter("fstr", Long.parseLong(fstr));
	list = query.getResultList();
	return list;
}
```
###複数のパラメータをクエリにいくつでも埋め込める

　`setParameter`（パラメータを設定済みのQueryインスタンスを返す）をメソッドチェーンで連ねて、一つのクエリにパラメータをいくつも設定できる

```java
String qstr = "from MyData where id = :fid or name like :fname or mail like :fmail";
Long fid = 0L;
Query query =
    entityManager.createQuery(qstr).setParameter("fid", fid)
			.setParameter("fname", "%" + fstr + "%")
			.setParameter("fmail", fstr + "@%");
```
###「?」による番号指定のパラメータ
　クエリ内に埋め込むパラメータ用変数は、番号指定によって値を設定するものもある。`?1`のように、「**?**」の後に数字を指定をすることでパラメータの埋め込み一を設定する

```java
String qstr = "from MyData where id = ?1 or name like ?2 or mail like ?3";
Long fid = 0L;
    Query query = entityManager.createQuery(qstr).setParameter(1, fid)
		.setParameter(2, "%" + fstr + "%")
		.setParameter(3, fstr + "@%");
```
###クエリアノテーション
　名前付きクエリは`@NamedQuery`を使って作ることができる。エンティティクラスの宣言の前に付ける
　クエリの文字列に名前をつけて設定する

```java
@Entity
@NamedQuery(
  name = "findWithName",
  query = "from MyData where name like :fname"
)
@Table(name = "mydata")
public class MyData {
  ...
}
```
複数のクエリをまとめるために`@NamedQueries`を使う
カンマで区切っていくらでも`@NamedQuery`を追加できる

```java
@NamedQueries (
    @NamedQuery(
        name="findWithName",
        query="from MyData where name like :fname"
    )
)
```
`createNamedQuery`は引数にクエリアノテーションの名前をテキストで指定することで、その名前のクエリを取得して、`Query`インスタンスを作成する
　名前付きクエリを使うことでDAOのコードから切り離して、エンティティクラスにクエリを置く
-> 複数のエンティティを扱うときに同じ働きのクエリを同じ名前でそれぞれに置くことでわかりやすい

```java
Query query = entityManager
    .createQuery("findWithName")
    .setParameter("fname", "%" + fstr + "%");
```

###リポジトリと@ Query
 検索機能を拡張するたびにエンティティを書き換えるのはナンセンスなので、実際にDBアクセスを実行する側にクエリを準備したい
　クエリは、リポジトリとなるインターフェースに`@Query`で宣言することができる
`@Query`はアノテーションを記述したメソッドを呼び出す際に指定されたクエリが使われるようになる

```java
@Repository
public interface MyDataRepository  extends JpaRepository<MyData, Long> {
	
	@Query("SELECT d FROM MyData d ORDER BY d.name")
	List<MyData> findAllOrderByName();
}
```

　コントローラーから、クエリを実行するリポジトリを呼び出してみる
　クエリを用意する場所が、DAOかリポジトリかの違いなので内部的な違いはない

```java
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(ModelAndView mav) {
	mav.setViewName("index");
	mav.addObject("title","Find Page");
	mav.addObject("msg","MyDataのサンプルです。");
	Iterable<MyData> list = repository.findAllOrderByName(); //dao.getAll();
	mav.addObject("datalist", list);
	return mav;
}
```

###@ NamedQueryのパラメータ
　詳細な検索を行いたい場合、クエリの中に検索条件のための値を組み込む必要が生じる
　こうした場合に、クエリアノテーションに設定するクエリテキストにパラメータを用意することができる
　

```java
@NamedQuery (
    name = "findByAge",
    query = "from MyData where age > :min and age < :max"
)
```

　エンティティクラスの手前にこのような形で`@NamedQuery`を用意しておいて、クエリに埋め込まれたパラメータに値を渡すようにしてDAOから呼び出す
　DAOから実際に`findByAge`を呼び出してみる
　`Query`インスタンスの作成は`createNamedQuery`を引数をクエリの名前を指定して行う
　その後`setParameter`を使って`@NamedQuery`に用意したクエリテキストのパラメータに値を渡す
　そして、`getResultList`でエンティティを検索する

```java
public List<MyData> findByAge(int min, int max);
```

```java
@suppresswarning
@Override
public List<MyData> findByAge(int min, int max) {
    return (List<MyData>) entityManager
        .createNamedQuery("findByAge")
        .setParameter("min", min)
        .setParameter("max", max)
        .getResultList();
}
```
###@ Queryを使う
　`@Query`を使う場合もクエリテキストに変数を埋め込み、メソッドの引数で指定するやり方としては同じ
　ただし、`@Param`を使い、どの変数がどのパラメータと関連付けられるかを指定する
　以下`@NamedQuery`に追加した`findByAge`をリポジトリに用紙する場合のサンプル
　
【リポジトリのインターフェース】

```java
@Query("from MyData where age > :min and age < :max")
public List<MyData> findByAge(@Param("min") int min, @Param("max") int max);
```
　エンティティ自体にクエリを持たせるか、リポジトリに用意するかはアプリケーションの設計によって最適な方を使い分ける。

##Criteria APIによる検索
　JPQLのような言語を使わず、メソッドチェーンによってDBアクセスを行う機能も用意されている -> Criteria API
　Criteria APIは3つのクラスを組み合わせて利用する

|クラス|できること|
|:--|:--|
|CriteriaBuilder|クエリ生成の管理|
|CriteriaQuery|クエリ実行|
|Root|検索されるエンティティのルートでここからエンティティを絞り込んだりする|

①CriteriaBuilderの取得
　`CriteriaBuilder`のインスタンスの用意をして、`EntityManager#getCriteriaBuilder`を呼び出す

```java
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
```

②CriteriaQueryの作成
　クエリ文を引数としたりはしない
　特定のエンティティにアクセスするためにそのエンティティのclassプロパティを引数に指定する

```java
CriteriaQuery <Entity> query = builder.createQuery(Entity.class);
```

③Rootの取得
　　RootをCriteriaQueryのfromメソッドで取得
　引数には検索するエンティティのClassプロパティを指定

```java
Root <Entity> root = query.from(Entity.class);
```

④CriteriaQueryメソッドの実行
`CriteriaQuery`でエンティティを絞り込むためのメソッドの呼び出し
必要に応じてメソッドチェーンで呼び出す

```java
query.select(root);
```

⑤createQueryして結果を取得
　最後に`createQuery`でQueryを生成し、`getResultList`で結果の`List`を取得
　`createQuery`の引数には`QriteriaQuery`を指定するのが通常のQueryによる検索処理との違い

```java
List<Entity> list = (List<MyData>)entityManager
    .createQuery(query)
    .getResultList();
return list;
```
以下、全エンティティの取得を`getAll`メソッドによって行うサンプル

　Rootの取得には`from`メソッドの引数としてMyData.classを指定
全MyDataかを情報として保持したRootインスタンスが得られる
 Root取得後、全てのMyDataを取得するのに、`CriteriaQuery#select`を引数にMyData.classを指定して呼び出す
　後は、この`CriteriaQuery`を`createQuery`し、`getResult`すればすべてのMydataが取得できるようになっている

```java
@Override
public List<MyData> getAll() {
	List<MyData> list = null;		
	CriteriaBuilder builder = 
			entityManager.getCriteriaBuilder();
	CriteriaQuery<MyData> query = 
			builder.createQuery(MyData.class);
	Root<MyData> root = query.from(MyData.class);
	query.select(root);
	list = (List<MyData>)entityManager
			.createQuery(query)
			.getResultList();
	return list;
}
```
###CriteriaAPIによる名前検索
　引数のテキストとnameの値が一致するエンティティだけを検索するようにしている
　Rootインスタンスを取得した後、取り出すエンティティを絞り込むための処理をする
　
`select(root)`後にメソッドチェーンを使って`where`メソッドをExpression（様々な式の評価を扱う）を引数としてエンティティを絞り込む処理を行う
　　`equal`メソッドに引数に指定したExpressionとObjectによって両者が等しいかどうかを確認し、結果を`Predicate`クラスのインスタンスとして返す
　`Predicate`はメソッドに指定される条件や式をオブジェクトとして表す役割があるので、例えば`equal`なら引数に指定したものが等しい条件を示す`Predicate`が用意され、条件に合致するエンティティを絞り込む

```java
// where(Expression<boolen>)
// equal(Expression, Object)
query.select(root)
		.where(builder.equal(root.get("name"), fstr));
```

###CriteriaBuilderのメソッド

|メソッド|書式|説明|
|:--|:--|:--|
|equal|equal(Expression<?> x, Expression<?> y)|引数が等しいことを検証するための述語を作ります。|
|gt|gt(Expression<? extends java.lang.Number> x, Expression<? extends java.lang.Number> y)|最初の引数が二つ目の引数より大きいかどうか検証するための述語を作ります。|
|greaterThan|greaterThan(Expression<? extends Y> x, Expression<? extends Y> y)|最初の引数が二つ目の引数より大きいかどうかを検証するための述語を作ります。|
|ge|ge(Expression<? extends java.lang.Number> x, Expression<? extends java.lang.Number> y)|最初の引数が二つ目の引数以上であるかどうか検証するための述語を作ります。|
|greaterThanOrEqualTo|greaterThanOrEqualTo(Expression<? extends Y> x, Expression<? extends Y> y)|最初の引数が二つ目の引数以上であるかどうか検証するための述語を作ります。|
|lt|lt(Expression<? extends java.lang.Number> x, Expression<? extends java.lang.Number> y)|最初の引数が二つ目の引数未満であるかどうか検証するための述語を作ります。|
|lessThan|Predicate|lessThan(Expression<? extends Y> x, Y y)|最初の引数が二つ目の引数未満であるかどうか検証するための述語を作ります。|
|le|le(Expression<? extends java.lang.Number> x, java.lang.Number y)|最初の引数が二つ目の引数以下であるかどうか検証するための述語を作ります。|
|lessThanOrEqualTo|lessThanOrEqualTo(Expression<? extends Y> x, Y y)|最初の引数が二つ目の引数以下であるかどうか検証するための述語を作ります。|
|between|between(Expression<? extends Y> v, Expression<? extends Y> x, Expression<? extends Y> y)|最初の引数が二つ目と三つ目の引数の間の値であるか検証するための述語を作ります。|
|isNull|isNull(Expression<?> x)|式がnullかどうかを検査する述語を作ります。|
|isNotNull|isNotNull(Expression<?> x)|式がnullでないかどうかを検査する述語を作ります。|
|isEmpty|isEmpty(Expression<C> collection)|コレクションが空かどうかを検証するための述語を作ります。|
|isNotEmpty|isNotEmpty(Expression<C> collection)|コレクションが空でないかどうかを検証するための述語を作ります。|
|like|like(Expression<java.lang.String> x, Expression<java.lang.String> pattern)|式が与えられたパターンを満たすかどうかを検証する述語を作ります。|
|and|and(Expression<java.lang.Boolean> x, Expression<java.lang.Boolean> y)|与えられたブール式の論理積を作ります。|
|or|or(Expression<java.lang.Boolean> x, Expression<java.lang.Boolean> y)|与えられたブール式の論理和を作ります。|
|not|not(Expression<java.lang.Boolean> restriction)|与えられた限定の否定を作ります。|

####orderByによるエンティティのソート
　検索された結果はエンティティを`List`として取得する際に`orderBy`メソッドを使用する
　引数の`Expression`は`CriteriaBuilder#get`を使ってエンティティのプロパティを示すPathを指定する
　サンプルの`orderBy`の引数はnameの要素について昇順に並べ替えるPredicateを設定している

```java
query.select(root).orderBy(builder.asc(root.get("name")));
```
###取得位置と取得個数の設定
　Queryのエンティティ取得メソッドは、エンティティを1つだけ返す[getSingleResult](###DAOに検索メソッドを追加する)と全エンティティをListで返す[getResultList](###Queryから結果を取得する)がある
　実際のDB利用の際には、位置と個数を指定して取得することもできる

* 指定の位置から取得する

　引数に整数値を指定する
　取得位置はリストの先頭を0とする

```java
　query.setFirstResult(int pos);
```
* 指定の個数を取得する

　取得する個数を指定
　設定されるのは得られる最大数なのでエンティティが足りない場合はあるだけが取り出される

```java
@Override
public List<MyData> getAll() {
	int offset = 1; // 取り出す位置の指定
	int limit = 2;  // 取り出す個数の指定
	List<MyData> list = null;
	CriteriaBuilder builder = 
			entityManager.getCriteriaBuilder();
	CriteriaQuery<MyData> query = 
			builder.createQuery(MyData.class);
	Root<MyData> root = 
			query.from(MyData.class);
	query.select(root);
	list = (List<MyData>)entityManager
			.createQuery(query)
			.setFirstResult(offset)
			.setMaxResults(limit)
			.getResultList();
	return list;
}
```

##エンティティの連携
　複数のテーブルが関連して動くようなDBは「アソシエーション」と呼ばれる機能によりエンティティ同士を連携して処理する
-> クラスのプロパティとして別のエンティティを持たせる

####@ OneToOne
　2つのエンティティが1対1で対応する連携を示すもの
####@ OneToMany
　1つのエンティティに対してもう一方のエンティティの複数が対応する
####@ ManyToOne
　複数のエンティティに対し、もう一方のエンティティの1つだけが対応する
####@ ManyToMany
　複数のエンティティに対し、他方の複数のエンティティが対応する関係

サンプルの`MsgData`は一人のメンバーがいくつでもメッセージを投稿できるので、
`@ManyToOne`で`MyData`に関連付けられている

【関連付け元のエンティティ】

```java
@Entity
@Table(name = "msgdata")
@Getter
@Setter
public class MsgData {
  @Id
  @Column
  @NotNull
  private long id;

  @Column
  private String title;

  @Column(nullable = false)
  @NotEmpty
  private String message;

  @ManyToOne
  private MyData mydata;

  //以下、コンストラクタ、アクセサの省略
}
```

【関連付け先のエンティティ】
　MsgDataと関連付けるためのmsgdatasとうプロパティを追加する

```java
@Entity
@Table(name = "mydata")
@Getter
@Setter
public class MyData {
  @OneToMany(cascade = CascadeType.ALL)
  @Column(nullable = true)
  private List<MsgData> msgdatas;
}
```

　リポジトリの`save`では、保存をする際、他のエンティティに関連付けられたフィールドがある場合は、送信された情報を元にインスタンスを取得して自動的に設定する
そのため、関連付いたレコードの登録処理をエンティティの連携を意識してプログラマが実装する必要がない

```java
repository.saveAndFlush(msgdata);
```
<エンティティ連携のポイント>

* モデルできちんとアノテーションを付ける
* フォームに正しく関連付けたエンティティの項目を用意する

#７． SpringBootを更に活用する
##サービスとは
　ビジネスロジックの中で、アプリケーションからりようできるようコンポーネント化された部分は「**サービス層**」と一般に呼ばれ、コントローラーやモデルを利用するDAOなどとも違って、どこからでも呼び出して利用できるクラス

コントローラーとビジネスロジック（モデル）の両者から自由に呼び出せるものが**サービス**

SpringFrameworkはこのサービスをBeanとして登録してアノテーションを記述するだけでいつでも利用できるようになっている

```
○アプリケーション層
  ・コントローラー
    リクエストハンドラ
  ・モデル
    ビジネスロジック
    エンティティ
○ドメイン層
  ・サービス
  ・リポジトリ
```
###@ Service
　このクラスをサービスとして登録するためのアノテーションで、サービスのクラスはクラス名の前にこのアノテーションをつける

###@ PersisitenceContext
　`EntityManager`のBeanを自動的に割り当てるためのもので、コントローラークラス側にではなく、サービスに`EntityManager`を用意して利用することもできる

```java
@Service
public class MyDataService {

	@PersistenceContext
	private EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public List<MyData> getAll() {
		return (List<MyData>) entityManager
			.createQuery("from MyData").getResultList();
	}

	public MyData get(int num) {
		return (MyData)entityManager
				.createQuery("from MyData where id = " + num)
				.getSingleResult();
	}

	public List<MyData> find(String fstr) {
		CriteriaBuilder builder = entityManager.getCriteriaBuilder();
		CriteriaQuery<MyData> query = builder.createQuery(MyData.class);
		Root<MyData> root = query.from(MyData.class);
		query.select(root).where(builder.equal(root.get("name"), fstr));
		List<MyData> list = null;
		list = (List<MyData>) entityManager.createQuery(query).getResultList();
		return list;
	}

}
```

###コントローラーでサービスBeanを使う
　DAOからサービスBeanを使ってDBアクセスする
　作成したサービスは`@Autowired`でBeanとしてコントローラーに関連付けて使用する

`@Service`が記述されているサービスクラスはアプリケーション内でBean化され、それが`@Autowired`によってフィールドに割り当てられる

```java
@Controller
public class SampleController  {

	@Autowired
	MyDataRepository repository;

        // サービスBeanをフィールドに関連付ける	
	@Autowired
	private MyDataService service;
	
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("title","Find Page");
		mav.addObject("msg","MyDataのサンプルです。");
                // 全エンティティの取得
		List<MyData> list = service.getAll(); 
		mav.addObject("datalist", list);
		return mav;
	}

        // "/find"のGETリクエストハンドラ省略

        @RequestMapping(value = "/find", method = RequestMethod.POST)
        public ModelAndView search(HttpServletRequest request,
            ModelAndView mav) {
        mav.setViewName("find");
        String param = request.getParameter("fstr");
        if(param == "") {
            mav = new ModelAndView("redirect:/find");
        } else {
            mav.addObject("title", "Find result");
            mav.addObject("msg", "「" + param + "」の検索結果");
            mav.addObject("value", param);
            // エンティティの検索
            List<MyData> list = service.find(param);
            mav.addObject("datalist", list);
        }
        return mav;
    }
    
    // 以下コンストラクタ、アクセサ等省略

}
```

##RestControllerを作成する
 Webアプリケーション開発における「**サービス**」とは一般に「**外部からアクセスして必要な情報を受け取ることのできるWebプログラム**」を意味する
　外部から利用できるサービスとしてJSON形式、XML形式のRESTサービスがある

```java
@RestController
public class MyDataRestController {

	@Autowired
	private MyDataService service;

	@RequestMapping("/rest")
	public List<MyData> restAll() {
		return service.getAll();
	}

	@RequestMapping("/rest/{num}")
	public MyData restBy(@PathVariable int num) {
		return service.get(num);
	}
}
```
###XMLでデータを取得する
　RestControllerでXMLで扱う場合はデータ形式を解析して処理するライブラリ「Jackson DataFormat XML」を用意する

###@ XmlRootElement
 XMLデータでのルートとなるエレメントであることを示す。リクエストハンドラの`restAll
`や`restBy`が得られたオブジェクトを返して、通常ならJSON形式に変換され、`@XmlRootElement`がついていたらXML形式に変換されるだけの違い
Mavenを利用している場合

```xml:pom.xml
<dependency>
	<groupId>com.fasterxml.jackson.dataformat</groupId>
	<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
```

##コンポーネントとBean
　**コンポーネント**はアプリケーション内に自動生成されるBeanで、Beanのインスタンスは`@Autowired`でバインドすると利用できるようになる
　サービスはコンポーネントの一種 -> サービス層のコンポーネントが**サービス**と呼ばれるもの

###@ Component
アノテーションによってこれがつけられているクラスがコンポーネントとしてアプリケーションに認識されるようになる
　クラスのインスタンスがBeanとして登録されるようになる

###@ Autowiredコンストラクタ
　コンストラクタに`@Autowired`がつけられている場合、そのクラスのインスタンスがBeanとして登録される際にこの`@Autowired`が指定されたコンストラクタによってインスタンスが生成されるようになる
　`@Autowired`のついたコンストラクタがコンポーネントクラスに用意されていないと、アプリケーション実行時にエラーが発生し、起動に失敗するので必ず用意する

　`MySampleBean(ApplicationArguments　args)`のインスタンス引数は、アプリケーションが実行されたとき、つまり`@SpringBootApplication`が指定されたクラスで`SpringApplication.run`が実行されるときに渡された引数を管理するオブジェクト
　実行時に渡される引数を利用する場合はこのインスタンスを引数として用意する
　サンプルのメソッド内では`ApplicationArgments#getNonOptionArgs`でアプリケーション実行時の引数を`List`として取り出す

```java
@Component
public class MySampleBean {

	private int max = 10;

	@Autowired
	public MySampleBean(ApplicationArguments args) {
		List<String> files = args.getNonOptionArgs();
		try {
			max = Integer.parseInt(files.get(0));
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
	}
        
        public int count() {
		counter++;
		counter = counter > max ? 0 : counter;
		return counter;
	}
}
```

###コンポーネントの利用
　コンポーネントを利用するためにコントローラークラスにリクエストハンドラを追加する
　`@Autowired`でフィールドに関連付けておくと、自動的にバインドされるようになるので、リクエストハンドラ内の`bean.count`が実行できる
　コンポーネントは`@Autowired`でフィールドに関連付けることでどこからでも自由に利用できるようになる
　いくつものリクエストハンドラから呼び出す汎用的な機能があればとりあえずまとめておくとよい

```java
@Autowired
MySampleBean bean;

@RequestMapping("/count")
public int count() {
	return bean.count();
}
```
また`@Controller`はコントローラーの役割を果たすコンポーネント、`@Repository`は、データアクセスのためのコンポーネントとそれぞれ特別な役割が与えられたコンポーネントの一種で、`@Conponent`はそういった特別な役割を持たないものにつけられる

##覚えておきたいその他の機能
　Springにおいては標準で用意されるBeanを`@Autowired`などのアノテーションをつかってバインドすることや自分で**コンポーネント**や**サービス**を作ってBeanとして利用できるが、
**構成クラス**を利用してBeanをコントローラーなど各所で利用できる
　実際は**構成ファイルからアノテーションへ**というSpringBootの思想上、**構成ファイルを作る**というやり方はあまり推奨されない

###構成クラスの作成
　特に特殊なクラスを継承していない一般的なクラスでも`@Configuration`をつけておくと、アプリケーション起動時にこのクラスが構成クラスとしてインスタンス化されてそこに記述されているBeanなどをアプリケーションに登録する

【フィールドにBeanを登録した構成クラス】

```java
@Configuration
public class MyBootAppConfig {

	@Bean
	MyDataBean myDataBean(){
		return new MyDataBean();
	}
}
```

構成クラス内に`@Bean`をつけてクラスのインスタンスを返すメソッドを用意すれば、それがBeanとして登録されるようになる

【もととなったBeanクラス】

```java
public class MyDataBean {
	
	@Autowired
	MyDataRepository repository;
	
	public String getTableTagById(Long id){
		Optional<MyData> opt = repository.findById(id);
		MyData data = opt.get();
		String result = "<tr><td>" + data.getName()
				+ "</td><td>" + data.getMail() + 
				"</td><td>" + data.getAge() + 
				"</td><td>" + data.getMemo() + 
				"</td></tr>";
		return result;
	}

}
```
Beanがアプリケーションに用意されている状態で、`@Autowired`すれば、そのインスタンスが自動的にバインドされる

【Beanを使うためにフィールドに関連付けているコントローラー】

```java
@Autowired
MyDataBean myDataBean;

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ModelAndView indexById(@PathVariable long id,
		ModelAndView mav) {
	mav.setViewName("pickup");
	mav.addObject("title","Pickup Page");
	String table = "<table>"
			+ myDataBean.getTableTagById(id)
			+ "</table>";
	mav.addObject("msg","pickup data id = " + id);
	mav.addObject("data",table);
	return mav;
}
```
##ページネーション
SpringFrameworkにはページ分けのための**Page**クラスが用意されており、これを利用することで、ページごとにデータを扱う機能であるページネーションを実現できる

パラメータを指定することでページのレコード数や表示するページ番号を指定することができる（2データ/ページでその0ページ目という例）

【アクセス方法】

```
/page?size=2&page=0
```


リクエストハンドラである`findAll`メソッドは`Pagable`を引数にして`Page`インスタンスを取り出して`datalist`という名前でテンプレートに渡している



【ページネーションが実装されているリクエストハンドラをもつコントローラー】

```java
@RequestMapping(value = "/page", method = RequestMethod.GET)
public ModelAndView index(ModelAndView mav, Pageable pageable) {
	mav.setViewName("index");
	mav.addObject("title","Find Page");
	mav.addObject("msg","MyDataのサンプルです。");
	Page<MyData> list = repository.findAll(pageable); //●
	mav.addObject("datalist", list);
	return mav;
}
```
`Page`は`List`のサブクラスなので、`List`と同じ感覚でテンプレートに渡されたエンティティをテーブルに表示することができる。


【テンプレート】

```html
<table>
<tr><th>ID</th><th>名前</th><th>メール</th><th>年齢</th><th>メモ(tel)</th></tr>
<tr th:each="obj : ${datalist}">
	<td th:text="${obj.id}"></td>
	<td th:text="${obj.name}"></td>
	<td th:text="${obj.mail}"></td>
	<td th:text="${obj.age}"></td>
	<td th:text="${obj.memo}"></td>
</tr>
</table>
```

###Pageableクラスのメソッド
|メソッド|戻り|
|:--|:--|
|Pageable#getPageNumber()|現在のページ番号|
|Pageable#getPageSize()|ページに表示するレコード数|
|Pageable#first()|最初のPageable|
|Pageable#previousOrFirst()|前のまたは最初のPageable|
|Pageable#next()|次のPageable|

###Thymelaefの独自タグ作成
　ページネーションをして分けられたエンティティを取れば、ページの前後に移動したり、ページの表示に関する機能を用意する必要があるので**ユーティリティオブジェクト**を利用してJavaのクラスとして定義してThymeleaf内からその内部のメソッドを呼び出して結果を出力させることができる
　ユーティリティオブジェクトを使うためにはThymeleafの属性を処理する`AttributeTagProcessor`クラスとこのクラスをまとめるための`Dialect`クラスを用意する
　
`th:text="name"`とThymeleafの独自属性を記述したときにtextという属性の処理として値の`name`を受け取って処理をするのでその具体的な処理を用意する

`AbstractAttributeTagProcessor`を継承して作成したクラスにコンストラクタと`doProcess`を用意している
このメソッドに渡される引数については以下

|引数の型|説明|
|:--|:--|
|ITemplatecontext|テンプレートのコンテキストを扱う。ここからテンプレートエンジンや設定情報などテンプレートの情報を取り出す。|
|IProcessableElementTag|エレメントタグを扱うクラスでタグに組み込まれている属性などの情報を取り出せる|
|AttributeName|属性名やプレフィクス（値の前につけられるテキスト）などを扱う|
|String|属性の値|
|IElementTagStructureHandler|エレメントに属性を組み込むなど構造をハンドリングするクラス|

Thymeleafの変数式などが値に記述されている場合テンプレートエンジンに組み込まれている**リゾルバ**という値を評価する機能を使って変数式を処理して、結果となる値を取得してから実際の属性処理を行う必要があるので、以下サンプルは`doProcess`で行っている

【AbstractAttributeTagProcessorの継承クラス】

```java
public class MyPageAttributeTagProcessor extends AbstractAttributeTagProcessor {
	
	private static final String ATTR_NAME = "mypage";
	private static final int PRECEDENCE = 10000;
	public static int size = 2;

	public MyPageAttributeTagProcessor(final String dialectPrefix) {
		super(TemplateMode.HTML, dialectPrefix, null,
				false, ATTR_NAME, true, PRECEDENCE, true);
    }
	 
	protected MyPageAttributeTagProcessor(TemplateMode templateMode, 
			String dialectPrefix, String elementName,
			boolean prefixElementName, 
			String attributeName, 
			boolean prefixAttributeName, 
			int precedence,
			boolean removeAttribute) {
		super(templateMode, dialectPrefix, elementName, 
				prefixElementName, attributeName, prefixAttributeName, 
				precedence,removeAttribute);
	}

	@Override
	protected void doProcess(ITemplateContext context, 
			IProcessableElementTag tag, 
			AttributeName attrName, 
			String attrValue,
			IElementTagStructureHandler handler) {
		
		final IEngineConfiguration configuration = context.getConfiguration();
		final IStandardExpressionParser parser =
				StandardExpressions.getExpressionParser(configuration);
		final IStandardExpression expression = 
				parser.parseExpression(context, attrValue);
		int value = (int)expression.execute(context);
		value = value < 0 ? 0 : value;
		handler.setAttribute("href", "/page?size=" + size + "&page=" + value);
	}

}
```

`AbstractProcessorDialect`には`IProcessor`をまとめたSetを取得する`getProcessors`というメソッドが用意されている
`IProcessor`はThymeleafの属性などの処理を行うクラス
サンプルは`Set`インスタンスを作成して`IProcessor`を組み込んで`return`する処理をしている

【Dialectクラスとして属性としてまとめる】

```java
public class MyDialect extends AbstractProcessorDialect {
	
	private static final String DIALECT_NAME = "My Dialect";
	
	public MyDialect() {
		super(DIALECT_NAME, "my", StandardDialect.PROCESSOR_PRECEDENCE);
	}
	protected MyDialect(String name, String prefix, 
			int processorPrecedence) {
		super(name, prefix, processorPrecedence);
	}

	@Override
	public Set<IProcessor> getProcessors(String dialectPrefix) {
		final Set<IProcessor> processors = new HashSet<IProcessor>();
		processors.add(new MyPageAttributeTagProcessor(dialectPrefix));
		return processors;
	}

}
```

　`AttributeTagProcessor`と`Dialect`を利用するための`Bean`を登録して使う

①templateEngineの作成

　`SpringTemplateEngine`インスタンスの作成後、`setTemplateResolver`でテンプレートリゾルバの設定をする
　これによって`templateResolver`で作成されたテンプレートリゾルバが設定される
　用意できたテンプレートエンジンに作成しているMyDialectのインスタンスを`addDialect`で組み込み、そのテンプレートエンジンを`return`するとレンダリングの際に使用されるようになる

②templateResolverの作成

　`ClassLoaderTemplateResolver`のインスタンスを作成してプレフィックスの設定、キャッシュできるようにするかどうかの設定、サフィックスの設定、テンプレートモード等の設定を行う


【構成クラス】

```java
@Configuration
public class MyBootAppConfig {

	...

    @Bean
	public ClassLoaderTemplateResolver templateResolver() {
		ClassLoaderTemplateResolver templateResolver = 
			new ClassLoaderTemplateResolver();
		templateResolver.setPrefix("templates/");
		templateResolver.setCacheable(false);
		templateResolver.setSuffix(".html");        
		templateResolver.setTemplateMode("HTML5");
		templateResolver.setCharacterEncoding("UTF-8");
		return templateResolver;
	}
 
	@Bean
	public SpringTemplateEngine templateEngine(){
		SpringTemplateEngine templateEngine = new SpringTemplateEngine();
		templateEngine.setTemplateResolver(templateResolver());
		templateEngine.addDialect(new MyDialect());
		return templateEngine;
	}
}

```

【テンプレート】

```html
<div>
<a my:mypage="${datalist.getNumber() - 1}">&lt;&lt;prev</a>
｜
<a my:mypage="${datalist.getNumber() + 1}">next&gt;&gt;</a>
</div>
```

##MongoDBの利用
NoSQLのMongoDBは基本的な使い方は、MongoRepositoryがJpaRepositoryと同じように設計されているので、SQLデータベースとほぼ同じ -> **リポジトリを書いて呼び出す**


#８． SpringToolSuiteリファレンス
割愛

#参考
- [SpringBoot2 プログラミング入門](https://www.amazon.co.jp/Spring-Boot-2-プログラミング入門-掌田津耶乃/dp/4798053473)