7月9日

投稿者: | 2020年7月9日

MyDataを編集(CRUDのUpadate)するための機能を追加する。

テンプレートに編集用のフラグメントを追加する。

<div th:fragment="edit">
  <form action="/edit" method="post" th:object="${mydata}">
    <table>
      <tr>
        <td>名前</td>
        <td><input type="text" name="name" th:value="*{name}" /></td>
      </tr>
      <tr>
        <td>年齢</td>
        <td><input type="text" name="age" th:value="*{age}" /></td>
      </tr>
      <tr>
        <td>メール</td>
        <td><input type="text" name="mail" th:value="*{mail}" /></td>
      </tr>
      <tr>
        <td>メモ</td>
        <td><textarea rows="5" cols="20" name="memo" th:text="*{memo}"></textarea></td>
      </tr>
      <tr>
        <td></td><td><input type="submit" value="送信" /></td>
      </tr>
    </table>
  </form>
</div>

MyDataRepository に findById() を追加する。

package jp.abc;

import java.util.Optional;

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

public interface MyDataRepository extends JpaRepository<MyData, Long> {
	public Optional<MyData> findById(long id);
}

コントローラで MyData を取得してテンプレートに渡す。

	@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
	public ModelAndView edit(
			@ModelAttribute("mydata") MyData mydata,
			@PathVariable long id,
			ModelAndView mav) {
		Optional<MyData> data = myDataRepository.findById(id);
		MyData myData = data.get();
		mav.addObject("mydata", myData);
		mav.addObject("template", "mydata");
		mav.addObject("fragment", "edit");
		mav.setViewName("layout");
		return mav;
	}

POSTメソッドを受け取れるようにコントローラを修正する。

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	public ModelAndView update(
			@ModelAttribute("mydata") MyData mydata,
			ModelAndView mav) {
		return new ModelAndView("redirect:/");
	}

テンプレートに id のデータを持つための input を追加する。

<div th:fragment="edit">
  <form action="/edit" method="post" th:object="${mydata}">
    <input type="hidden" name="id" th:value="*{id}" />
    <table>
      <tr>
        <td>名前</td>
        <td><input type="text" name="name" th:value="*{name}" /></td>
      </tr>

コントローラにデータベースを更新する処理を追加する。

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	public ModelAndView update(
			@ModelAttribute("mydata") MyData mydata,
			ModelAndView mav) {
		myDataRepository.saveAndFlush(mydata);
		return new ModelAndView("redirect:/");
	}

CRUD のうち、Create/Read/Update ができたので、次は Delete を実装する。
まずは、削除するためのリンクを用意する。

<table>
  <tr>
    <th>ID</th>
    <th>名前</th>
    <th>メール</th>
    <th>年齢</th>
    <th>操作</th>
  </tr>
  <tr th:each="mydata : ${list}">
    <td th:text="${mydata.id}"></td>
    <td th:text="${mydata.name}"></td>
    <td th:text="${mydata.mail}"></td>
    <td th:text="${mydata.age}"></td>
    <td>
      <a th:href="@{'/edit/' + ${mydata.id}}">編集</a>
      <a th:href="@{'/delete/' + ${mydata.id}}">削除</a>
    </td>
  </tr>
</table>

サーバー側で用意してないので、削除をクリックすると404エラーになる。
コントローラを修正して、/delete/{id} を受け付けるようにする。

	@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
	public ModelAndView delete(
			@ModelAttribute("mydata") MyData mydata,
			@PathVariable long id,
			ModelAndView mav) {
		Optional<MyData> data = myDataRepository.findById(id);
		MyData myData = data.get();
		mav.addObject("mydata", myData);
		mav.addObject("template", "mydata");
		mav.addObject("fragment", "delete");
		mav.setViewName("layout");
		return mav;
	}

delete用のフラグメントを用意する。
mydata.html に以下の2行を追加する。

<div th:fragment="delete">
</div>

フラグメント内に削除するデータの内容を表示する。

<div th:fragment="delete">
  <p>このデータを削除しますか?</p>
  <form action="/delete" method="post" th:object="${mydata}">
    <input type="hidden" name="id" th:value="*{id}" />
    <table>
      <tr>
        <td>名前</td>
        <td th:text="*{name}"></td>
      </tr>
      <tr>
        <td>年齢</td>
        <td th:text="*{age}"></td>
      </tr>
      <tr>
        <td>メール</td>
        <td th:text="*{mail}"></td>
      </tr>
      <tr>
        <td>メモ</td>
        <td><textarea rows="5" cols="20" name="memo" th:text="*{memo}" readonly></textarea></td>
      </tr>
      <tr>
        <td></td><td><input type="submit" value="削除" /></td>
      </tr>
    </table>
  </form>
</div>

コントローラに /delete に対する POST メソッドを受け付けるメソッドを追加する。

	@RequestMapping(value = "/delete", method = RequestMethod.POST)
	public ModelAndView remove(
			@RequestParam long id,
			ModelAndView mav) {
		myDataRepository.deleteById(id);
		return new ModelAndView("redirect:/");
	}

現状は、名前などが空欄だったり、不正なメールアドレスでも登録できてしまうので、あまりよろしくない。
入力チェックを追加する。
そのための仕組みがバリデーションと呼ばれている。
まずバリデーションを行うためのライブラリを追加する。

pom.xml に以下の内容を追加する。

		<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-validator</artifactId>
		    <version>6.1.5.Final</version>
		</dependency>

MyData にバリデーションのためのアノテーションを追加する。

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Email;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;

import com.sun.istack.NotNull;

@Entity // my_dataテーブルと関連付けられる
public class MyData {
	@Id
	@Column
	@GeneratedValue
	@NotNull
	private long id;

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

	@Column(length = 100, nullable = false)
	@Email
	private String mail;

	@Column
	@Min(0)
	private int age;

	@Column(nullable = true)
	private String memo;

	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getMail() {
		return mail;
	}
	public void setMail(String mail) {
		this.mail = mail;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getMemo() {
		return memo;
	}
	public void setMemo(String memo) {
		this.memo = memo;
	}
}

コントローラにバリデーションに対応するためのコードを追加する。

	@RequestMapping(value = "/", method = RequestMethod.POST)
	public ModelAndView post(
			@ModelAttribute("mydata") @Validated MyData mydata,
			BindingResult result,
			ModelAndView mav) {
		if (result.hasErrors()) {
			List<MyData> list = myDataRepository.findAll();
			mav.addObject("list", list);
			mav.addObject("template", "mydata");
			mav.addObject("fragment", "mydata");
			mav.setViewName("layout");
			mav.addObject("msg", "validation error");
			return mav;
		}
		myDataRepository.saveAndFlush(mydata);
		return new ModelAndView("redirect:/");
	}

テンプレートにメッセージを表示する要素を追加する。

<div th:fragment="mydata">
<h1>MyData</h1>
<p>MyDataフラグメント</p>
<p th:text="${msg}"></p>
<form action="/" method="post" th:object="${mydata}">

<table>

エラーメッセージを表示する。

<div th:fragment="mydata">
<h1>MyData</h1>
<p>MyDataフラグメント</p>
<p th:text="${msg}"></p>
<form action="/" method="post" th:object="${mydata}">

<ul>
  <li th:each="error : ${#fields.detailedErrors()}" th:text="${error.message}"></li>
</ul>

<table>