Spring Bootで書籍管理Webアプリを作ろう part3

# はじめに

どうも、プログラミング勉強中の大学生、@Ikuto19です。今回は[前回の続き(part2)](https://qiita.com/Ikuto19/items/7422370a3a1d8671e4be)からやっていこうと思います。

# 前回のおさらい
part2では、作成手順1~3までを行いました。今回は作成手順4~5の2つをやろうかなと思います。
以下が今回、新規作成（赤）または修正(青)するものです。
![スクリーンショット 2020-08-25 1.44.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520861/cd6f0b64-a6f4-489f-83a8-518abdfcefc3.png)


# ホーム画面からの画面遷移の実装
ホーム画面となるindex.htmlから、登録・削除を行うoperateCollate.htmlへ画面遷移する仕組みを実装します。

### 新規ファイルの作成・既存ファイルの修正

###### OperateController.java
URLに対応してoperateCollate.htmlを表示します。その際、index.htmlのページのテキストボックスから入力された文字列型のISBNコードをoperateCollate.htmlにModelMapというクラスを用いて渡します。第一引数に変数名、第二引数に渡したい文字列を入れます。個人的にここの変数名は統一すべきだと思っています。

```java:OperateController.java
package com.app.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class OperateController {
	
	@GetMapping("/index")
	public String getIndexPage(Model model) {
		return "index";
	}

	//以下追加するメソッド
	@RequestMapping("/operateCollate")
	public String operateCollate(ModelMap modelMap, @RequestParam("isbn") String isbn) {
		modelMap.addAttribute("isbn", isbn);
		return "operateCollate";
	}
}
```

###### noImage.png
[こちらからダウンロード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520861/fdec788d-41f9-383c-f767-e41476cbbb79.png)
ダウンロード後、「noImage.png」に変更してください。

######  bookInfo.js
この方のプログラムを今回の目的に応じて変更しています。
[openBD の API で ISBN をキーに書誌情報を取得する ( jQuery 使用 )](https://qiita.com/slangsoft/items/c62023d227a9a9f43f8c)

入力されたISBNコードを元に書籍情報をjson形式で取得し、今回は下記の情報のみ取得しています。タイトル・出版社・著者の情報がない場合は "なし" を格納し、表紙がない場合はNo Imageと書かれたpngファイルのurlを格納しています。


* 書籍タイトル → title
* 出版社 → publisher
* 著者 → author
* 表紙 →thumbnail

```js:bookInfo.js
$(function () {
	const isbn = $("#isbn").val();
	const url = "https://api.openbd.jp/v1/get?isbn=" + isbn;

	$.getJSON(url, function (data) {
		var title = 'なし';
		var publisher = 'なし';
		var author = 'なし';
		var thumbnail = '../images/noImage.png';
		
		if (data[0] != null) {
			if (data[0].summary.cover == "") {
				$("#thumbnail_image").html('<img src=\"' + thumbnail + '\" style=\"border:solid 1px #000000\" />');
			} else {
				$("#thumbnail_image").html('<img src=\"' + data[0].summary.cover + '\" style=\"border:solid 1px #000000\" />');
				thumbnail = data[0].summary.cover;
			}

			title = data[0].summary.title;
			publisher = data[0].summary.publisher;
			author = data[0].summary.author;
		}else{
			$("#thumbnail_image").html('<img src=\"' + thumbnail + '\" style=\"border:solid 1px #000000\" />');
		}

		$("#title").val(title);
		$("#publisher").val(publisher);
		$("#author").val(author);
		$("#thumbnail").val(thumbnail);
	});
});
```

###### operateCollate.html
書籍の問い合わせ終了後、取得した情報を表示して登録もしくは削除するページです。

```html:operateCollate.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>

<script th:src="@{/webjars/jquery/3.1.1/jquery.min.js}"></script>
<script type="text/javascript" src="/js/bookInfo.js"
	th:src="@{/js/bookInfo.js}"></script>

<meta charset="UTF-8">
<title>書籍管理アプリ</title>
</head>

<body>
	<div class="main_containerCollate background">
		<form method="get" action="regist">
			<div class="flexbox">
				<div class="">
					<div class="info">
						ISBN：<input id="isbn" class="texts" type="text" name="isbn" th:value="${isbn}"
							autofocus>
					</div>

					<div class="info">
						書籍名：<input id="title" class="texts" type="text" name="title" value="">
					</div>

					<div class="info">
						出版社：<input id="publisher" class="texts" type="text" name="publisher" value="">
					</div>

					<div class="info">
						著者：<input id="author" class="texts" type="text" name="author" value="">
					</div>
				</div>
				<div class="">
					<p id="thumbnail_image"></p>
					<input hidden id="thumbnail" type="text" name="thumbnail" value="">
				</div>
			</div>
			<div class="info">
				<p>上記の書籍について、下記を選択してください.</p>
				<button type="submit" class="submit">登録</button>
				<button type="submit" class="submit" formaction="delete">削除</button>
			</div>
		</form>

		<div class="link">
			<a href="/index">戻る</a>
		</div>
	</div>
</body>
</html>
```

###### pom.xml
下記の依存関係を追加します。jQueryを使うためのライブラリです。

```xml:pom.xml
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jquery</artifactId>
	<version>3.1.1</version>
</dependency>
```

# データベースへの登録と削除の実装

###### OperateController.java
下記のフィールド変数とメソッドをOperateController.javaに追加

* フィールド: isbnRepository →　リポジトリ
* メソッド: regist() → データベースへの登録メソッド
* メソッド： delete() → データベースの削除メソッド

取得した情報をISBNオブジェクトにセットし、DatabaseClassクラスを使って表示するメッセージを取得している。

```java:OperateController.java
package com.app.controller;

import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.app.database.DatabaseClass;
import com.app.entity.ISBN;
import com.app.repository.ISBNRepository;

@Controller
public class OperateController {
	@Autowired
	ISBNRepository isbnRepository;
	
	@RequestMapping("/operateCollate")
	public String operateCollate(ModelMap modelMap, @RequestParam("isbn") String isbn) {
		modelMap.addAttribute("isbn", isbn);
		return "operateCollate";
	}
	
	@RequestMapping("regist")
	public String regist(ModelMap modelMap, @RequestParam("isbn") String isbn,
			@RequestParam("title") String title, @RequestParam("publisher") String publisher,
			@RequestParam("author") String author, @RequestParam("thumbnail") String thumbnail) throws SQLException {
		
		ISBN isbnInfo = new ISBN();
		isbnInfo.setIsbn(isbn);
		isbnInfo.setTitle(title);
		isbnInfo.setPublisher(publisher);
		isbnInfo.setAuthor(author);
		isbnInfo.setThumbnail(thumbnail.replace("https://cover.openbd.jp/", ""));
		
		DatabaseClass dc = new DatabaseClass(isbnRepository.findAll());
		String message = dc.registDB(isbnInfo,isbnRepository);
		modelMap.addAttribute("message",message);
		
		return "regist";
	}

	@RequestMapping("delete")
	public String delete(ModelMap modelMap, @RequestParam("isbn") String isbn,
			@RequestParam("title") String title, @RequestParam("publisher") String publisher,
			@RequestParam("author") String author, @RequestParam("thumbnail") String thumbnail) throws SQLException {
		
		ISBN isbnInfo = new ISBN();
		isbnInfo.setIsbn(isbn);
		isbnInfo.setTitle(title);
		isbnInfo.setPublisher(publisher);
		isbnInfo.setAuthor(author);
		isbnInfo.setThumbnail(thumbnail.replace("https://cover.openbd.jp/", ""));
		
		DatabaseClass dc = new DatabaseClass(isbnRepository.findAll());
		String message = dc.deleteDB(isbnInfo,isbnRepository);
		modelMap.addAttribute("message",message);
		
		return "delete";
	}
}

```

###### DatabaseClass.java
データの型の加工や状況によって変わるメッセージの生成を行うクラス。

* registDB()メソッド → データベースと比較して登録と登録用メッセージの生成
* deleteDB()メソッド → データベースと比較して削除と削除用メッセージの生成
* convertStrings（）メソッド → ISBNオブジェクトを文字列のISBNコードとして変換

```java:DatabaseClass.java
package com.app.database;
(import文の省略)
public class DatabaseClass {
	private List<ISBN> manageBookDB;
	
	public DatabaseClass(List<ISBN> manageBookDB) {
		this.manageBookDB = manageBookDB;
	}

	public String registDB(ISBN isbnInfo, ISBNRepository isbnRepository) throws SQLException {
		String message = null;
		
		if(isbnInfo.getTitle().equals("なし") || isbnInfo.getPublisher().equals("なし") || isbnInfo.getAuthor().equals("なし")){
			message = "書籍情報を取得できなかったので、登録できませんでした.";
		}else if(convertStrings(manageBookDB).contains(isbnInfo.getIsbn())) {
			message = "すでにデータベースに存在します.";
		} else {
			message = "新しくデータベースに登録しました.";
			isbnRepository.save(isbnInfo);
		}
		return message;
	}

	public String deleteDB(ISBN isbnInfo, ISBNRepository isbnRepository) throws SQLException {
		String message = null;
		
		if(convertStrings(manageBookDB).contains(isbnInfo.getIsbn())) {
			message = "データベースから削除しました.";
			isbnRepository.delete(isbnInfo);
		}else {
			message = "データベースに存在しません.";
		}
		return message;
	}

	public List<String> convertStrings(List<ISBN> manageBook){
		List<String> isbnList = new ArrayList<String>();
		for(ISBN isbn:manageBook) {
			isbnList.add(isbn.getIsbn());
		}
		return isbnList;
	}

}
```

###### ISBN.java
LoginUser.javaと同じエンティティクラス。

```java:ISBN.java
package com.app.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "isbn_code")
public class ISBN {
	
	@Id
	@Column(name = "isbn")
	private String isbn;

	@Column(name = "title")
	private String title;

	@Column(name = "publisher")
	private String publisher;

	@Column(name = "author")
	private String author;

	@Column(name = "thumbnail")
	private String thumbnail;

	public String getIsbn() {
		return isbn;
	}
	
	public void setIsbn(String isbn) {
		this.isbn = isbn;
	}
	
	public String getTitle() {
		return title;
	}
	
	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getPublisher() {
		return publisher;
	}
	
	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}
	
	public String getAuthor() {
		return author;
	}
	
	public void setAuthor(String author) {
		this.author = author;
	}
	
	public String getThumbnail() {
		return thumbnail;
	}
	
	public void setThumbnail(String thumbnail) {
		this.thumbnail = thumbnail;
	}

}
```

###### ISBNRepository.java
```java:ISBNRepository.java
package com.app.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.app.entity.ISBN;

@Repository
public interface ISBNRepository extends JpaRepository<ISBN, String>{}

```

###### delete.html
削除を行うページ。

```html.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>削除ページ</title>
</head>
<body>
	<div class="main_container do">
		<div class=title>
			<h1>書籍削除</h1>
		</div>
		<div class="message">
			<p th:text="${message}"></p>
		</div>
		<div>
			<a href="index">戻る</a>
		</div>
	</div>
</body>
</html>
```

###### regist.html
登録を行うページ。

```html:regist.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登録ページ</title>
</head>
<body>
	<div class="main_container do">
		<div class=title>
			<h1>書籍登録</h1>
		</div>
		<div class="message">
			<p th:text="${message}"></p>
		</div>
		<div>
			<a href="index">戻る</a>
		</div>
	</div>
</body>
</html>
```

# 書籍情報データベースの構築
以下のコマンドで書籍情報を保存するテーブルを作成します。テーブル名はエンティティクラスであるISBN.javaの```@Table(name = "〇〇")```の〇〇と同じにします。今回はisbn_codeというテーブル名にしました。

```terminal
$ mysql -u (mysqlのユーザー名) -p
Enter password: (mysqlのパスワード)
mysql> use manageBook
mysql> create table isbn_code(,isbn varchar(256),title varchar(256),publisher varchar(256),author varchar(256),thumbnail varchar(256));
```

# 動作確認
http://localhost:8080/login にアクセス後、前回設定したログイン用のusernameとpasswordを入力してください。ISBNコードを入力して登録ボタンや削除ボタンを押すとデータベースから登録または削除ができるかと思います。データベースを確認する際は以下のコマンドで確認してください。

```terminal
$ mysql -u (mysqlのユーザー名) -p
Enter password: (mysqlのパスワード)
mysql> create database manageBook;
mysql> use manageBook
mysql> select * from isbn_code;
```

# 終わりに
今回はここまでにします。今回で最後と書いたのですが、長くなりそうなので分割しました。次回が本当に最後で、残りの部分(herokuの設定やデプロイなど)を作っていこうと思います。

次回へ続く(part final) > 近々投稿

# 参考サイト
[openBD の API で ISBN をキーに書誌情報を取得する ( jQuery 使用 )](https://qiita.com/slangsoft/items/c62023d227a9a9f43f8c)