第4章 エラー実装をしてみよう

4.2 重複チェックをしよう

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

実行結果

フォルダ構造

【ErrorController.java】(追記)
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;	
	
	⋮
	
@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>
【OrderRepository.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番号を指定して書籍情報を取得するメソッドですが、指定したISBNの値が存在しない可能性も考えられます。その場合はnullになりますが、Optionalクラスを使用することで、Optionalインスタンスとして取得できるようになります。すなわちnullではなくなります。これを使用することでnullだった場合の処理を書く必要がなくなるのでコードの簡略化ができるのです。

NEXT>> 4.3 @ExceptionHandler