SpringBoot + BootStrap + DataTablesで選択画面を作成する

##選択ボタンで検索画面をモーダル表示して検索結果を親画面に反映するケースを検討します。

1.説明
(1) 解説
画面の入力では、マスタを検索して対象を選択するようなケースがあります。このような場合において、BootStrapのモーダルダイアログの機能と、DataTablesの一覧表示機能を使って実装する方法を検討します。

(2)全体イメージ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/82b63def-b7da-ce3b-3535-4d22e4cf2bd4.png)
フォーム上のボタンを押して、モーダルウィンドウを表示します。一覧から対象のデータを選択するとフォームに選択したデータが入力された状態にします。
BootStrapのモーダルウィンドウを使います。

(3)モーダルダイアログの概念図
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/36a8c54c-b6ce-a92d-99d9-f77fae34527f.png)

モーダルダイアログはjQuery DataTablesを使います。データは、Ajaxプロパティに、RestControllerからデータの一覧を返すという仕組みにします。ここでは、ユーザマスタ(Account)としています。

2.プロジェクトの構成

```
sample-modal
│  build.gradle
└─src
    └─main
        ├─java
        │  └─com
        │      └─stone
        │          └─ccc
        │                  Account.java
        │                  AccountRepository.java
        │                  DataTablesRestController.java
        │                  HeloController.java
        │                  SampleModalApplication.java
        │                  ServletInitializer.java
        └─resources
            │  application.properties
            │  hibernate.properties
            ├─static
            │  └─DataTables-1.10.16
            │      │  Japanese.json
            │      │  
            │      ├─css
            │      │      dataTables.bootstrap.min.css
            │      │      dataTables.bootstrap4.min.css
            │      │      dataTables.jqueryui.min.css
            │      │      jquery.dataTables.min.css
            │      └─js
            │              dataTables.bootstrap.min.js
            │              dataTables.bootstrap4.min.js
            │              dataTables.jqueryui.min.js
            │              jquery.dataTables.min.js
            └─templates
                    index.html
                    modalempselect.html
```

jQuery DataTablesのcss, jsをstaticの下に配置します。
index.htmlが親画面
modalempselectがモーダルになっています。

3.依存関係

```build.gradle
dependencies {
	compile('org.springframework.boot:spring-boot-starter-data-jpa')
	compile('org.springframework.boot:spring-boot-starter-thymeleaf')
	compile('org.springframework.boot:spring-boot-starter-web')
	compile('org.apache.commons:commons-lang3:3.7')
	compile('org.webjars:jquery:3.2.1')
	compile('org.webjars:jquery-ui:1.12.1')
	compile('org.webjars:bootstrap:4.0.0')
	compile('com.fasterxml.jackson.datatype:jackson-datatype-jsr310')
	runtime('org.springframework.boot:spring-boot-devtools')
	runtime('org.postgresql:postgresql')
	compileOnly('org.projectlombok:lombok')
	providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
	testCompile('org.springframework.boot:spring-boot-starter-test')
}
```

4.ＤＢ接続設定

```application.properties
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
spring.datasource.username=testuser
spring.datasource.password=testuser
spring.jpa.hibernate.ddl-auto=none
```
DBは、postgresqlを使います。

```hibernate.properties
hibernate.jdbc.lob.non_contextual_creation = true
```
postgresqlを使った場合にエラーが発生するのでこのpropertyを設定しておきます。

5.DB

```account.sql
create table account (
  username character varying(64) not null
  , password character varying(255)
  , email character varying(64)
  , authority character varying(64)
  , primary key (username)
);
```

```account_insert.sql
insert into account(username,password,email,authority)
values 
('admin','admin','admin@localhost','ROLE_ADMIN')
,('user','pass','user@localhost','ROLE_USER');
```


6.Entity

```Account.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "account")
public class Account {
	@Id
	@Column(name="username")
	private String username;
	@Column(name="email")
	private String email;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
}
```

7.Repository

```AccountRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
public interface AccountRepository extends JpaRepository<Account, String> {}
```

7.RestController

```
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DataTablesRestController {
	@Autowired
	AccountRepository Repo;
	@RequestMapping("/getaccountlist")
	public List<Account> getuserlist() {
		return Repo.findAll();
	}
}
```
jQuery DataTablesのajaxパラメータに渡すJsonの配列です。

8.Controller

```HeloController.java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class HeloController {
	@RequestMapping(value = "/", method = RequestMethod.GET)
    public String index(Model model) {
        return "index";
    }
}
```

9.html
(1)フォーム

```index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
	<head>
		<title>モーダルダイアログ　サンプル</title>
		<meta charset="utf-8" />
		<link th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.min.css}" rel="stylesheet" />
		<script type="text/javascript" th:src="@{/webjars/jquery/3.2.1/jquery.min.js}"></script>
		<script type="text/javascript" th:src="@{/webjars/bootstrap/4.0.0/js/bootstrap.min.js}"></script>
		<link rel="stylesheet" th:href="@{/DataTables-1.10.16/css/jquery.dataTables.min.css}"/>
		<link rel="stylesheet" th:href="@{/DataTables-1.10.16/css/dataTables.bootstrap4.min.css}"/>
		<script type="text/javascript" th:src="@{/webjars/jquery-ui/1.12.1/jquery-ui.min.js}"></script>
		<script type="text/javascript" th:src="@{/DataTables-1.10.16/js/jquery.dataTables.min.js}"></script>
		<script type="text/javascript" th:src="@{/DataTables-1.10.16/js/dataTables.bootstrap4.min.js}"></script>
	</head>
	<body>
		<div class="container">
			<h2>モーダルダイアログ　サンプル</h2>
			<div class="form-group">
				<label class="col-sm-2">username:</label>
				<input type="text" id="username" size="10"/>
			</div>
			<div class="form-group">
				<label class="col-sm-2">email:</label>
				<input type="text" id="email" size="20"/>
				<a class="form-control-sm bg-primary" id="empchange"
					data-toggle="modal" data-target="#modal-emp-select">選択</a>
			</div>
		</div>
		<div th:replace="modalempselect::modalempselect"></div>
		<script th:inline="javascript">
		/*<![CDATA[*/
			$(document).on("click","#btn-modalemp-select", function() {
				$('#username').val(modalempdata.username);
				$('#email').val(modalempdata.email);
				$('#modal-emp-select').modal('hide');
			});
		/*]]>*/
		</script>
	</body>
</html>
```

point

```
<a class="form-control-sm bg-primary" id="empchange"
					data-toggle="modal" data-target="#modal-emp-select">選択</a>
```

data-toggle="modal" data-target="#modal-emp-select"とするだけで、クリックしたらmodalが開きます。

(2)モーダル

```modalempselect.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
	<head>
		<title>モーダルダイアログ　サンプル</title>
		<meta charset="utf-8" />
	</head>
	<body>
	<div th:fragment="modalempselect">
	<!-- モーダルの設定 -->
	<div class="modal" id="modal-emp-select" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
		<div class="modal-dialog modal-lg" role="document">
			<div class="modal-content">
				<div class="modal-header">
					<h6 class="modal-title">従業員選択画面</h6>
					<button type="button" class="close" data-dismiss="modal" aria-label="閉じる">
						<span aria-hidden="true">&times;</span>
					</button>
				</div>
				<div class="modal-body">
					<table id="modal-emplist-table" class="table table-bordered table-hover table-lg">
						<thead class="thead-light">
							<tr>
								<th>従業員番号</th>
								<th>氏名</th>
							</tr>
						</thead>
						<tbody>
						</tbody>
					</table>
					<script th:inline="javascript">
					/*<![CDATA[*/
						var modalempdata = null;
						$(function(){
						    // datatableの設定を変更
							var modalemptable = $("#modal-emplist-table").DataTable({
								"bPaginate": true,
								"bLengthChange": false,
								"bFilter": true,
								"bSort": false,
								"bInfo": false,
								"bAutoWidth": false,
								"language": {
									"url": /*[[@{/DataTables-1.10.16/Japanese.json}]]*/ 'Japanese.json'
								},
								"ajax": { url: /*[[@{/getaccountlist}]]*/ 'getaccountlist', dataSrc: '' },
								"columns": [
									{ data: "username" },
									{ data: "email" },
								],
								"columnDefs": [
									{ targets: 0, width: 60 },
									{ targets: 1, width: 180 },
									{targets:'_all',className : 'dt-head-center'},
								]
							});
							//一覧をクリックした
							$('#modal-emplist-table tbody').on("click", "tr", function() {
								if ($(this).find('.dataTables_empty').length == 0) {
									if ( $(this).hasClass('selected') ) {
										$(this).removeClass('selected');
									} else {
										modalemptable.$('tr.selected').removeClass('selected');
										$(this).addClass('selected');
									}
									modalempdata=$('#modal-emplist-table').dataTable().fnGetData(this);
								}
							});
						})
					/*]]>*/
					</script>
	      </div>
	      <div class="modal-footer">
	        <button type="button" class="btn btn-primary" id="btn-modalemp-select">選択</button>
	        <button type="button" class="btn btn-primary" data-dismiss="modal">キャンセル</button>
	      </div><!-- /.modal-footer -->
	    </div><!-- /.modal-content -->
	  </div><!-- /.modal-dialog -->
	</div><!-- /.modal -->
</div>
	</body>
</html>
```

thymeleafのfragmentを使ってます

10.実行してみます
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/ca2cd79b-dfb2-1147-ce0f-7b4424834ca6.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/404f3880-6868-3cd1-e620-57ed206e2a06.png)
↓　選択ボタンを押して
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/a83d8b36-65dd-7ffa-33a6-fee772456673.png)
↓　行を選択してモーダルの選択ボタンを押します
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/5d7a2d33-a605-27d3-9b05-a2867728b8ab.png)

できました。