9月1日

jQueryとAJAXでTODO項目を更新する。

jQueryライブラリを追加する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <input type="checkbox" name="item" value="${t.id}" />${t.item}<br />
    </c:forEach>
  </form>
</c:if>



</body>
</html>

jQueryでチェックボックスのイベントを取得するためのコードを追加する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	$('input[name="item"]').change(function(){
		console.log("change");
	});
})
</script>
</head>
(略)

チェックボックスをクリックすると、JavaScriptコンソールに change が出力されるのが確認できる。

次に、チェックボックスをクリックしたときに、完了済みのエリアにチェックボックスを移動するように処理を追加する。
そのために、完了済みのチェックボックスを配置するための場所を用意する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	$('input[name="item"]').change(function(){
		console.log("change");
	});
})
</script>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <input type="checkbox" id="check${t.id}" name="item" value="${t.id}" />${t.item}<br />
    </c:forEach>
  </form>
</c:if>

<hr />
<h3>完了済み</h3>
<div id="done"></div>

</body>
</html>

実際にチェックボックスをクリックしてみると、□だけが移動してしまう。
文字も移動させるために、div要素でまとめる。

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <div id="check${t.id}">
      	<input type="checkbox" name="item" value="${t.id}" />${t.item}
      </div>
    </c:forEach>
  </form>
</c:if>

チェックボックスがクリックされたイベントが発生したら、完了済みに移動する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	$('input[name="item"]').change(function(){
		console.log($(this).parent());
		$('#done').append($(this).parent());
	});
})
</script>
</head>

コントローラに、完了を受け取るためのメソッドを用意する。
パラメータを受け取れたかどうかを確認するためのコードを書いておく。

	@RequestMapping(value = "/done", method = RequestMethod.POST)
	public void done(@RequestParam(value = "id") String id, Model model) {
		System.out.println(id);
	}

ブラウザでチェックボックスをチェックすると、そのIDがサーバー側のコンソールに表示されることがわかる。

ToDoエンティティを更新できるようにする。

ToDoDaoにメソッドを追加する。

package jp.abc;

import java.util.List;

public interface ToDoDao<T> {
	public List<T> getAll();
	public void add(T item);
	public T findById(long id);
	public void update(T item);
}

ToDoDaoImplに実装を追加する。

package jp.abc;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

public class ToDoDaoImpl implements ToDoDao<ToDo> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

	public List<ToDo> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<ToDo> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<ToDo> q = builder.createQuery(ToDo.class);
		Root<ToDo> r = q.from(ToDo.class);
		q.select(r);
		list = (List<ToDo>)manager.createQuery(q).getResultList();
		manager.close();
		return list;
	}

	public void add(ToDo item) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.persist(item);
		tx.commit();
		manager.close();
	}

	public ToDo findById(long id) {
		EntityManager manager = factory.createEntityManager();
		Query q = manager.createQuery("from ToDo where id = " + id);
		return (ToDo)q.getSingleResult();
	}

	public void update(ToDo item) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.merge(item);
		tx.commit();
		manager.close();
	}

}

コントローラでToDoエンティティを更新するコードを追加する。

	@RequestMapping(value = "/done", method = RequestMethod.POST)
	public void done(@RequestParam(value = "id") String id, Model model) {
		ToDoDao<ToDo> dao = new ToDoDaoImpl();
		ToDo todo = dao.findById(Long.parseLong(id));
		todo.setDone(new Date());
		dao.update(todo);
	}

8月28日

SpringMVCによるWebアプリを作成する練習問題

ToDoリストアプリ

プロジェクト名: ToDo
パッケージ名: jp.abc
コントローラクラス名: ToDoController
エンティティクラス名: ToDo
JSPファイル名: todo.jsp

最初に基本動作となる画面遷移部分を作成する。

  1. プロジェクトを作成する。
  2. [Maven]-[プロジェクトの更新]を実行する。
  3. [実行]-[maven install]を実行する。
  4. Tomcatサーバーに作成したプロジェクトを追加する。
  5. Tomcatサーバーを起動する。
  6. http://localhost:8080/ToDo/ にアクセスする。
    → 「click to enter」表示でOK
  7. mvc-config.xml を修正して jp.abc パッケージを読み込むようにする。
  8. ToDoControllerを作成する。
  9. ToDoControllerで指定したURLにアクセスする。
    → todo.jsp がないのでエラー
  10. todo.jspを作成する。
  11. ToDoControllerで指定したURLにアクセスする。
    → todo.jsp の内容が表示されればOK
  12. 「登録」ボタンを押す。→ POSTメソッドに未対応なのでエラー
  13. ToDoControllerにPOSTメソッドを受け付けるメソッドを追加してtodo.jspにリダイレクトする。
  14. 「登録」ボタンを押す。
    → todo.jspが表示されればOK
  15. 日本語は文字化けするのでweb.xmlを変更して文字化け対策をする。

コントローラは、単純に todo.jsp を表示させるだけのシンプルなものを作成する。

ToDoController.java

package jp.abc;

import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class ToDoController {

	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public String todo(Model model) {
		return "todo";
	}

}

JSPは、ToDo項目を入力するフィールドと登録ボタンを用意する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

</body>
</html>

画面遷移ができるようになったら、エンティティとDAOを用意してToDo項目をデータベースに保存できるようにする。

エンティティ: ToDo
DAO: ToDoDao
DAO実装: ToDoDaoImpl

設定ファイルなどの準備作業を行う。

  1. pom.xml にデータベースアクセス関連の依存関係を追加する。
  2. database.properties ファイルを作成する。
  3. persistence.xmlファイルを作成する。
  4. application-config.xmlファイルを修正する。

pom.xml にデータベース関連の依存関係を追加する。

		<dependency>
		    <groupId>org.apache.commons</groupId>
		    <artifactId>commons-lang3</artifactId>
		    <version>3.1</version>
		</dependency>
		<dependency>
		    <groupId>org.hsqldb</groupId>
		    <artifactId>hsqldb</artifactId>
		    <version>2.3.4</version>
		</dependency>
		<dependency>
		    <groupId>javax.transaction</groupId>
		    <artifactId>jta</artifactId>
		    <version>1.1</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-aop</artifactId>
		    <version>3.2.4.RELEASE</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-aspects</artifactId>
		    <version>${spring-framework.version}</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-orm</artifactId>
		    <version>3.2.4.RELEASE</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-context</artifactId>
		    <version>${spring-framework.version}</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.data</groupId>
		    <artifactId>spring-data-jpa</artifactId>
		    <version>1.3.4.RELEASE</version>
		</dependency>
		<dependency>
		    <groupId>commons-dbcp</groupId>
		    <artifactId>commons-dbcp</artifactId>
		    <version>1.4</version>
		    <exclusions>
		        <exclusion>
		            <groupId>commons-logging</groupId>
		            <artifactId>commons-logging</artifactId>
		        </exclusion>
		        <exclusion>
		            <groupId>xml-apis</groupId>
		            <artifactId>xml-apis</artifactId>
		        </exclusion>
		    </exclusions>
		</dependency>

エンティティとDAOとDAO実装を作成して、コントローラからデータベースにアクセスする。

  1. ToDoエンティティを作成する。
  2. DAOとDAOの実装を作成する。
  3. ToDoControllerに、DAOを通してデータベースにアクセスするコードを追加する。

ToDoエンティティでは、ToDoの内容をitem、作成した日時 created、完了日 done のメンバーを持たせる。

ToDo.java

package jp.abc;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

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

	@Column
	private String item;

	@Column
	private Date created;

	@Column
	private Date done;

	public long getId() {
		return id;
	}

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

	public String getItem() {
		return item;
	}

	public void setItem(String item) {
		this.item = item;
	}

	public Date getCreated() {
		return created;
	}

	public void setCreated(Date created) {
		this.created = created;
	}

	public Date getDone() {
		return done;
	}

	public void setDone(Date done) {
		this.done = done;
	}
}

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

ToDoDao.java

package jp.abc;

import java.util.List;

public interface ToDoDao<T> {
	public List<T> getAll();
	public void add(T item);
}

DAOの実装を作成する。

ToDoDaoImple.java

package jp.abc;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

public class ToDoDaoImpl implements ToDoDao<ToDo> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

	public List<ToDo> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<ToDo> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<ToDo> q = builder.createQuery(ToDo.class);
		Root<ToDo> r = q.from(ToDo.class);
		q.select(r);
		list = (List<ToDo>)manager.createQuery(q).getResultList();
		manager.close();
		return list;
	}

	public void add(ToDo item) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.persist(item);
		tx.commit();
		manager.close();
	}

}

コントローラからデータベースにアクセスするコードを追加する。

ToDoController.java

package jp.abc;

import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class ToDoController {

	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public String todo(Model model) {
		ToDoDao<ToDo> dao = new ToDoDaoImpl();
		List<ToDo> list = dao.getAll();
		model.addAttribute("list", list);
		return "todo";
	}

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String add(@RequestParam(value = "item") String item, Model model) {
		ToDo todo = new ToDo();
		ToDoDao<ToDo> dao = new ToDoDaoImpl();
		todo.setItem(item);
		todo.setCreated(new Date());
		dao.add(todo);
		return "redirect:/list";
	}
}

todo.jsp に、ToDo項目のリストを表示するコードを追加する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <input type="checkbox" name="item" value="${t.id}" />${t.item}<br />
    </c:forEach>
  </form>
</c:if>

</body>
</html>

8月25日

Webアプリ「Shindan」で診断した内容をデータベースに保存する機能を追加する。

まずはDAOを作成する。

ShindanDao.java

package jp.abc;

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

public interface ShindanDao<T> extends Serializable {
	public List<T> getAll();
	public void add(Shindan s);
}

ShindanDao の実装クラス ShindanDaoImpl を作成する。
今回は、クエリ部分を CriteriaAPI で実装する。

ShindanDaoImpl.java

package jp.abc;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

public class ShindanDaoImpl implements ShindanDao<Shindan> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

	public List<Shindan> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<Shindan> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<Shindan> q = builder.createQuery(Shindan.class);
		Root<Shindan> r = q.from(Shindan.class);
		q.select(r);
		list = (List<Shindan>)manager.createQuery(q).getResultList();
		manager.close();
		return list;
	}

	public void add(Shindan s) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.persist(s);
		tx.commit();
		manager.close();
	}

}

コントローラに、DAOを通してDBにアクセスするコードを追加する。
入力チェックは、バリデーション機能を使わずに、独自で簡単に実装しておく。

package jp.abc;

import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class ShindanController {

	@RequestMapping(value = "/input", method = RequestMethod.GET)
	public String shindan(Model model) {
		Shindan s = new Shindan();
		ShindanDao<Shindan> dao = new ShindanDaoImpl();
		List<Shindan> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "shindan";
	}

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String form(@RequestParam(value = "name") String name,
					   @RequestParam(value = "type") String type,
					   Model model) {
		if (name == null || type == null) {
			model.addAttribute("message", "入力が不足しています。");
			return "shindan";
		}
		model.addAttribute("name", name);
		model.addAttribute("type", type);
		String s = name + type;
		int h = Math.abs(s.hashCode());
		h = h % 101;
		model.addAttribute("percent", h);

		Shindan shindan = new Shindan();
		ShindanDao<Shindan> dao = new ShindanDaoImpl();
		shindan.setName(name);
		shindan.setType(type);
		shindan.setValue(h);
		shindan.setTime(new Date());
		dao.add(shindan);
		return "redirect:/input";
	}
}

JSPに、DBから取得した履歴データを表示するコードを追加する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>診断アプリ</title>
</head>
<body>

<c:if test="${message != null}">
<p style="color:red;">${message}</p>
</c:if>

<form method="post" action="input">
<input type="text" name="name">さんの<br>
<input type="text" name="type">度を診断します<br>
<input type="submit" value="診断">

</form>

<div style="margin: 10px 50px;font-size: 20pt;">
<c:if test="${name != null}">
${name} さんの ${type} 度は、${percent}%です。<br>
</c:if>
</div>

<hr>
<c:if test="${datalist != null}">
<table border="1">
<tr><th>名前</th><th>診断内容</th><th>値</th></tr>
<c:forEach var="s" items="${datalist}">
  <tr>
    <td>${s.name}</td>
    <td>${s.type}</td>
    <td>${s.value} %</td>
  </tr>
</c:forEach>
</table>
</c:if>

</body>
</html>

persistence.xml に間違いがあったので修正する。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="2.0"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
      <property name="hibernate.hbm2ddl.auto" value="update" />
      <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbc.JDBCDriver" />
      <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:hsql://localhost/mydata" />
    </properties>
  </persistence-unit>
</persistence>

pom.xml の HSQLDB のバージョンも修正する。

		<dependency>
		    <groupId>org.hsqldb</groupId>
		    <artifactId>hsqldb</artifactId>
		    <version>2.3.4</version>
		</dependency>

データベースへの接続でエラーが発生する場合は、hsqldb.bat で パラメータを追加する。

hsqldb.bat

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

DB登録までできた人は、診断結果の値でソートする機能を追加してみること。

8月21日

復習としてSpringMVCを使ったWebアプリケーションを作成する。

ServletとJSPを使って作成した診断アプリを、SpringMVCを使って作成してみよう。

プロジェクト名: Shindan

5月29日の内容を参考にしてプロジェクトを作成する。

5月29日

6月2日の内容を参考にして mvc-config.xml を編集する。

6月2日

コントローラを作成する。
コントローラ: ShindanController.java

コントローラから shindan.jsp を表示させるコードを書く。

package jp.abc;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class ShindanController {

	@RequestMapping(value = "/input", method = RequestMethod.GET)
	public String shindan(Model model) {
		return "shindan";
	}
}

この状態で、http://localhost:8080/Shindan/input にアクセスすると404エラーが発生する。
エラーで WEB-INF/view/shindan.jsp が見つからないといわれるので、shindan.jsp を作成する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>診断アプリ</title>
</head>
<body>

<form method="post" action="ShindanServlet">
<input type="text" name="name">さんの<br>
<input type="text" name="type">度を診断します<br>
<input type="submit" value="診断">

</form>

</body>
</html>

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

package jp.abc;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class ShindanController {

	@RequestMapping(value = "/input", method = RequestMethod.GET)
	public String shindan(Model model) {
		return "shindan";
	}

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String form(Model model) {
		return "shindan";
	}
}

フォームのあとに、「○○さんの○○度はXX%です。」と表示する部分を追加する。
nameにデータがあるときだけ表示するように、JSTLの c:if タグで条件を指定する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>診断アプリ</title>
</head>
<body>

<form method="post" action="input">
<input type="text" name="name">さんの<br>
<input type="text" name="type">度を診断します<br>
<input type="submit" value="診断">

</form>

<c:if test="${name != null}">
${name} さんの ${type} 度は、${percent}%です。<br>
</c:if>

</body>
</html>

名前と診断内容を表示するために、リクエストパラメータから値を取得する。
そのために、POSTメソッドを受け取る form メソッドに、@RequestParam アノテーションを追加した引数を追加する。

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String form(@RequestParam(value = "name") String name,
					   @RequestParam(value = "type") String type,
					   Model model) {
		model.addAttribute("name", name);
		model.addAttribute("type", type);
		return "shindan";
	}

これで、名前と診断内容は表示できるようになる。

次に診断結果を表示できるようにする。
以前の ShindanServlet を参考にコードを追加する。

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String form(@RequestParam(value = "name") String name,
					   @RequestParam(value = "type") String type,
					   Model model) {
		model.addAttribute("name", name);
		model.addAttribute("type", type);
		String s = name + type;
		int h = Math.abs(s.hashCode());
		h = h % 101;
		model.addAttribute("percent", h);
		return "shindan";
	}

これまでの診断結果をデータベースに保存するようにしてみよう!

そのためには、pom.xml にデータベース関連のライブラリを追加する必要があるので、
6月19日の内容を参照して pom.xml を変更する。

6月19日

さらに、database.properties ファイルと persistence.xml を追加する。
これも6月19日を参照すればOK。

また、6月19日の記録を参照し、application-config.xml ファイルも変更する。

ここまでやれば、データベースを利用する準備が完了。

デスクトップに作成した hsqldb.bat をダブルクリックして HSQLDB を起動する。

Shindan エンティティの作成

jp.abc パッケージを右クリックして、[新規]-[クラス]を選択する。
クラス名は「Shindan」とする。

package jp.abc;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Shindan {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	private long id;

	@Column
	private Date time;

	@Column
	private String name;

	@Column
	private String type;

	@Column
	private int value;

	public long getId() {
		return id;
	}

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

	public Date getTime() {
		return time;
	}

	public void setTime(Date time) {
		this.time = time;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}
}

次回予定

  • DAOインタフェースの作成
  • DAO実装クラスの作成
  • コントローラの修正
  • JSPの修正

以上を行えば、データベースにアクセスできるようになるはず。

7月3日

試験範囲について

  • Eclipseを使った開発
  • ストリームを利用したファイル入出力とURLからのデータ取得
  • FizzBuzz問題を例題としてTDDによる開発手法の学習
  • TDDBC大阪の例題の自動販売機を実装する
  • JavaによるWebアプリケーションの基礎(Servlet/JSP/JSTL)
  • JSPによる入力フォームとServletでのデータの受け取り

サービスとリポジトリは便利ですが、使わなくてもWebアプリケーションを作れるので、今回はパスします。
興味がある人は自分でやってみてください。

エンティティの連携

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.persistence.Table;
import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.NotEmpty;

@Entity
@Table(name = "msgdata")
public class MsgData {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column
	private String title;

	@Column(nullable = false)
	@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を修正する
MyDataに、MsgDataへの参照を追加する。
インスタンス変数を追加したら、Eclipseの[ソース]-[getterおよびsetterの生成]でアクセサメソッドを自動生成する。

package jp.abc;

import java.util.List;

import javax.persistence.CascadeType;
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.persistence.Table;

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

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

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

	@Column(nullable = true)
	private Integer age;

	@Column(nullable = true)
	private String memo;

	@OneToMany(cascade = CascadeType.ALL)
	@Column(nullable = true)
	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;
	}

}

MsgDataDaoの用意

MsgDataDaoインタフェースを作成する。

package jp.abc;

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

public interface MsgDataDao<T> extends Serializable {
	public List<T> getAll();
	public T findById(long id);
	public void add(T data);
	public void update(T data);
	public void delete(T data);
	public void delete(long id);
}

MsgDataDaoImplクラスを作成する。
テキストの通りに各メソッドに @Override アノテーションをつけるとコンパイルエラーになる。
これは、プロジェクトの設定で Javaコンパイラのバージョンが1.5になっているため。
1.6に変更すれば @Override アノテーションのコンパイルエラーは消える。
同時に、プロジェクト・ファセットの設定でバージョンを合わせる必要がある。

package jp.abc;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class MsgDataDaoImpl implements MsgDataDao<MsgData> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

	@Override
	public List<MsgData> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<MsgData> list = null;
		Query q = manager.createQuery("from MsgData");
		list = q.getResultList();
		manager.close();
		return list;
	}

	@Override
	public MsgData findById(long id) {
		EntityManager manager = factory.createEntityManager();
		Query q = manager.createQuery("from MsgData where id = " + id);
		return (MsgData)q.getSingleResult();
	}

	@Override
	public void add(MsgData data) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.persist(data);
		tx.commit();
		manager.close();
	}

	@Override
	public void update(MsgData data) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.merge(data);
		tx.commit();
		manager.close();
	}

	@Override
	public void delete(MsgData data) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		MsgData entity = manager.merge(data);
		manager.remove(entity);
		tx.commit();
		manager.close();
	}

	@Override
	public void delete(long id) {
		delete(findById(id));
	}

}

ビューテンプレートの用意

[新規]-[JSPファイル]でJSPファイルを作成する。
ファイル名はテキストの通り「showMsgData.jsp」とする。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>${title}</title>
<style>
h1 { font-size: 16pt; background-color: #ccccff; padding: 3px;}
p { color: #000066; }
</style>
</head>
<body>
  <h1>${title}</h1>
  <p>${message}</p>
  <table>
  <form:form modelAttribute="msgdata">
    <tr>
      <td></td>
      <td><form:errors path="*" /></td>
    </tr>
    <tr>
      <td><form:label path="title">タイトル</form:label></td>
      <td><form:input path="title" size="20" /></td>
    </tr>
    <tr>
      <td><form:label path="message">メッセージ</form:label></td>
      <td><form:textarea path="message" cols="20" rows="5" /></td>
    </tr>
    <tr>
      <td><form:label path="mydata">MYDATA_ID</form:label></td>
      <td><form:input path="mydata" size="20" /></td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </form:form>
  </table>
  <hr />
  <c:if test="${datalist != null}">
  <table>
    <tr>
      <th>ID</th><th>投稿者</th><th>タイトル</th><th>メッセージ</th>
    </tr>
    <c:forEach var="obj" items="${datalist}" varStatus="status">
      <tr>
        <td><c:out value="${obj.id}" /></td>
        <td><c:out value="${obj.mydata.name}" /></td>
        <td><c:out value="${obj.title}" /></td>
        <td><c:out value="${obj.message}" /></td>
      </tr>
    </c:forEach>
  </table>
  </c:if>
</body>
</html>

コントローラに新しいURL用のメソッドを追加する

	@RequestMapping(value = "/msg", method = RequestMethod.GET)
	public String msg(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "MsgDataのサンプルです。");
		MsgData msgdata = new MsgData();
		model.addAttribute("msgdata", msgdata);
		MsgDataDao<MsgData> dao = new MsgDataDaoImpl();
		List<MsgData> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "showMsgData";
	}

	@RequestMapping(value = "/msg", method = RequestMethod.POST)
	public String msgform(@Valid @ModelAttribute MsgData msgdata,
			Errors result, Model model) {
		System.out.println("msgform: " + msgdata.getMydata());
		if (result.hasErrors()) {
			model.addAttribute("title", "Sample [ERROR]");
			model.addAttribute("message", "値を再チェックしてください。");
			return "showMsgData";
		}
		MsgDataDao<MsgData> dao = new MsgDataDaoImpl();
		dao.add(msgdata);
		return "redirect:/msg";
	}

POSTするとエラーが発生する。
フォームではMYDATA_IDは単なる文字としての値なので、これをMyDataのインスタンスに変換するための処理が必要になる。
そのために、PropertyEditor を継承するクラス MyDataPropertyEditor を用意する。

package jp.abc;

import java.beans.PropertyEditorSupport;

public class MyDataPropertyEditor extends PropertyEditorSupport {
	public String getAsText() {
		MyData value = (MyData)getValue();
		System.out.println("getAsText: " + value);
		if (value == null) {
			return "";
		} else {
			return "" + value.getId();
		}
	}

	public void setAsText(String value) {
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		MyData mydata = (MyData)dao.findById(Long.parseLong(value));
		System.out.println("setAsText: " + mydata);
		setValue(mydata);
	}
}

作成した MyDataPropertyEditor を使用するためのコードをコントローラに追加する。

@Controller
public class MyDataConroller {

	@InitBinder
	protected void initBinder(HttpServletRequest req,
			ServletRequestDataBinder binder) throws Exception {
		binder.registerCustomEditor(MyData.class, new MyDataPropertyEditor());
	}

6月30日

orderByによるエンティティのソート

getAll() メソッドの中でorderByを指定して、名前で昇順または降順でソートしてみる。

MyDataDaoCriteria.java の getAll() を変更する。

	public List<MyData> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> q = builder.createQuery(MyData.class);
		Root<MyData> root = q.from(MyData.class);
		q.select(root).orderBy(builder.desc(root.get("name")));
		list = (List<MyData>)manager.createQuery(q).getResultList();
		return list;
	}

取得位置と取得個数の指定も可能。

	public List<MyData> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> q = builder.createQuery(MyData.class);
		Root<MyData> root = q.from(MyData.class);
		q.select(root).orderBy(builder.desc(root.get("name")));
		list = (List<MyData>)manager.createQuery(q)
				.setFirstResult(2)
				.setMaxResults(2)
				.getResultList();
		return list;
	}

JPQLではID・名前・メールアドレスから検索できていたので、CriteriaAPIでも同様に検索できるようにする。
find() メソッドを変更する。

	public List<MyData> find(String fstr) {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> q = builder.createQuery(MyData.class);
		Root<MyData> root = q.from(MyData.class);
		int fid = 0;
		try {
			fid = Integer.parseInt(fstr);
		} catch (NumberFormatException e) {}
		q.select(root).where(
			builder.or(
				builder.equal(root.get("id"), fid),
				builder.like(root.<String>get("name"), "%" + fstr + "%"),
				builder.like(root.<String>get("mail"), "%" + fstr + "%")
				)
			);
		list = (List<MyData>)manager.createQuery(q).getResultList();
		return list;
	}

クリックしたら名前の昇順または降順でソートできるようにする。

まずはJSPにクリックするための矢印を追加する。

		<hr>
		<c:if test="${datalist != null}">
		<table>
			<tr>
				<th>ID</th>
				<th>名前<a href="?sort=a">↓</a>
						<a href="?sort=d">↑</a></th>
			</tr>
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<tr>
				<td><c:out value="${obj.id}" /></td>
				<td><c:out value="${obj.name}" /></td>
				</tr>
			</c:forEach>
		</table>
		</c:if>

コントローラで引数を受け取れるようにする。
引数なしでも受け付けるようにするために @RequestParam の引数に required = false を追加する。

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(@RequestParam(value = "sort", required = false) String s, Model model) {
		model.addAttribute("title");
		model.addAttribute("message", "MyDataのサンプルです。" + s);
		MyData mydata = new MyData();
		model.addAttribute("myData", mydata);

MyDataDao にソート指定できる getAll() を追加し、ソート順を指定するための定数を追加する。

package jp.abc;

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

public interface MyDataDao<T> extends Serializable {
	public static final int ASC = 1;
	public static final int DESC = 2;

	public List<T> getAll();
	public List<T> getAll(int sort);
	public T findById(long id);
	public List<T> findByName(String name);
	public void add(T data);
	public void update(T data);
	public void delete(T data);
	public void delete(long id);
	public List<T> find(String param);
}

MyDataDaoImple と MyDataDaoCriteria に、引数付 getAll() を作成する。
引数なしのgetAll() をコピーして貼り付けし、getAll(int sort) に変更すればよい。

public class MyDataDaoCriteria implements MyDataDao<MyData>{
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

	public List<MyData> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> q = builder.createQuery(MyData.class);
		Root<MyData> root = q.from(MyData.class);
		q.select(root);
		list = (List<MyData>)manager.createQuery(q).getResultList();
		return list;
	}

	public List<MyData> getAll(int sort) {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> q = builder.createQuery(MyData.class);
		Root<MyData> root = q.from(MyData.class);
		q.select(root);
		list = (List<MyData>)manager.createQuery(q).getResultList();
		return list;
	}

getAll(int)の実装を修正して、ソートできるようにする。

	public List<MyData> getAll(int sort) {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> q = builder.createQuery(MyData.class);
		Root<MyData> root = q.from(MyData.class);
		if (sort == ASC) {
			q.select(root).orderBy(builder.asc(root.get("name")));
		} else {
			q.select(root).orderBy(builder.desc(root.get("name")));
		}
		list = (List<MyData>)manager.createQuery(q).getResultList();
		return list;
	}

コントローラでは、sortパラメータなしのときは引数なしのgetAll()を、sortパラメータがあるときは、引数ありのgetAll(int)を呼ぶように変更する。

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(@RequestParam(value = "sort", required = false) String s, Model model) {
		model.addAttribute("title");
		model.addAttribute("message", "MyDataのサンプルです。" + s);
		MyData mydata = new MyData();
		model.addAttribute("myData", mydata);
		MyDataDao<MyData> dao = new MyDataDaoCriteria();
		List<MyData> list = null;
		if (s == null) {
			list = dao.getAll();
		} else {
			int v = s.equals("a") ? MyDataDao.ASC : MyDataDao.DESC;
			list = dao.getAll(v);
		}
		model.addAttribute("datalist", list);
		return "mydata";
	}

6月26日

エンティティの削除

エンティティの削除は、URLのリクエストパラメータでIDを指定するように実装する。

MyDataDaoImpleに以下のメソッドを追加する。

	public void delete(MyData data) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		MyData entity = manager.merge(data);
		manager.remove(entity);
		tx.commit();
		manager.clear();
	}

	public void delete(long id) {
		delete(findById(id));
	}

コントローラでは、以下のメソッドを追加する。

	@RequestMapping(value = "/delete", method = RequestMethod.GET)
	public String delete(@RequestParam(value = "id")int id, Model model) {
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		dao.delete(id);
		return "redirect:/mydata";
	}

JPQLを活用する

フォームで入力した値に従って検索できるようにする。

find.jspを作成する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>${title}</title>
<style>
h1 { font-size: 16pt; background-color: #ccccff; padding: 3px;}
p { color: #000066; }
</style>
</head>
<body>
  <h1>${title}</h1>
  <p>${message}</p>
  <table>
  <form action="/SpringMyApp/find" method="post">
    <tr>
      <td>FIND:</td>
      <td><input type="text" name="fstr" size="20" /></td>
    </tr>
    <tr><td></td><td><input type="submit"></td></tr>
  </form>
  </table>
  <hr>
  <c:if test="${datalist != null}">
    <table border="1">
      <c:forEach var="obj" items="${datalist}" varStatus="status">
      <tr>
        <td><c:out value="${obj.id}" /></td>
        <td><c:out value="${obj.name}" /></td>
      </tr>
      </c:forEach>
    </table>
  </c:if>
</body>
</html>

コントローラにfind.jspに対応するメソッドを追加する。

	@RequestMapping(value = "/find", method = RequestMethod.GET)
	public String find(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "検索のサンプルです。");
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		List<MyData> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "find";
	}

	@RequestMapping(value = "/find", method = RequestMethod.POST)
	public String search(@RequestParam(value = "fstr")String param, Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "「" + param + "」の検索結果");
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		List<MyData> list = dao.find(param);
		model.addAttribute("datalist", list);
		return "find";
	}

MyDataDaoに検索用メソッドを追加する。

package jp.abc;

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

public interface MyDataDao<T> extends Serializable {
	public List<T> getAll();
	public T findById(long id);
	public List<T> findByName(String name);
	public void add(T data);
	public void update(T data);
	public void delete(T data);
	public void delete(long id);
	public List<T> find(String param);
}

MyDataDaoImplでfindメソッドの実装を追加する。

	public List<MyData> find(String fstr) {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		String qstr = "from MyData where id = :fstr";
		Query q = manager.createQuery(qstr);
		q.setParameter("fstr", Long.parseLong(fstr));
		list = q.getResultList();
		manager.close();
		return list;
	}

以上のコードを追加して http://localhost:8080/SpringMyApp/find にアクセスすると、IDによる検索ができる。

複数の名前付きパラメータで検索できるようにする

MyDataDaoImplを次のように変更して、IDだけでなく、名前とメールアドレスの検索もできるようにする。

	public List<MyData> find(String fstr) {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		String qstr = "from MyData where id = :fid or name like :fname"
					+ " or mail like :fmail";
		Long fid = 0L;
		try {
			fid = Long.parseLong(fstr);
		} catch (NumberFormatException e) {
			//e.printStackTrace();
		}
		Query q = manager.createQuery(qstr);
		q.setParameter("fid", fid)
			.setParameter("fname", "%" + fstr + "%")
			.setParameter("fmail", fstr + "@%");
		list = q.getResultList();
		manager.close();
		return list;
	}

CriteriaAPI による検索

CriteriaAPI による検索を行うため、新しくMyDataDaoCriteriaクラスを作成する。
まずは、クラスの全メンバーを、MyDataDaoImplからコピーして、CriteriaAPIを使うところだけを書き換えていく。

	public List<MyData> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> q = builder.createQuery(MyData.class);
		Root<MyData> root = q.from(MyData.class);
		q.select(root);
		list = (List<MyData>)manager.createQuery(q).getResultList();
		return list;
	}

MyDataController で dao.getALl() を使っている部分を、MyDataDaoCriteria を使うように書き換える。

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(Model model) {
		model.addAttribute("title");
		model.addAttribute("message", "MyDataのサンプルです。");
		MyData mydata = new MyData();
		model.addAttribute("myData", mydata);
		MyDataDao<MyData> dao = new MyDataDaoCriteria();
		List<MyData> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "mydata";
	}

CriteriaAPIでfindの実装を書き換えてみる。

	public List<MyData> find(String fstr) {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> q = builder.createQuery(MyData.class);
		Root<MyData> root = q.from(MyData.class);
		q.select(root).where(builder.equal(root.get("name"), fstr));
		list = (List<MyData>)manager.createQuery(q).getResultList();
		return list;
	}

MyDataController の find を呼び出すところを、MyDataDaoCriteria に変更する。

	@RequestMapping(value = "/find", method = RequestMethod.GET)
	public String find(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "検索のサンプルです。");
		MyDataDao<MyData> dao = new MyDataDaoCriteria();
		List<MyData> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "find";
	}

	@RequestMapping(value = "/find", method = RequestMethod.POST)
	public String search(@RequestParam(value = "fstr")String param, Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "「" + param + "」の検索結果");
		MyDataDao<MyData> dao = new MyDataDaoCriteria();
		List<MyData> list = dao.find(param);
		model.addAttribute("datalist", list);
		return "find";
	}

6月23日

CRUDをDAOに追加する

MyDataDaoにCRUDのメソッドを追加する。

package jp.abc;

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

public interface MyDataDao<T> extends Serializable {
	public List<T> getAll();
	public T findById(long id);
	public List<T> findByName(String name);
	public void add(T data);
	public void update(T data);
	public void delete(T data);
	public void delete(long id);
}

MyDataDaoImpleにCRUDの実装を追加する。

package jp.abc;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class MyDataDaoImpl implements MyDataDao<MyData> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

	public List<MyData> getAll() {
		EntityManager manager = factory.createEntityManager();
		Query query = manager.createQuery("from MyData");
		List<MyData> list = query.getResultList();
		manager.close();
		return list;
	}

	public MyData findById(long id) {
		EntityManager manager = factory.createEntityManager();
		Query q = manager.createQuery("from MyData where id = " + id);
		return (MyData)q.getSingleResult();
	}

	public List<MyData> findByName(String name) {
		EntityManager manager = factory.createEntityManager();
		Query q = manager.createQuery("from MyData where name = " + name);
		return (List<MyData>)q.getResultList();
	}

	public void add(MyData data) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.persist(data);
		tx.commit();
		manager.close();
	}

	public void update(MyData data) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.merge(data);
		tx.commit();
		manager.clear();
	}

	public void delete(MyData data) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		MyData entity = manager.merge(data);
		manager.remove(entity);
		tx.commit();
		manager.clear();
	}

	public void delete(long id) {
		delete(findById(id));
	}
}

コントローラに、更新(Update)に関する処理を追加する。

package jp.abc;

import java.util.List;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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.bind.annotation.RequestParam;

@Controller
public class MyDataConroller {

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(Model model) {
		model.addAttribute("title");
		model.addAttribute("message", "MyDataのサンプルです。");
		MyData mydata = new MyData();
		model.addAttribute("myData", mydata);
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		List<MyData> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "mydata";
	}

	@RequestMapping(value = "/mydata", method = RequestMethod.POST)
	public String form(@Valid @ModelAttribute MyData mydata,
			Errors result, Model model) {
		if (result.hasErrors()) {
			model.addAttribute("title", "Sample[ERROR]");
			model.addAttribute("message", "値を再チェックしてください。");
			return "mydata";
		}
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		dao.add(mydata);
		return "redirect:/mydata";
	}

	@RequestMapping(value = "/update", method = RequestMethod.GET)
	public String edit(@RequestParam(value = "id") int id, Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "更新のページ");
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		MyData mydata = dao.findById(id);
		model.addAttribute("myData", mydata);
		model.addAttribute("datalist", dao.getAll());
		return "mydata";
	}

	@RequestMapping(value = "/update", method = RequestMethod.POST)
	public String update(@RequestParam(value = "id")int id,
			@Valid @ModelAttribute MyData mydata, Errors result, Model model) {
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		dao.update(mydata);
		return "redirect:/mydata";

	}
}

6月19日

メッセージのカスタマイズ

簡単な方法としては、MemoModelのインスタンス変数で指定したアノテーションに、message引数を追加することで、簡単にメッセージを変更できる。

package jp.abc;

import java.util.Date;

import javax.validation.constraints.Min;

import org.hibernate.validator.constraints.NotEmpty;

public class MemoModel {
	@NotEmpty(message = "商品名は必須です。")
	private String item;
	@Min(value = 0, message = "{value}以上の値が必要です。")
	private Integer price;
	private Date buydate;
	private String memo;

	public String getItem() {
		return item;
	}
	public void setItem(String item) {
		this.item = item;
	}
	public Integer getPrice() {
		return price;
	}
	public void setPrice(Integer price) {
		this.price = price;
	}
	public Date getBuydate() {
		return buydate;
	}
	public void setBuydate(Date buydate) {
		this.buydate = buydate;
	}
	public String getMemo() {
		return memo;
	}
	public void setMemo(String memo) {
		this.memo = memo;
	}
}

JPAによるデータベースの利用

データベースを利用するために必要なライブラリを追加する。
pom.xmlに以下の内容を追加する。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.1</version>
</dependency>
<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>2.2.9</version>
</dependency>
<dependency>
    <groupId>javax.transaction</groupId>
    <artifactId>jta</artifactId>
    <version>1.1</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>3.2.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>${spring-framework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>3.2.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring-framework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>1.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
    <exclusions>
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
        <exclusion>
            <groupId>xml-apis</groupId>
            <artifactId>xml-apis</artifactId>
        </exclusion>
    </exclusions>
</dependency>

database.propertiesファイルを作成する
src/main/resources/spring フォルダを右クリックし、[新規]-[ファイル]を選択してファイルを作成する。
ファイル名は database.properties とする。
ファイルの内容は、以下のとおりとする。(テキストとは異なるので注意)

database.driverClassName=org.hsqldb.jdbc.JDBCDriver
database.url=jdbc:hsqldb:hsql://localhost/mydata
database.username=sa
database.password=

persistence.xmlを作成する

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="2.0"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
      <property name="hibernate.hbm2ddl.auto" value="update" />
      <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbc.JDBCDriver" />
      <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:file:../workspace/SpringMyApp/db/mydata" />
    </properties>
  </persistence-unit>
</persistence>

application-config.xmlの変更

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jee
        http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
        http://www.springframework.org/schema/data/jpa
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
  
    <context:property-placeholder location="classpath:spring/database.properties"/>
  
    <bean class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" id="dataSource">
        <property name="driverClassName" value="$database.driverClassName}" />
        <property name="url" value="${database.url}" />
        <property name="username" value="${database.username}" />
        <property name="password" value="${database.password}" />
        <property name="testOnBorrow" value="true" />
        <property name="testOnReturn" value="true" />
        <property name="testWhileIdle" value="true" />
        <property name="timeBetweenEvictionRunsMillis" value="1800000" />
        <property name="numTestsPerEvictionRun" value="3" />
        <property name="minEvictableIdleTimeMillis" value="1800000" />
    </bean>
</beans>

サーバーにある以下のHSQLDBのファイルをコピーしてC:\pleiades45 の下に展開する。
\\kgakusei1\share\澤田\hsqldb\hsqldb-2.3.4.zip

hsqldbを起動するためのバッチファイルを作成する
デスクトップにテキストファイルを新規作成し、ファイル名を hsqldb.bat に変更する。
ファイルには以下の内容を記述する。

cd C:\pleiades45\hsqldb-2.3.4\hsqldb\lib
java -cp hsqldb.jar org.hsqldb.Server -database db/mydata

HSQLDBのクライアントを起動するためのバッチファイルも作成する。
hsqldbc.bat を作成する。

cd C:\pleiades45\hsqldb-2.3.4\hsqldb\lib
java -cp hsqldb.jar org.hsqldb.util.DatabaseManager

エンティティクラスの作成

Javaリソースのsrc/main/java にある jp.abc パッケージを右クリックし、[新規]-[クラス]を選択する。
クラス名 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.persistence.Table;

@Entity
@Table(name = "mydata")
public class MyData {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	private long id;
	
	@Column(length = 50, nullable = false)
	private String name;
	
	@Column(length = 200, nullable = true)
	private String mail;
	
	@Column(nullable = true)
	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;
	}
	
}

Data Access Object

DAOインタフェースを用意する。
jp.abc パッケージを右クリックし[新規]-[インタフェース]を選択する。
インタフェース名は MyDataDao とする。

package jp.abc;

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

public interface MyDataDao<T> extends Serializable {
	public List<T> getAll();
	public void add(MyData mydata);
}

DAOの実装クラスを作成する
jp.abcパッケージを右クリックし[新規]-[クラス]を選択する。
クラス名は MyDataDaoImpl とする。

package jp.abc;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class MyDataDaoImpl implements MyDataDao<MyData> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

	public List<MyData> getAll() {
		EntityManager manager = factory.createEntityManager();
		Query query = manager.createQuery("from MyData");
		List<MyData> list = query.getResultList();
		manager.close();
		return list;
	}

	public void add(MyData data) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.persist(data);
		tx.commit();
		manager.close();
	}

}

コントローラを作成する

jp.abcパッケージを右クリックして[新規]-[クラス]を選択する。
クラス名は MyDataController とする。

package jp.abc;

import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MyDataConroller {

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(Model model) {
		model.addAttribute("title");
		model.addAttribute("message", "MyDataのサンプルです。");
		MyData mydata = new MyData();
		model.addAttribute("myData", mydata);
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		List<MyData> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "mydata";
	}
}

ビューテンプレートを作成する

mydata.jsp を作成する。
src/main/webapp/WEB-INF/view を右クリックし、[新規]-[JSPファイル]を選択する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
	<head>
		<meta charset="utf-8">
		<title>${title}</title>
	</head>
	<body>
		<h1>${title}</h1>
		<p>${message}</p>
		<table>
		<form:form modelAttribute="myData">
			<tr>
				<td></td><td><form:errors path="*" element="div" />
			</tr>
			<tr>
				<td></td><td><form:hidden path="id" /></td>
			</tr>
			<tr>
				<td><form:label path="name">名前</form:label></td>
				<td><form:input path="name" size="20"/></td>
			</tr>
			<tr>
				<td><form:label path="age">年齢</form:label></td>
				<td><form:input path="age" size="20" /></td>
			</tr>
			<tr>
				<td><form:label path="mail">メール</form:label></td>
				<td><form:input path="mail" cols="20" rows="5" /></td>
			</tr>
			<tr>
				<td><form:label path="memo">メモ</form:label></td>
				<td><form:textarea path="memo" cols="20" rows="5" /></td>
			</tr>
			<tr><td><input type="submit" /></td></tr>
		</form:form>
		</table>
		<hr>
		<c:if test="${datalist != null}">
		<table>
			<tr><th>ID</th><th>名前</th></tr>
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<tr>
				<td><c:out value="${obj.id}" /></td>
				<td><c:out value="${obj.name}" /></td>
				</tr>
			</c:forEach>
		</table>
		</c:if>
	</body>
</html>

6月16日

リストで複数項目を選択する

複数項目を選択できるようにするために、SelectModelのselect1をString配列に変更する。
getterの戻り値の型と、setterの引数の型も変更する。

package jp.abc;

public class SelectModel {
	private String[] select1;

	public String[] getSelect1() {
		return select1;
	}

	public void setSelect1(String[] select1) {
		this.select1 = select1;
	}
}

コントローラもテキストの通りに変更する。

package jp.abc;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class SelectController {
	private List<ListDataModel> getList() {
		List<ListDataModel> list = new ArrayList<ListDataModel>();
		list.add(new ListDataModel("マック", "Mac"));
		list.add(new ListDataModel("ウィンドウズ", "Windows"));
		list.add(new ListDataModel("リナックス", "Linux"));
		list.add(new ListDataModel("アイフォン", "iOS"));
		list.add(new ListDataModel("アンドロイド", "Android"));
		return list;
	}

	@RequestMapping(value = "/select", method=RequestMethod.GET)
	public String select(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "Selectのサンプルです。");
		SelectModel sm = new SelectModel();
		sm.setSelect1(new String[]{"Mac"});
		model.addAttribute("selectModel", sm);
		model.addAttribute("optionlist", getList());
		return "select";
	}

	@RequestMapping(value = "/select", method = RequestMethod.POST)
	public String form(@ModelAttribute SelectModel sm, Model model) {
		model.addAttribute("title", "Sample");
		String[] sels = sm.getSelect1();
		String res = "<ol>";
		for (String item : sels) {
			res += "<li>" + item + "</li>";
		}
		res += "</ol>";
		model.addAttribute("message", res);
		model.addAttribute("selectModel", sm);
		model.addAttribute("optionlist", getList());
		return "select";
	}
}

JSPはmultiple属性をtrueに変更する。

		<form:select path="select1" size="5" multiple="true">

リストの項目を複数選択する場合は、Ctrlキーを押しながら選択する。

バリデーションの利用

サンプルとして買い物メモを作成する。
テキストではFormModelを変更しているが、ここではMemoModelを新規作成する。

package jp.abc;

import java.util.Date;

public class MemoModel {
	private String item;
	private Integer price;
	private Date buydate;
	private String memo;

	public String getItem() {
		return item;
	}
	public void setItem(String item) {
		this.item = item;
	}
	public Integer getPrice() {
		return price;
	}
	public void setPrice(Integer price) {
		this.price = price;
	}
	public Date getBuydate() {
		return buydate;
	}
	public void setBuydate(Date buydate) {
		this.buydate = buydate;
	}
	public String getMemo() {
		return memo;
	}
	public void setMemo(String memo) {
		this.memo = memo;
	}
}

JSPもmemo.jspとして新規作成する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
	<head>
		<meta charset="utf-8">
		<title>${title}</title>
	</head>
	<body>
		<h1>${title}</h1>
		<p>${message}</p>
		<table>
		<form:form modelAttribute="memoModel">
			<tr>
				<td><form:label path="item">商品名</form:label></td>
				<td><form:input path="item" size="20"/></td>
			</tr>
			<tr>
				<td><form:label path="price">金額</form:label></td>
				<td><form:input path="price" size="20" /></td>
			</tr>
			<tr>
				<td><form:label path="memo">メモ</form:label></td>
				<td><form:textarea path="memo" cols="20" rows="5" /></td>
			</tr>
			<tr><td><input type="submit" /></td></tr>
		</form:form>
		</table>
		<hr>
		<c:if test="${datalist != null}">
		<table>
			<tr><th>商品名</th><th>価格</th></tr>
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<tr>
				<td><c:out value="${obj.item}" /></td>
				<td><c:out value="${obj.price}" /></td>
				</tr>
			</c:forEach>
		</table>
		</c:if>
	</body>
</html>

コントローラもMemoControllerとして新規作成する。
まずはGETメソッドの部分だけ作成して動作確認する。
ボタンを押して送信すると POST not supported のエラーとなる。

package jp.abc;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MemoController {
	private List<MemoModel> buylist = new ArrayList<MemoModel>();

	@RequestMapping(value = "/memo", method = RequestMethod.GET)
	public String memo(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "買い物メモです");
		MemoModel mm = new MemoModel();
		model.addAttribute("memoModel", mm);
		model.addAttribute("datalist", buylist);
		return "memo";
	}
}

GETメソッドが正常に動作し、POSTでエラーとなることを確認したら、POSTに対応するメソッドを追加する。

	@RequestMapping(value = "/memo", method = RequestMethod.POST)
	public String form(@ModelAttribute MemoModel mm,
			BindingResult result, Model model) {
		buylist.add(mm);
		model.addAttribute("title", "Sample");
		String res = "<ol>";
		res += "<li>" + mm.getItem() + "</li>";
		res += "<li>" + mm.getPrice() + "</li>";
		res += "<li>" + mm.getMemo() + "</li>";
		res += "<li>" + Calendar.getInstance().getTime() + "</li>";
		res += "</ol>";
		res += "<p>" + buylist.size() + "</p>";
		model.addAttribute("message", res);
		model.addAttribute("datalist", buylist);
		model.addAttribute("memoModel", new MemoModel());
		return "memo";
	}

バリデーション用のライブラリをロードする

pom.xml を開き、最後の dependencies タグの手前に以下の設定を追加する。

		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.1.0.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.0.1.Final</version>
		</dependency>

追加して保存したら、「プロジェクトの更新」と「maven install」を実行する。

エラーが解決できない場合、次の手順を試してみること。
・tomcatサーバーを停止→tomcatサーバーを削除→tomcatサーバーを作成

それでもエラーが解決できない場合、
[ユーザー]\.m2\repository 以下のファイルを全て削除し、「プロジェクトの更新」と「Maven install」を再実行する。

MemoModel.java にバリデーションのアノテーションを追加する。

package jp.abc;

import java.util.Date;

import javax.validation.constraints.Min;

import org.hibernate.validator.constraints.NotEmpty;

public class MemoModel {
	@NotEmpty
	private String item;
	@Min(0)
	private Integer price;
	private Date buydate;
	private String memo;

	public String getItem() {
		return item;
	}
	public void setItem(String item) {
		this.item = item;
	}
	public Integer getPrice() {
		return price;
	}
	public void setPrice(Integer price) {
		this.price = price;
	}
	public Date getBuydate() {
		return buydate;
	}
	public void setBuydate(Date buydate) {
		this.buydate = buydate;
	}
	public String getMemo() {
		return memo;
	}
	public void setMemo(String memo) {
		this.memo = memo;
	}
}

JSPにエラーメッセージを表示する要素を追加する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
	<head>
		<meta charset="utf-8">
		<title>${title}</title>
	</head>
	<body>
		<h1>${title}</h1>
		<p>${message}</p>
		<table>
		<form:form modelAttribute="memoModel">
			<tr>
				<td></td><td><form:errors path="*" element="div" />
			</tr>
			<tr>
				<td><form:label path="item">商品名</form:label></td>
				<td><form:input path="item" size="20"/></td>
			</tr>
			<tr>
				<td><form:label path="price">金額</form:label></td>
				<td><form:input path="price" size="20" /></td>
			</tr>
			<tr>
				<td><form:label path="memo">メモ</form:label></td>
				<td><form:textarea path="memo" cols="20" rows="5" /></td>
			</tr>
			<tr><td><input type="submit" /></td></tr>
		</form:form>
		</table>
		<hr>
		<c:if test="${datalist != null}">
		<table>
			<tr><th>商品名</th><th>価格</th></tr>
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<tr>
				<td><c:out value="${obj.item}" /></td>
				<td><c:out value="${obj.price}" /></td>
				</tr>
			</c:forEach>
		</table>
		</c:if>
	</body>
</html>

コントローラを修正する。
エラーチェックはPOSTメソッドが呼ばれる前に行われている。

package jp.abc;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MemoController {
	private List<MemoModel> buylist = new ArrayList<MemoModel>();

	@RequestMapping(value = "/memo", method = RequestMethod.GET)
	public String memo(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "買い物メモです");
		MemoModel mm = new MemoModel();
		model.addAttribute("memoModel", mm);
		model.addAttribute("datalist", buylist);
		return "memo";
	}

	@RequestMapping(value = "/memo", method = RequestMethod.POST)
	public String form(@Valid @ModelAttribute MemoModel mm,
			BindingResult result, Model model) {
		if (result.hasErrors()) {
			model.addAttribute("title", "Sample [ERROR]");
			model.addAttribute("message", "値を再チェックしてください!");
		} else {
			buylist.add(mm);
			model.addAttribute("title", "Sample");
			String res = "<ol>";
			res += "<li>" + mm.getItem() + "</li>";
			res += "<li>" + mm.getPrice() + "</li>";
			res += "<li>" + mm.getMemo() + "</li>";
			res += "<li>" + Calendar.getInstance().getTime() + "</li>";
			res += "</ol>";
			res += "<p>" + buylist.size() + "</p>";
			model.addAttribute("message", res);
			model.addAttribute("memoModel", new MemoModel());
		}
		model.addAttribute("datalist", buylist);
		return "memo";
	}
}