7月30日

投稿者: | 2020年7月30日

MusicPlayerのCRUDを作っていく。

Create部分を作成する。

musicplayerテンプレートに、登録用のフォームを作成する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>MusicPlayer</title>
</head>
<body>

<div th:fragment="musicplayer">
<h1>MusicPlayer</h1>
<p>MusicPlayerフラグメント</p>
<p th:text="${msg}"></p>

<form action="/" method="post" th:object="${album}">

<table>
	<tr>
		<th>タイトル</th>
		<td><input type="text" name="title" th:value="*{title}" /></td>
	</tr>
	<tr>
		<th>アーティスト</th>
		<td><input type="text" name="artist" th:value="*{artist}" /></td>
	</tr>
	<tr>
		<th></th>
		<td><input type="submit" value="登録" /></td>
	</tr>
</table>

</form>

<table>
  <tr><th>ID</th><th>タイトル</th><th>アーティスト</th></tr>
  <tr th:each="album : ${list}">
    <td th:text="${album.id}"></td>
    <td th:text="${album.title}"></td>
    <td th:text="${album.artist}"></td>
  </tr>
</table>

</div>

</body>
</html>

再起動してアクセスすると500エラーが発生した。
musicplayerテンプレートの19行目でエラー。
titleを参照しようとしたが、th:objectで指定した名前に対応する値が存在しないためにエラーになっている。

コントローラでalbumを作ってModelAndViewに渡す。

package jp.abc;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {
	@Autowired
	AlbumRepository repository;

    @RequestMapping("/")
    public ModelAndView index(ModelAndView mav) {
    	List<Album> list = repository.findAll();
    	Album album = new Album();
    	mav.addObject("album", album);
    	mav.addObject("list", list);
        mav.addObject("template", "musicplayer");
        mav.addObject("fragment", "musicplayer");
        mav.setViewName("layout");
        return mav;
    }
}

コントローラでGETとPOSTを別々のメソッドで受け取るようにする。

package jp.abc;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {
	@Autowired
	AlbumRepository repository;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView index(
    		@ModelAttribute("album") Album album,
    		ModelAndView mav) {
    	List<Album> list = repository.findAll();
    	mav.addObject("album", album);
    	mav.addObject("list", list);
        mav.addObject("template", "musicplayer");
        mav.addObject("fragment", "musicplayer");
        mav.setViewName("layout");
        return mav;
    }

    @RequestMapping(value = "/", method = RequestMethod.POST)
    public ModelAndView post(
    		@ModelAttribute("album") Album album,
    		ModelAndView mav) {
    	repository.saveAndFlush(album);
    	return new ModelAndView("redirect:/");
    }
}

CRUC の Update 機能を追加する。
HTMLテンプレートに編集用のリンクを追加する。
編集用のフラグメントを追加する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>MusicPlayer</title>
</head>
<body>

<div th:fragment="musicplayer">
<h1>MusicPlayer</h1>
<p>MusicPlayerフラグメント</p>
<p th:text="${msg}"></p>

<form action="/" method="post" th:object="${album}">

<table>
	<tr>
		<th>タイトル</th>
		<td><input type="text" name="title" th:value="*{title}" /></td>
	</tr>
	<tr>
		<th>アーティスト</th>
		<td><input type="text" name="artist" th:value="*{artist}" /></td>
	</tr>
	<tr>
		<th></th>
		<td><input type="submit" value="登録" /></td>
	</tr>
</table>

</form>

<table>
  <tr>
    <th>ID</th>
    <th>タイトル</th>
    <th>アーティスト</th>
    <th>操作</th>
  </tr>
  <tr th:each="album : ${list}">
    <td th:text="${album.id}"></td>
    <td th:text="${album.title}"></td>
    <td th:text="${album.artist}"></td>
    <td><a th:href="@{'/edit/' + ${album.id}}">編集</a></td>
  </tr>
</table>

</div>

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

</body>
</html>

編集用の edit フラグメントの中身は、登録用のformをコピーして、action のURLだけを変更する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>MusicPlayer</title>
</head>
<body>

<div th:fragment="musicplayer">
<h1>MusicPlayer</h1>
<p>MusicPlayerフラグメント</p>
<p th:text="${msg}"></p>

<form action="/" method="post" th:object="${album}">

<table>
	<tr>
		<th>タイトル</th>
		<td><input type="text" name="title" th:value="*{title}" /></td>
	</tr>
	<tr>
		<th>アーティスト</th>
		<td><input type="text" name="artist" th:value="*{artist}" /></td>
	</tr>
	<tr>
		<th></th>
		<td><input type="submit" value="登録" /></td>
	</tr>
</table>

</form>

<table>
  <tr>
    <th>ID</th>
    <th>タイトル</th>
    <th>アーティスト</th>
    <th>操作</th>
  </tr>
  <tr th:each="album : ${list}">
    <td th:text="${album.id}"></td>
    <td th:text="${album.title}"></td>
    <td th:text="${album.artist}"></td>
    <td><a th:href="@{'/edit/' + ${album.id}}">編集</a></td>
  </tr>
</table>

</div>

<div th:fragment="edit">

<form action="/edit" method="post" th:object="${album}">

<table>
	<tr>
		<th>タイトル</th>
		<td><input type="text" name="title" th:value="*{title}" /></td>
	</tr>
	<tr>
		<th>アーティスト</th>
		<td><input type="text" name="artist" th:value="*{artist}" /></td>
	</tr>
	<tr>
		<th></th>
		<td><input type="submit" value="登録" /></td>
	</tr>
</table>

</form>

</div>

</body>
</html>

AlbumRepository に findById() を追加する。

package jp.abc;

import java.util.Optional;

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

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

コントローラで /edit を受け付けるようにする。

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

入力フォームにはIDがないので、どのデータを更新していいのかわからない。
hiddenでidを追加する。

<div th:fragment="edit">

<form action="/edit" method="post" th:object="${album}">
<input type="hidden" name="id" th:value="*{id}" />
<table>

コントローラでPOSTメソッドを受け付けるようにする。

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

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

musicplayer.html

<table>
  <tr>
    <th>ID</th>
    <th>タイトル</th>
    <th>アーティスト</th>
    <th>操作</th>
  </tr>
  <tr th:each="album : ${list}">
    <td th:text="${album.id}"></td>
    <td th:text="${album.title}"></td>
    <td th:text="${album.artist}"></td>
    <td>
      <a th:href="@{'/edit/' + ${album.id}}">編集</a>
      <a th:href="@{'/delete/' + ${album.id}}">削除</a>
    </td>
  </tr>
</table>

コントローラに /delete へのリクエストを受け取るためのメソッドを用意する。
edit() とほぼ同じなので、コピーしてurlとメソッド名を変更する。

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

フラグメントはeditのままなので、このまま動作させると、削除のリンクをクリックすると、編集用の画面が表示される。

削除用のフラグメントを追加する。

musicplayer.html

<div th:fragment="delete">
  <p>このデータを削除しますか?</p>
  <form action="/delete" method="post" th:object="${album}">
    <input type="hidden" name="id" th:value="*{id}" />
    <table>
      <tr>
        <td>タイトル</td>
        <td th:text="*{title}"></td>
      </tr>
      <tr>
        <td>アーティスト</td>
        <td th:text="*{artist}"></td>
      </tr>
      <tr>
        <td></td><td><input type="submit" value="削除" /></td>
      </tr>
    </table>
  </form>
</div>

削除用のフラグメントを追加したので、コントローラで削除用のフラグメントを使うように修正する。

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

コントローラに削除のPOSTメソッドを受け取るためのメソッドを追加する。

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