第4章 エラー実装をしてみよう
4.2 重複チェックをしよう
重複チェックとは、これから挿入しようとしているデータが、既にデータベースに登録されていないか確認するエラー処理になります。今まで作成してきた書籍管理システムであれば、書籍登録時に重複チェックを実装する必要があります。
実行結果

フォルダ構造

【ErrorController.java】(追記)
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import jp.co.f1.spring.repository.BookRepository;
⋮
@Autowired
private BookRepository bookinfo;
⋮
/**
* 「/check2」へGET送信された場合
*/
@GetMapping("/check2")
// POSTデータをBookインスタンスとして受け取る
public ModelAndView check2(@ModelAttribute Book book, ModelAndView mav) {
// 画面に出力するViewを指定
mav.setViewName("checkForm2");
// ModelとView情報を返す
return mav;
}
/**
* 「/check2」へPOST送信された場合
*/
@PostMapping("/check2")
// POSTデータをBookインスタンスとして受け取る
public ModelAndView check2(@ModelAttribute @Validated(Book.All.class) Book book, BindingResult result, ModelAndView mav) {
Optional < Book > optional_book = bookinfo.findByIsbn(book.getIsbn());
if(optional_book.isPresent()) {
mav.addObject("message", "入力ISBNは既にDBに存在します。");
// 画面に出力するViewを指定
mav.setViewName("checkForm2");
} else {
// 画面に出力するViewを指定
mav.setViewName("checkResult2");
}
return mav;
}
【checkForm2.html】
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>重複チェックをしてみよう</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div id="main" class="container">
<!-- エラーメッセージ -->
<p class="error-msg" th:if="${message} != null" th:text="${message}"></p>
<!-- 入力フォーム -->
<form action="/check2" method="POST" th:object="${book}">
<table class="input-table" align="center">
<tr>
<th>ISBN</th>
<td>
<input type="text" name="isbn" th:value="*{isbn}" th:errorclass="error-msg">
<p th:if="${#fields.hasErrors('isbn')}" th:errors="*{isbn}" th:errorclass="error-msg"></p>
</td>
</tr>
</table>
<input type="submit" value="確認">
</form>
</div>
</body>
</html>
【checkResult2.html】
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>重複チェックをしてみよう</title> </head> <body> <p>入力ISBNはDBに存在しませんでした。</p> </body> </html>
【BookRepository.java】(書き換え)
package jp.co.f1.spring.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import jp.co.f1.spring.entity.Book;
@Repository
public interface BookRepository extends JpaRepository < Book, String > {
public Optional < Book > findByIsbn(String isbn);
}
アプリケーションにアクセス
以下のアドレスからアプリケーションにアクセスします。
URL:http://localhost:8080/check2
解説
findByIsbnメソッドは、引数で渡されたISBN番号を元にデータベース上のデータを検索するメソッドです。戻り値はOptionalクラス型です。Optionalクラスについては後ほど解説します。
今回はfindByIsbnメソッドの引数に、画面で入力したISBN番号を渡しています。これで、findByIsbnメソッドはISBN番号を元にデータベース上で検索し、それに伴う結果を返してくれます。結果は呼び出し元に戻り、optional_book変数に格納されます。
Optional<Book> optional_book = bookinfo.findByIsbn(book.getIsbn());
その戻り値をisPresentメソッドを使用して中に値が格納されているのかチェックしています。もし『中身が何もない=データベース上にデータが存在しない』場合は、isPresentメソッドはfalseを返します。逆に『中身がある=データベースにデータが存在する』場合はisPresentメソッドはtrueを返します。これをif文の条件式に利用しています。
if (optional_book.isPresent()) {
Optionalクラス型は簡単にいうと、『nullの可能性があるオブジェクトをラップするためのクラス』です。findByIsbnメソッドのように、指定されたISBNに一致する書籍情報が存在しない可能性がある場合、Optionalを使用することで、値の存在チェックをより安全に扱うことができます。Optionalを使用しない場合、findByIsbnメソッドが書籍情報を見つけられなかった際にnullを返す可能性があります。よって、NullPointerExceptionが発生したり、そのための例外処理を記述する必要があります。Optionalを使用することで、findByIsbnメソッドは nullではなくOptionalオブジェクトを返します。これにより、findByIsbnの呼び出し側は、Optionalオブジェクトに対してisPresent()メソッドを呼び出すことで書籍情報が存在するかどうかを安全に確認できます。このように、Optionalを使用することで、nullチェックを明示的に行う必要がなくなり、より安全で可読性の高いコードを記述できます。