8月26日

BookshelfとBookを連携する

src/main/java/
└jp.abc
 └Bookshelf.java

package jp.abc;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Bookshelf {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

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

	@OneToMany
	private List<Book> books;

	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 List<Book> getBooks() {
		return books;
	}

	public void setBooks(List<Book> books) {
		this.books = books;
	}
}

src/main/java/
└jp.abc
 └Book.java

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Book {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String title;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String author;

	@ManyToOne
	private Bookshelf bookshelf;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public Bookshelf getBookshelf() {
		return bookshelf;
	}

	public void setBookshelf(Bookshelf bookshelf) {
		this.bookshelf = bookshelf;
	}

}

HTMLテンプレートを修正する。

src/main/resources/
└templates
 └book.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Book</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>
<h1>Book</h1>
<p th:text="${msg}"></p>
<form method="post" action="/book" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td>
        <input type="text" name="title" th:value="*{title}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('title')}" th:errors="*{title}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="author">著者</label></td>
      <td>
        <input type="text" name="author" th:value="*{author}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('author')}" th:errors="*{author}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="bookshelf">本棚</label></td>
      <td>
        <input type="text" name="bookshelf" th:value="*{bookshelf}"
                th:errorclass="err"/>
        <div th:if="${#fields.hasErrors('bookshelf')}" th:errors="*{bookshelf}"
            th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>タイトル</th><th>著者</th><th>本棚</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.title}"></td>
    <td th:text="${obj.author}"></td>
    <td th:if="${obj.bookshelf != null}" th:text="${obj.bookshelf.name}"></td>
    <td th:if="${obj.bookshelf == null}" th:text="本棚なし"></td>
  </tr>
</table>

</body>
</html>

本を編集できるようにする

HTMLテンプレートを用意する。

src/main/resources/
└templates
 └edit.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>本の編集</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
</style>
</head>
<body>

<h1>本の編集</h1>

<form method="post" action="/edit" th:object="${formModel}">
  <input type="hidden" name="id" th:value="*{id}" />
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td><input type="text" name="title" th:value="*{title}" /></td>
    </tr>
    <tr>
      <td><label for="artist">著者</label></td>
      <td><input type="text" name="author" th:value="*{author}" /></td>
    </tr>
    <tr>
      <td><label for="bookshelf">本棚</label></td>
      <td th:if="*{bookshelf != null}">
        <input type="text" name="bookshelf" th:value="*{bookshelf.id}" />
      </td>
      <td th:if="*{bookshelf == null}">
        <input type="text" name="bookshelf" value="" />
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>


</body>
</html>

コントローラに編集画面へのマッピングを追加する。

src/main/java/
└jp.abc
 └BookController.java

	@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
	public ModelAndView edit(@ModelAttribute Book book,
	        @PathVariable long id,
	        ModelAndView mav) {
	    mav.setViewName("edit");
	    mav.addObject("title", "edit music");
	    Optional<Book> data = repository.findById(id);
	    mav.addObject("formModel", data.get());
	    return mav;
	}

POSTメソッドを受け取れるようにする。

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	public ModelAndView form(@ModelAttribute @Validated Book book,
	        Errors result,
	        ModelAndView mav) {
	    if (result.hasErrors()) {
	        return mav;
	    }
	    repository.saveAndFlush(book);
	    return new ModelAndView("redirect:/book");
	}

book.html に編集と削除のリンクを追加する。

src/main/resources/
└templates
 └book.html

<hr />
<table>
  <tr>
    <th>ID</th><th>タイトル</th><th>著者</th><th>本棚</th><th>編集</th><th>削除</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.title}"></td>
    <td th:text="${obj.author}"></td>
    <td th:if="${obj.bookshelf != null}" th:text="${obj.bookshelf.name}"></td>
    <td th:if="${obj.bookshelf == null}" th:text="本棚なし"></td>
    <td><a th:href="@{'/edit/' + ${obj.id}}">編集</a></td>
    <td><a th:href="@{'/delete/' + ${obj.id}}">削除</a></td>
  </tr>
</table>

本を削除できるようにする

src/main/resources/
└templates
 └delete.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>本の削除</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
</style>
</head>
<body>

<h1>本の削除</h1>

<form method="post" action="/delete" th:object="${formModel}">
  <input type="hidden" name="id" th:value="*{id}" />
  <table>
    <tr><td><p th:text="|タイトル : *{title}|"></p></td></tr>
    <tr><td><p th:text="|著者 : *{author}|"></p></td></tr>
    <tr><td><input type="submit" value="削除" /></td></tr>
  </table>
</form>


</body>
</html>

コントローラに削除ページへのマッピングを追加する。

src/main/java/
└jp.abc
 └BookController.java

	@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
	public ModelAndView delete(@PathVariable int id,
	        ModelAndView mav) {
	    mav.setViewName("delete");
	    mav.addObject("title", "本の削除");
	    Optional<Book> data = repository.findById((long)id);
	    mav.addObject("formModel", data.get());
	    return mav;
	}

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

8月22日

Bookshelfを登録できるようにする

Repositoryを作成する。

src/main/java/
└jp.abc
 └BookshelfRepository.java

package jp.abc;

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

public interface BookshelfRepository extends JpaRepository<Bookshelf, Long> {

}

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

src/main/java/
└jp.abc
 └BookshelfController.java

package jp.abc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
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 BookshelfController {

	@Autowired
	private BookshelfRepository repository;

	@RequestMapping(value = "/bookshelf", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("bookshelf");
		mav.addObject("formModel", new Bookshelf());
		mav.addObject("datalist", repository.findAll());
		return mav;
	}

	@RequestMapping(value = "/bookshelf", method = RequestMethod.POST)
	public ModelAndView post(
			@ModelAttribute("formModel") @Validated Bookshelf bookshelf,
			Errors errors,
			ModelAndView mav) {
		if (errors.hasErrors()) {
			mav.addObject("msg", "エラーですよ");
			return mav;
		}
		repository.saveAndFlush(bookshelf);
		return new ModelAndView("redirect:/bookshelf");
	}
}

データベース接続設定を application.properties に記述する。

src/main/resources/
└application.properties

spring.datasource.url=jdbc:hsqldb:hsql://localhost/bookshelf
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.jpa.hibernate.ddl-auto=update

本棚に収納するための本のクラス Book を作成する。

src/main/java/
└jp.abc
 └Book.java

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Book {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String title;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String author;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

}

Book用のHTMLテンプレートを作成する。

src/main/resources/
└templates
 └book.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Book</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>
<h1>Book</h1>
<p th:text="${msg}"></p>
<form method="post" action="/book" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td>
        <input type="text" name="title" th:value="*{title}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('title')}" th:errors="*{title}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="author">著者</label></td>
      <td>
        <input type="text" name="author" th:value="*{author}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('author')}" th:errors="*{author}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>タイトル</th><th>著者</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.title}"></td>
    <td th:text="${obj.author}"></td>
  </tr>
</table>

</body>
</html>

Book用のリポジトリを作成する。
src/main/java/
└jp.abc
 └BookRepository.java

package jp.abc;

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

public interface BookRepository extends JpaRepository<Book, Long> {

}

Book用のコントローラを作成する。

src/main/java/
└jp.abc
 └BookController.java

package jp.abc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
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 BookController {

	@Autowired
	private BookRepository repository;

	@RequestMapping(value = "/book", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("book");
		mav.addObject("formModel", new Book());
		mav.addObject("datalist", repository.findAll());
		return mav;
	}

	@RequestMapping(value = "/book", method = RequestMethod.POST)
	public ModelAndView post(
			@ModelAttribute("formModel") @Validated Book book,
			Errors errors,
			ModelAndView mav) {
		if (errors.hasErrors()) {
			mav.addObject("msg", "エラーですよ");
			return mav;
		}
		repository.saveAndFlush(book);
		return new ModelAndView("redirect:/book");
	}
}

8月19日

Spring Bootの復習

簡単なWebアプリを作成してみる。

プロジェクト名: bookshelf
パッケージ名: jp.abc

プロジェクトを作成すると、pom.xml内でのSpringBootのバージョンが2.1.7になっているが、そのままではビルドエラーになるので、これを2.1.4に変更する。

BookshelfエンティティとBookエンティティを作成する。

Bookshelfのプロパティは name のみ。

Bookのプロパティは title と author の二つ。

作成するページ

  • トップページ http://localhost:8080/
  • Bookshelfページ http://localhost:8080/bookshelf
  • Bookページ http://localhost:8080/book

ビルドでエラーが出る人は、サーバーの 
 授業資料・OC資料\澤田\2019_SpringBOOT\repository
を、
 ユーザー\.m2
に上書きしてみる。

pom.xmlの変更
7月2日のページを参照して、pom.xmlを変更する。
ThymeleafとJPAとHSQLDBの依存関係を追加する。

データベースの用意
デスクトップに作成したhsqldb.batを編集して bookshelf インスタンスを用意する。

cd C:\pleiades\hsqldb-2.4.1\hsqldb\lib
java -cp hsqldb.jar org.hsqldb.Server --database.0 db/mydata --dbname.0 mydata --database.1 db/bookshelf --dbname.1 bookshelf

トップページを作成する

src/main/resources/
└templates
 └index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>top page</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
</style>
</head>
<body>

<h1>top page</h1>

</body>
</html>

トップページを表示するためのコントローラを作成する

src/main/java/
└jp.abc
 └IndexController.java

package jp.abc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		return mav;
	}

}

Bookshelf(本棚)を作成する

HTMLテンプレートを作成する。

src/main/resources/
└templates
 └bookshelf.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Bookshelf</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>
<h1>Bookshelf</h1>
<p th:text="${msg}"></p>
<form method="post" action="/bookshelf" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="name">名前</label></td>
      <td>
        <input type="text" name="name" th:value="*{name}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>名前</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.name}"></td>
  </tr>
</table>

</body>
</html>

Bookshelfエンティティを作成する

src/main/java/
└jp.abc
 └Bookshelf.java

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Bookshelf {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

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

	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;
	}
}

コントローラを作成する

src/main/java/
└jp.abc
 └BookshelfController.java

package jp.abc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class BookshelfController {
	@RequestMapping(value = "/bookshelf", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("bookshelf");
		mav.addObject("formModel", new Bookshelf());
		mav.addObject("datalist", null);
		return mav;
	}

}

前期提出課題

プロジェクト

プロジェクト名: se3NN (NN は学籍番号の下2桁)
パッケージ名: jp.abc

MyBootApp と同様のWebアプリケーションを作成する。
MyDataのかわりに、Userクラスを作成し、MsgDataクラスの代わりに Tweetクラスを作成する。

作成するページとURL

トップページ: http://localhost:8080/
ユーザー一覧&ユーザー登録: http://localhost:8080/user/
ユーザー編集ページ: http://localhost:8080/edit/{id}
ツイート一覧&ツイート投稿: http://localhost:8080/tweet/

エンティティ

User
・id – Long
・name – String
・profile – String
・tweets – List<Tweet>
Tweet
・id – Long
・time – java.util.Date
・content – String
・user – User

作成するHTMLテンプレート

  • index.html : トップページ
  • user.html : ユーザー一覧&ユーザー登録ページ
  • edit.html : ユーザー編集ページ
  • tweet.html : ツイート一覧&ツイート投稿ページ

トップページの内容

  • titleとh1タグに番号と名前を書くこと
  • ユーザー一覧&ユーザー登録ページへのリンクを作成
  • ツイート一覧&ツイート投稿ページへのリンクを作成

ユーザー一覧&ユーザー登録ページの内容

  • titleとh1タグに番号と名前を書くこと
  • h1のすぐ下にトップページへのリンクを作成
  • 入力フォームで名前(name)と自己紹介(profile)を入力できる
  • 自己紹介はtextareaにすること
  • 名前は1文字以上30文字以下
  • 自己紹介は1文字以上200文字以下
  • 送信ボタンを表示
  • 入力フォームの下に、登録済みユーザー一覧を表示する
  • ユーザー一覧にはID、名前、編集ページへのリンクを表示する

ユーザー編集ページの内容

  • titleとh1タグに番号と名前を書くこと
  • h1のすぐ下にトップページへのリンクを作成
  • 入力フォームに編集前の名前と自己紹介を表示
  • 入力フォームで名前と自己紹介を入力できる
  • 送信ボタンを表示

ツイート一覧&投稿ページの内容

  • titleとh1タグに番号と名前を書くこと
  • h1のすぐ下にトップページへのリンクを作成
  • 入力フォームで投稿内容(content)を入力できる
  • 投稿は1文字以上140文字以下
  • 投稿欄はtextareaにすること
  • 送信ボタンを表示
  • 日時はフォームに用意せず、コントローラが現在時刻を設定する
  • 入力フォームの下に、投稿済みツイート一覧を表示する
  • 投稿一覧にはID、名前、日時、投稿内容を表示する

application.properties

spring.datasource.url=jdbc:hsqldb:hsql://localhost/se3NN  ←NNは学籍番号の下2桁
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.jpa.hibernate.ddl-auto=update

hsqldb.bat
データベースインスタンスを追加する。
インスタンス名は se3NN (NNは学籍番号の下2桁)

cd (hsqldbの置き場所)\lib
java -cp hsqldb.jar org.hsqldb.Server --database.0 db/mydata --dbname.0 mydata --database.1 db/se3NN --dbname.1 se3NN

課題提出方法

プロジェクトを作成したフォルダを、エクスプローラで開く。

フォルダ「se3NN」(NNは学籍番号の下2桁)を右クリックし、[送る]-[圧縮(zip 形式)フォルダー]を選択する。
se3NN.zip ファイルができるので、そのファイルを提出する。

提出先

サーバーの以下のフォルダに提出。

\\stfs\ABKC\課題提出用\澤田\2019_SE3\課題提出

配点

接続先データベースや、プロジェクト名、番号・名前の間違いは、他人のものをコピーしたと判断し0点。
コピペもOKだけど最低限ができてなければ論外。
Webサイトを作って納品してもサイト名や会社名が間違ってたら、まず次の仕事はない。

  1. トップページ : 10点
    • titleとh1に番号と名前
    • ユーザーページへのリンク
    • 投稿ページへのリンク
  2. ユーザー一覧&ユーザー登録(GET) : 10点
    • titleとh1に番号と名前
    • 入力フォーム
    • 送信ボタン
    • ユーザー一覧
    • トップページへのリンク
  3. ユーザー一覧&ユーザー登録(POST) : 10点
    • 名前のエラーチェック
    • 自己紹介のエラーチェック
    • エラーメッセージ
    • データベースに保存
  4. ユーザー編集(GET) : 10点
    • titleとh1に番号と名前
    • 入力フォーム
    • 送信ボタン
    • トップページへのリンク
  5. ユーザー編集(POST) : 10点
    • 名前のエラーチェック
    • 自己紹介のエラーチェック
    • エラーメッセージ
    • データベースに保存
  6. ツイート一覧&投稿(GET) : 10点
    • titleとh1に番号と名前
    • 入力フォーム
    • 送信ボタン
    • ツイート一覧
    • トップページへのリンク
  7. ツイート一覧&投稿(POST) : 10点
    • 投稿内容のエラーチェック
    • 現在時刻を自動設定
    • エラーメッセージ
    • データベースに保存
  8. ツイート一覧で投稿者名が表示される(エンティティの連携) : 10点
  9. エラーメッセージの日本語化(全部できていれば) : 10点
  10. ツイート投稿でSELECT/OPTIONでユーザーを選択できる : 10点
  11. ツイート一覧でIDと名前の下に投稿が表示される : 10点
  12. ツイート一覧で複数行投稿がきちんと表示される : 10点
  13. トップページに授業の感想・意見を書く : 1〜20点

※1〜8はプログラムで採点しています。なので、1〜8の部分点はありません。
※14の授業の感想・意見は参考になった度合いで加点します。
※配点の総合計は100点を超えてますが、最大は100点です。

提出期限

7月19日(金)17:00

7月5日

プレイリストを登録できるようにする

リポジトリを作成する。

PlayListRepository.java

package jp.abc;

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

public interface PlayListRepository extends JpaRepository<PlayList, Long> {

}

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

package jp.abc;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
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 PlayListController {

	@Autowired
	private PlayListRepository repository;

	@RequestMapping(value = "/playlist", method = RequestMethod.GET)
	public ModelAndView list(ModelAndView mav) {
		mav.setViewName("playlist");
		PlayList pl = new PlayList();
		mav.addObject("formModel", pl);
		List<PlayList> list = repository.findAll();
		mav.addObject("datalist", list);
		return mav;
	}

	@RequestMapping(value = "playlist", method = RequestMethod.POST)
	public ModelAndView post(
			@ModelAttribute("formModel") @Validated PlayList playlist,
			Errors result,
			ModelAndView mav) {
		if (result.hasErrors()) {
			mav.addObject("msg", "エラーですよ");
			return mav;
		}
		repository.saveAndFlush(playlist);
		return new ModelAndView("redirect:/playlist");
	}
}

HTMLテンプレートを修正する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>プレイリスト</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>

<h1>プレイリスト</h1>
<p th:text="${msg}"></p>
<form method="post" action="/playlist" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="name">名前</label></td>
      <td>
        <input type="text" name="name" th:value="*{name}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>名前</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.name}"></td>
  </tr>
</table>

</body>
</html>

PlayListとMusicを連携する

MusicからPlayListへの関連性を追加する。

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Music {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String title;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String artist;

	@ManyToOne
	private PlayList playlist;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getArtist() {
		return artist;
	}

	public void setArtist(String artist) {
		this.artist = artist;
	}

	@Override
	public String toString() {
		return "Music [title=" + title + ", artist=" + artist + "]";
	}

	public PlayList getPlaylist() {
		return playlist;
	}

	public void setPlaylist(PlayList playlist) {
		this.playlist = playlist;
	}

}

PlayListからMusicへの関連性を追加する。

package jp.abc;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class PlayList {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

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

	@OneToMany
	private List<Music> musics;

	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 List<Music> getMusics() {
		return musics;
	}

	public void setMusics(List<Music> musics) {
		this.musics = musics;
	}


}

Music を登録するHTMLテンプレート index.html に、プレイリストを設定するフィールドを追加する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ミュージックプレイヤー</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>

<h1>ミュージックプレイヤー</h1>
<p th:text="${msg}"></p>
<form method="post" action="/" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td>
        <input type="text" name="title" th:value="*{title}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('title')}" th:errors="*{title}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="artist">アーティスト</label></td>
      <td>
        <input type="text" name="artist" th:value="*{artist}"
      			th:errorclass="err"/>
      	<div th:if="${#fields.hasErrors('artist')}" th:errors="*{artist}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="playlist">プレイリスト</label></td>
      <td>
        <input type="text" name="playlist" th:value="*{playlist}"
      			th:errorclass="err"/>
      	<div th:if="${#fields.hasErrors('playlist')}" th:errors="*{playlist}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

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

</body>
</html>

入力フォームの下に、Musicのリストを表示しているが、そこにプレイリスト名を表示する。
プレイリストがnullの場合は「プレイリストなし」と表示する。

<hr />
<table>
  <tr>
    <th>ID</th><th>タイトル</th><th>アーティスト</th><th>プレイリスト</th><th>編集</th><th>削除</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.title}"></td>
    <td th:text="${obj.artist}"></td>
    <td th:if="${obj.playlist != null}" th:text="${obj.playlist.name}"></td>
    <td th:if="${obj.playlist == null}" th:text="プレイリストなし"></td>
    <td><a th:href="@{'/edit/' + ${obj.id}}">編集</a></td>
    <td><a th:href="@{'/delete/' + ${obj.id}}">削除</a></td>
  </tr>
</table>

Musicを編集できるようにする。

コントローラで編集のURLを受け付けるようにする。

	@RequestMapping(value = "/edit/{id}")
	public ModelAndView edit(@ModelAttribute Music music,
			@PathVariable long id,
			ModelAndView mav) {
		mav.setViewName("edit");
		mav.addObject("title", "edit music");
		Optional<Music> data = repository.findById(id);
		mav.addObject("formModel", data.get());
		return mav;
	}

HTMLテンプレート edit.html を作成する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>top page</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
</style>
</head>
<body>

<h1>Music edit page</h1>

<form method="post" action="/edit" th:object="${formModel}">
  <input type="hidden" name="id" th:value="*{id}" />
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td><input type="text" name="title" th:value="*{title}" /></td>
    </tr>
    <tr>
      <td><label for="artist">アーティスト</label></td>
      <td><input type="text" name="artist" th:value="*{artist}" /></td>
    </tr>
    <tr>
      <td><label for="playlist">プレイリスト</label></td>
      <td th:if="*{playlist != null}">
        <input type="text" name="playlist" th:value="*{playlist.id}" />
      </td>
      <td th:if="*{playlist == null}">
        <input type="text" name="playlist" value="" />
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>


</body>
</html>

MusicController で POSTを受け付ける。

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	public ModelAndView form(@ModelAttribute @Validated Music music,
			Errors result,
			ModelAndView mav) {
		if (result.hasErrors()) {
			return mav;
		}
		repository.saveAndFlush(music);
		return new ModelAndView("redirect:/");
	}

7月2日

ミュージックプレイヤーのWebアプリケーションを作ってみる

以前、JavaコンソールアプリケーションとしてMusicPlayerを作成したが、今回は、それをSpringBootを使用したWebアプリケーションとして作成してみる。

まずは新規プロジェクトを作成する。

プロジェクト名は好きなように決めてよい。

pom.xml で SpringBoot のバージョンを変更する。
デフォルトでは2.1.6になっているが、エラーが発生するので、これまでに使っていた2.1.4にする。
そして、ThymeleafとJPAとHSQLDBの依存関係も追加しておく。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>jp.abc</groupId>
	<artifactId>stunes</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>stunes</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

HSQLDBを起動するBATファイルに、新しいデータベースインスタンスを追加する。

cd C:\pleiades\hsqldb-2.4.1\hsqldb\lib
java -cp hsqldb.jar org.hsqldb.Server --database.0 db/mydata --dbname.0 mydata --database.1 db/stunes --dbname.1 stunes

Musicエンティティを作成する。

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Music {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String title;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String artist;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getArtist() {
		return artist;
	}

	public void setArtist(String artist) {
		this.artist = artist;
	}

	@Override
	public String toString() {
		return "Music [title=" + title + ", artist=" + artist + "]";
	}

}

リポジトリを作成する。

package jp.abc;

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

public interface MusicRepository extends JpaRepository<Music, Long> {

}

コントローラを作成する。

package jp.abc;

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 MusicController {

	@Autowired
	private MusicRepository repository;

	@RequestMapping("/")
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		return mav;
	}
}

HTMLテンプレートを作成する。
CSSと入力フォームの部分は、mydata.html の該当箇所をコピーして使うと早い。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ミュージックプレイヤー</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>

<h1>ミュージックプレイヤー</h1>
<p th:text="${msg}"></p>
<form method="post" action="/" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td>
        <input type="text" name="title" th:value="*{title}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('title')}" th:errors="*{title}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="artist">アーティスト</label></td>
      <td>
        <input type="text" name="artist" th:value="*{artist}"
      			th:errorclass="err"/>
      	<div th:if="${#fields.hasErrors('artist')}" th:errors="*{artist}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

</body>
</html>

これで実行するとエラーが発生する。
コントローラで formModel を渡していないのが原因なので、コントローラを修正する。

package jp.abc;

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 MusicController {

	@Autowired
	private MusicRepository repository;

	@RequestMapping("/")
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		Music m = new Music();
		mav.addObject("formModel", m);
		return mav;
	}
}

POSTメソッドを受け付けるようにするために、コントローラを修正する。

package jp.abc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
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 MusicController {

	@Autowired
	private MusicRepository repository;

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		Music m = new Music();
		mav.addObject("formModel", m);
		return mav;
	}

	@RequestMapping(value = "/", method = RequestMethod.POST)
	public ModelAndView post(
			@ModelAttribute("formModel") @Validated Music music,
			Errors result,
			ModelAndView mav) {
		if (result.hasErrors()) {
			mav.setViewName("index");
			mav.addObject("msg", "エラーです");
			return mav;
		}
		repository.saveAndFlush(music);
		return new ModelAndView("redirect:/");
	}
}

データベース接続の設定を、application.properties ファイルに記述する。

spring.datasource.url=jdbc:hsqldb:hsql://localhost/stunes
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.jpa.hibernate.ddl-auto=update

HTMLテンプレートに、保存されているデータのリストを表示するテーブルを追加する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>ミュージックプレイヤー</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>

<h1>ミュージックプレイヤー</h1>
<p th:text="${msg}"></p>
<form method="post" action="/" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td>
        <input type="text" name="title" th:value="*{title}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('title')}" th:errors="*{title}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="artist">アーティスト</label></td>
      <td>
        <input type="text" name="artist" th:value="*{artist}"
      			th:errorclass="err"/>
      	<div th:if="${#fields.hasErrors('artist')}" th:errors="*{artist}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

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

</body>
</html>

コントローラで、datalist の名前で、データをわたす。

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		Music m = new Music();
		mav.addObject("formModel", m);
		List<Music> list = repository.findAll();
		mav.addObject("datalist", list);
		return mav;
	}

プレイリストも作ってみる

まずはエンティティを作成する。

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class PlayList {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

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

	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;
	}


}

HTMLテンプレートを作成する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>プレイリスト</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>

<h1>プレイリスト</h1>
<p th:text="${msg}"></p>
<form method="post" action="/" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="name">名前</label></td>
      <td>
        <input type="text" name="name" th:value="*{name}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>名前</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.title}"></td>
  </tr>
</table>

</body>
</html>

コントローラを作成する。

package jp.abc;

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

@Controller
public class PlayListController {
	@RequestMapping("/playlist")
	public ModelAndView list(ModelAndView mav) {
		mav.setViewName("playlist");
		PlayList pl = new PlayList();
		mav.addObject("formModel", pl);
		return mav;
	}
}

動いた!

6月28日

エンティティの連携

MyData に、複数の MsgData を関連付ける。

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class MsgData {
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private Long id;
	
	@Column
	private String title;
	
	@Column
	@NotEmpty
	private String message;
	
	@ManyToOne
	private MyData mydata;

	public MsgData() {
		super();
		mydata = new MyData();
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public MyData getMydata() {
		return mydata;
	}

	public void setMydata(MyData mydata) {
		this.mydata = mydata;
	}
	
}

MyData にもエンティティの連携に関連するコードを追加する。

package jp.abc;

import java.util.List;

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


@Entity
public class MyData {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

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

	@Column(length = 200, nullable = true)
	@Email
	private String mail;

	@Column(nullable = true)
	@Min(value=0)
	@Max(value=200)
	private Integer age;

	@Column(nullable = true)
	private String memo;

	@OneToMany
	private List<MsgData> msgdatas;

	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 Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}

	public List<MsgData> getMsgdatas() {
		return msgdatas;
	}

	public void setMsgdatas(List<MsgData> msgdatas) {
		this.msgdatas = msgdatas;
	}

}

MsgDataを永続化するためのリポジトリを用意する。

package jp.abc.repositories;

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

import jp.abc.MyData;

public interface MsgDataRepository extends JpaRepository<MyData, Long> {

}

HTMLテンプレートを作成する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="${title}">top page</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
tr {
  margin: 5x;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
</style>
</head>
<body>
<h1 th:text="${title}">MyMsg page</h1>
<p th:text="${msg}"></p>
<form method="post" action="/msg" th:object="${formModel}">
  <input type="hidden" name="id" th:value="*{id}" />
  <table>
  	<tr>
  	  <td><label for="title">タイトル</label></td>
  	  <td><input type="text" name="title" th:value="*{title}" />
  	</tr>
  	<tr>
  	  <td><label for="message">メッセージ</label></td>
  	  <td><textarea name="message" th:text="*{message}"></textarea></td>
  	</tr>
  	<tr>
  	  <td><label for="mydata">MYDATA_ID</label></td>
  	  <td><input type="text" name="mydata" /></td>
  	</tr>
  	<tr>
  	  <td></td><td><input type="submit" /></td>
  	</tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>名前</th><th>タイトル</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.mydata.name}"></td>
    <td th:text="${obj.title}"></td>
  </tr>
</table>
</body>
</html>

新しくコントローラを作成する。
まずはGETメソッドに対応する部分だけを作成。

MsgDataController.java

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.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import jp.abc.repositories.MsgDataRepository;

@Controller
public class MsgDataController {

	@Autowired
	private MsgDataRepository repository;

	@RequestMapping(value = "/msg", method=RequestMethod.GET)
	public ModelAndView msg(ModelAndView mav) {
		mav.setViewName("showMsgData");
		mav.addObject("title", "Sample");
		mav.addObject("msg", "MsgDataのサンプルです。");
		MsgData msgdata = new MsgData();
		mav.addObject("formModel", msgdata);
		List<MsgData> list = repository.findAll();
		mav.addObject("datalist", list);
		return mav;
	}
}

コントローラにPOSTメソッドを追加する。

package jp.abc;

import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
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;

import jp.abc.repositories.MsgDataRepository;

@Controller
public class MsgDataController {

	@Autowired
	private MsgDataRepository repository;

	@RequestMapping(value = "/msg", method=RequestMethod.GET)
	public ModelAndView msg(ModelAndView mav) {
		mav.setViewName("showMsgData");
		mav.addObject("title", "Sample");
		mav.addObject("msg", "MsgDataのサンプルです。");
		MsgData msgdata = new MsgData();
		mav.addObject("formModel", msgdata);
		List<MsgData> list = repository.findAll();
		mav.addObject("datalist", list);
		return mav;
	}

	@RequestMapping(value = "/msg", method=RequestMethod.POST)
	public ModelAndView msgform(@Valid @ModelAttribute MsgData msgdata,
			Errors result,
			ModelAndView mav) {
		if (result.hasErrors()) {
			mav.setViewName("showMsgData");
			mav.addObject("title", "Sample [ERROR]");
			mav.addObject("msg", "値を再チェックしてください。");
			return mav;
		}
		repository.saveAndFlush(msgdata);
		return new ModelAndView("redirect:/msg");
	}
}

HTMLテンプレートの以下の部分でエラーが出てるので変更しておく。

  <input type="hidden" name="id" th:value="*{id}" />

↓↓↓↓↓↓

  <input type="hidden" name="id" value="0" />

6月25日

HSQLDBサーバーが動いたら、MyBootAppを起動する。
起動すると、自動的に3つのレコードが書き込まれる。
起動するたびにレコードが書き込まれるのはまずいので、以下のコードを削除する。

MyDataController.java

	@PostConstruct
	public void init() {
		MyData d1 = new MyData();
		d1.setName("tuyano");
		d1.setAge(123);
		d1.setMail("syoda@tuyano.com");
		d1.setMemo("this is data!");
		repository.saveAndFlush(d1);
		MyData d2 = new MyData();
		d2.setName("hanako");
		d2.setAge(15);
		d2.setMail("hanako@flower.com");
		d2.setMemo("this is data!");
		repository.saveAndFlush(d2);
		MyData d3 = new MyData();
		d3.setName("sachiko");
		d3.setAge(37);
		d3.setMail("sachiko@happy");
		d3.setMemo("this is data!");
		repository.saveAndFlush(d3);
	}

データベースマネージャを起動するBATファイルも作成する。
デスクトップにmanager.bat を作成する。

cd C:\pleiades\hsqldb-2.4.1\hsqldb\data
java -classpath ..\lib\hsqldb.jar org.hsqldb.util.DatabaseManager

データベースマネージャを起動すると、接続先設定の画面が出るので、以下のように入力する。

データベースのデータを毎回消さないようにするために、application.properties に設定を1行追加する。

spring.datasource.url=jdbc:hsqldb:hsql://localhost/mydata
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.jpa.hibernate.ddl-auto=update

DAOを使ったデータベースアクセス

Spring Boot ではリポジトリを使って容易にデータベースアクセスできる。
Java標準のJAPを使う場合は、一般的にDAOを使ってデータベースアクセスを実装する。

まずDAOインタフェースを作成する。

package jp.abc;

import java.io.Serializable;
import java.util.List;

public interface MyDataDao <T> extends Serializable {
	public List<T> getAll();
}

そして、DAOの実装クラスを作成する。

package jp.abc;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import jp.abc.MyData;
import jp.abc.MyDataDao;

public class MyDataDaoImpl implements MyDataDao<MyData> {

	private EntityManager entityManager;

	public MyDataDaoImpl() {
		super();
	}
	public MyDataDaoImpl(EntityManager entityManager) {
		this();
		this.entityManager = entityManager;
	}

	@Override
	public List<MyData> getAll() {
		Query query = entityManager.createQuery("from MyData");
		List<MyData> list = query.getResultList();
		entityManager.close();
		return list;
	}

}

コントローラには、以下のコードを追加する。
URL: /dao にアクセスしたときに、DAO経由でデータベースアクセスを実行する。

	@PersistenceContext
	EntityManager entityManager;

	MyDataDao<MyData> dao;

	@PostConstruct
	public void init() {
		dao = new MyDataDaoImpl(entityManager);
	}

	@RequestMapping("/dao")
	public ModelAndView dao(ModelAndView mav) {
		mav.setViewName("dao");
		mav.addObject("msg", "DAOを使ったサンプルです。");
		List<MyData> list = dao.getAll();
		mav.addObject("datalist", list);
		return mav;
	}

HTMLテンプレートを dao.html として用意する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>top page</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>

<h1>MyData page</h1>
<p th:text="${msg}"></p>

<hr />
<table>
  <tr>
    <th>ID</th><th>名前</th><th>メール</th><th>年齢</th><th>メモ</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.name}"></td>
    <td th:text="${obj.mail}"></td>
    <td th:text="${obj.age}"></td>
    <td th:text="${obj.memo}"></td>
  </tr>
</table>


</body>
</html>

6月21日

各入力フィールドにえらーを表示

エラーメッセージをそれぞれの入力フィールドの近くに表示するように、HTMLテンプレートを変更する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>top page</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>

<h1>MyData page</h1>
<p th:text="${msg}"></p>
<form method="post" action="/mydata" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="name">名前</label></td>
      <td>
        <input type="text" name="name" th:value="*{name}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="age">年齢</label></td>
      <td>
        <input type="text" name="age" th:value="*{age}"
      			th:errorclass="err"/>
      	<div th:if="${#fields.hasErrors('age')}" th:errors="*{age}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="mail">メール</label></td>
      <td>
        <input type="text" name="mail" th:value="*{mail}"
        	th:errorclass="err"/>
        <div th:if="${#fields.hasErrors('mail')}" th:errors="*{mail}"
        	th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="memo">メモ</label></td>
      <td><textarea name="memo" th:value="*{memo}" rows="5" cols="20"></textarea></td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>名前</th><th>編集</th><th>削除</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.name}"></td>
    <td><a th:href="@{'/edit/' + ${obj.id}}">編集</a></td>
    <td><a th:href="@{'/delete/' + ${obj.id}}">削除</a></td>
  </tr>
</table>


<pre th:text="${data}"></pre>


</body>
</html>

エラーメッセージを日本語で表示する

バリデーション条件を指定するアノテーションにmessageパラメータを追加することで、メッセージをカスタマイズできる。

package jp.abc;

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


@Entity
public class MyData {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 50, nullable = false)
	@NotEmpty(message="空白は不可")
	private String name;

	@Column(length = 200, nullable = true)
	@Email(message="メールアドレスのみ")
	private String mail;

	@Column(nullable = true)
	@Min(value=0, message="0以上")
	@Max(value=200, message="200以下")
	private Integer 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 Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}

}

プロパティーファイルを用意してメッセージをまとめて扱う

バリデーション用アノテーションに message 引数を追加してメッセージをカスタマイズする方法とは別に、プロパティーファイルを使う方法がある。

resources フォルダにValidationMessages.properties ファイルを作成する。
作成したファイルを右クリックして[次で開く]-[Limyプロパティーエディター]を選択する。

プロパティーファイルの内容はバリデーション用アノテーションのクラス名に続けて「.message = 」を追加して、右辺にカスタマイズしたメッセージを記述する。
MinとMaxは、アノテーションにvalue引数で渡した値を {value} で受け取って表示できる。

javax.validation.constraints.NotEmpty.message = 空白は不可です。
javax.validation.constraints.Email.message = メールアドレスではありません。
javax.validation.constraints.Min.message = {value}より大きくしてください。
javax.validation.constraints.Max.message = {value}より小さくしてください。

HSQLDBサーバーを起動する

HSQLDBをダウンロードする。
検索して公式サイトからhsqldb-2.4.1.zip をダウンロードする。
ZIPファイルを解凍したフォルダを、C:\pleiades\ に置く。

デスクトップに起動用BATファイル hsqldb.bat を作成する。

cd C:\pleiades\hsqldb-2.4.1\hsqldb\lib
java -cp hsqldb.jar org.hsqldb.Server --database.0 db/mydata --dbname.0 mydata

Macの人は、「書類」フォルダにHSQLDBを解凍する。
書類フォルダなどにテキストファイル hsqldb.sh を作成する。

#!/bin/sh
cd ~/Documents/hsqldb/lib
java -cp hsqldb.jar org.hsqldb.Server --database.0 db/mydata --dbname.0 mydata

hsqldb.sh を作成後、ターミナルで以下のコマンドを実行する。

$ cd ~/Documents
# chmod +x ./hsqldb.sh

hsqldb.bat をダブルクリックすると、HSQLDBサーバーが起動する。
コマンドプロンプトの画面を閉じるとHSQLDBサーバーが終了するので閉じないこと。
誤って閉じないように最小化しておく。

application.properties ファイルに以下の内容を記述する。

spring.datasource.url=jdbc:hsqldb:hsql://localhost/mydata
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect

6月18日

MyDataの更新

MyDataを更新する機能を追加する。
まず、HTMLテンプレートとして edit.html を用意した(前回)。

次にリポジトリに findById() メソッドを追加する。

package jp.abc.repositories;

import java.util.Optional;

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

import jp.abc.MyData;

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

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

	@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
	public ModelAndView edit(@ModelAttribute MyData mydata,
			@PathVariable int id,
			ModelAndView mav) {
		mav.setViewName("edit");
		mav.addObject("title", "edit mydata");
		Optional<MyData> data = repository.findById((long)id);
		mav.addObject("formModel", data.get());
		return mav;
	}

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

エンティティの削除

HTMLテンプレート delete.html を追加する。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>top page</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
</style>
</head>
<body>

<h1>MyData delete page</h1>

<form method="post" action="/delete" th:object="${formModel}">
  <input type="hidden" name="id" th:value="*{id}" />
  <table>
    <tr><td><p th:text="|名前 : *{name}|"></p></td></tr>
    <tr><td><p th:text="|年齢 : *{age}|"></p></td></tr>
    <tr><td><p th:text="*{mail}"></p></td></tr>
    <tr><td><p th:text="*{memo}"></p></td></tr>
    <tr><td><input type="submit" value="削除" /></td></tr>
  </table>
</form>


</body>
</html>

コントローラに、削除関連のリクエストを受け取るメソッドを追加する。

	@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
	public ModelAndView delete(@PathVariable int id,
			ModelAndView mav) {
		mav.setViewName("delete");
		mav.addObject("title", "delete mydata");
		Optional<MyData> data = repository.findById((long)id);
		mav.addObject("formModel", data.get());
		return mav;
	}

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

エンティティのバリデーション

バリデーションは、エンティティのフィールドにアノテーションを追加することで入力値の制限ができる。

package jp.abc;

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


@Entity
public class MyData {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

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

	@Column(length = 200, nullable = true)
	@Email
	private String mail;

	@Column(nullable = true)
	@Min(0)
	@Max(200)
	private Integer 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 Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}

}

コントローラの引数でバリデーションの結果を受け取る。

	@RequestMapping(value = "/mydata", method = RequestMethod.POST)
	public ModelAndView form(
			@ModelAttribute("formModel") @Validated MyData mydata,
			BindingResult result,
			ModelAndView mav) {
		if (!result.hasErrors()) {
			repository.saveAndFlush(mydata);
			return new ModelAndView("redirect:/mydata");
		}
		mav.setViewName("mydata");
		mav.addObject("msg", "sorry, error is occured...");
		Iterable<MyData> list = repository.findAll();
		mav.addObject("datalist", list);
		return mav;
	}

HTMLテンプレートでエラーメッセージを表示する。

td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>

<h1>MyData page</h1>
<p th:text="${msg}"></p>
<form method="post" action="/mydata" th:object="${formModel}">
<ul>
  <li th:each="error : ${#fields.detailedErrors()}" class="err"
      th:text="${error.message}" />
</ul>
  <table>
    <tr>
      <td><label for="name">名前</label></td>
      <td><input type="text" name="name" th:value="*{name}" /></td>
    </tr>