8月29日

エンティティを作成する

ひとりひとりの得点に対応するエンティティを作成する。試験成績なので Result とする。
プロジェクトエクスプローラでJavaリソース以下の src/main/java にある、jp.abc パッケージを右クリック。[新規]-[クラス]を選択。
名前に Result を入力して完了。

Result.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.Table;

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

	@Column(nullable = false)
	private String number;

	@Column(nullable = false)
	private int score;

	public long getId() {
		return id;
	}

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

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}
}

edit.jspの変更

エンティティを作ったので、edit.jsp もエンティティ経由でデータをやりとりするように変更する。

edit.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}</title>
</head>
<body>

<h1>${title}</h1>

<p>受験番号と得点を入力してください</p>
<form:form modelAttribute="result">
  <form:label path="number">受験番号</form:label>
  <form:input path="number" />
  <form:label path="score">得点</form:label>
  <form:input path="score" />
  <br/>
  <input type="submit" value="登録" />
</form:form>

</body>
</html>

コントローラからJSPにデータを渡す

edit.jspでエンティティを参照するようにしたので、JSPにエンティティを渡すように修正する。

EditController.java

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

	@RequestMapping(value = "/edit", method = RequestMethod.GET)
	public String home(Model model) {
		model.addAttribute("title", "成績の入力");
		Result r = new Result();
		model.addAttribute("result", r);
		return "edit";
	}

}

動作確認

エンティティを使うように変更したので、動作するか確認する。

入力チェックを追加する

まずは登録ボタンを押したときにエラーにならないようにする。
POSTメソッドのリクエストを受け取るようにする。

EditController.java

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

	@RequestMapping(value = "/edit", method = RequestMethod.GET)
	public String home(Model model) {
		model.addAttribute("title", "成績の入力");
		Result r = new Result();
		model.addAttribute("result", r);
		return "edit";
	}

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	public String add(Model model) {
		model.addAttribute("title", "成績の入力");
		Result r = new Result();
		model.addAttribute("result", r);
		return "edit";
	}
}

入力チェックの追加

入力チェックは、テキストp.230~240を参考にする。

バリデーション用ライブラリの追加

pom.xmlに以下のコードを追加する。

pom.xml

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

エンティティにバリデーションのアノテーションを追加する

Result.java

	@NotEmpty
	@Length(min=3, max=10)
	@Column(nullable = false)
	private String number;

	@Range(min=0, max=100)
	@Column(nullable = false)
	private int score;

コントローラにバリデーションのコードを追加する

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	public String add(@Valid @ModelAttribute Result result,
			BindingResult errors, Model model) {
		model.addAttribute("title", "成績の入力");
		Result r = new Result();
		model.addAttribute("result", r);
		return "edit";
	}

JSPにエラー表示用のコードを追加する

エラー表示用のタグ <form:errors /> を追加する。

edit.jsp

<p>受験番号と得点を入力してください</p>
<form:form modelAttribute="result">
  <form:errors path="*" element="div"/><br/>
  <form:label path="number">受験番号</form:label>

HSQLDBの用意

exam プロジェクトにデータベースアクセスのためのライブラリを追加する。

pom.xml の最後の </dependencies>の直前に以下の内容を追加する。

<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>4.0.0.RELEASE</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>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.7.4</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の作成

以下の spring フォルダを右クリックし、[新規]-[ファイル]を選択
exam
+ src
  + main
  + resources
   + spring

ファイル名に database.properties を入力して完了。
テキストp.270 のリスト5-4 の内容を入力する。

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

persistence.xmlの作成

以下の resources フォルダを右クリックし、[新規]-[フォルダー]を選択
exam
+ src
  + main
  + resources

フォルダ名に META-INF を入力して完了。
作成した META-INF フォルダを右クリックし、[新規]-[ファイル]を選択
ファイル名に persistence.xml を入力して完了。
作成した 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/exam" />
    </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>

DAOのインタフェースと実装

DAOインタフェースの用意

プロジェクトエクスプローラでJavaリソース以下の src/main/java にある、jp.abc パッケージを右クリック。[新規]-[インタフェース]を選択。
名前に ResultDao を入力して完了。

ResultDao.java

package jp.abc;
 
import java.io.Serializable;
import java.util.List;
 
public interface ResultDao extends Serializable {
    public List<Result> getAll();
    public void add(Result result);
}

DAOの実装を追加する

DAOの実装を追加する。

ResultDaoImpl.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.Query;
 
public class ResultDaoImpl implements ResultDao {
    private static EntityManagerFactory factory =
        Persistence.createEntityManagerFactory("persistenceUnit");
 
    public List<Result> getAll() {
        EntityManager manager = factory.createEntityManager();
        Query query = manager.createQuery("from Result");
        List<Result> list = query.getResultList();
        manager.close();
        return list;
    }
 
    public void add(Result result) {
        EntityManager manager = factory.createEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        manager.persist(result);
        transaction.commit();
        manager.close();
    }
}

コントローラからJSPに登録済みのリストをわたす

EditController.java

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	public String add(@Valid @ModelAttribute Result result,
			BindingResult errors, Model model) {
		ResultDao dao = new ResultDaoImpl();
		if (errors.hasErrors()) {
			model.addAttribute("title", "成績の入力");
		} else {
			model.addAttribute("title", "成績の入力");
			model.addAttribute("result", result);
			dao.add(result);
		}
		List<Result> list = dao.getAll();
		model.addAttribute("list", list);
		return "edit";
	}

ControllerとJSP

データ登録画面に登録済みのリストを表示する

edit.jsp

<!DOCTYPE html>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ 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}</title>
</head>
<body>

<h1>${title}</h1>

<p>受験番号と得点を入力してください</p>
<form:form modelAttribute="result">
  <form:errors path="*" element="div" cssStyle="color:red" /><br/>
  <form:label path="number">受験番号</form:label>
  <form:input path="number" />
  <form:label path="score">得点</form:label>
  <form:input path="score" />
  <br/>
  <input type="submit" value="登録" />
</form:form>
<hr/>
<c:if test="${list != null}">
  <table>
  <tr><th>ID</th><th>受験番号</th><th>得点</th></tr>
  <c:forEach var="r" items="${list}">
    <tr>
      <td>${r.id}</td>
      <td>${r.number}</td>
      <td>${r.score}</td>
    </tr>
  </c:forEach>
  </table>
</c:if>

</body>
</html>

8月28日

今までの復習をかねて、最初からWebアプリをつくってみる。

プロジェクト:exam

ID、受験番号、成績を格納するDBを作成する。
受験番号と成績を入力したら、DBに登録する。
受験番号を入力し、成績を検索する。

Springプロジェクトを作成する

テキストp.40~p.44と6月2日のページを参考にする。
プロジェクトを作成し、http://locahost:8080/exam/ にアクセスすると、Click to enter を表示する。

プロジェクトの更新

exam プロジェクトを右クリックし、[Maven]-[プロジェクトの更新]を選択。

Mavenインストール

exam プロジェクトを右クリックし、[実行]-[Maven install]を選択。

Webアプリの実行

サーバータブでTomcatサーバーを起動。
サーバータブで起動したTomcatサーバーにexamアプリを追加。
http://localhost:8080/exam/ にアクセスする。

検索画面を作る

HomeControllerを作成する。(p.163)
home.jspを作成する。(テキストではshowMessage.jspを表示している)
mvc-config.xmlを修正する。(p.167)

HomeController.java

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

	@RequestMapping(value = "/home", method = RequestMethod.GET)
	public String home(Model model) {
		model.addAttribute("title", "成績の検索");
		return "home";
	}
}

home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>${title}</title>
</head>
<body>

<h1>${title}</h1>

</body>
</html>

文字化け対策をする

テキストp.187を参照し、CharacterEncodingFilterを追加する。

入力フォームを作成する

home.jsp に受験番号を入力するフォームを追加する。

<!DOCTYPE html>
<%@ 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>
</head>
<body>

<h1>${title}</h1>

<p>受験番号を入力してください</p>
<form action="/exam/home" method="post">
    <input type="text" name="number" />
    <input type="submit" />
</form>

</body>
</html>

exam-1

コントローラで検索リクエストを受け取る

HomeController.java に query() メソッドを追加する。
検索結果は result.jsp で表示する。
リクエストパラメータは @RequestParam で受け取る。
得点は適当な値を設定しておく。

検索結果を表示する

result.jsp で検索結果を表示する。まだデータベースがないので、HomeControllerで適当な値を設定しておく。

<!DOCTYPE html>
<%@ 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>
</head>
<body>

<h1>${title}</h1>
<p>
受験番号 ${number} の得点は ${score} です。
</p>

<a href="/exam/home">戻る</a>
</body>
</html>

exam-2

データ登録画面を作成する

edit.jsp

<!DOCTYPE html>
<%@ 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>
</head>
<body>

<h1>${title}</h1>

<p>受験番号と得点を入力してください</p>
<form action="/exam/edit">
受験番号<input type="text" name="number"/>
得点<input type="number" name="score" />
<br/>
<input type="submit" value="登録"/>
</form>
</body>
</html>

データ登録画面を表示するためのコントローラを作成する

EditController.java では、http://localhost:8080/exam/edit をリクエストされたら、edit.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 EditController {

	@RequestMapping(value = "/edit", method = RequestMethod.GET)
	public String home(Model model) {
		model.addAttribute("title", "成績の入力");
		return "edit";
	}
}

データ登録画面を表示する

http://localhost:8080/exam/edit にアクセスすると、データ登録画面を表示する。

exam-4

7月14日

Criteria APIを使用したクエリ

Webページにページングを追加する

Criteria API での検索には、setFirstResult() で先頭の位置を指定し、setMaxResults()で取得するデータの最大数を指定する。

MyDataDaoImpl.java

	public List<MyData> getList() {
		int offset = 0;
		int limit = 5;
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> query = builder.createQuery(MyData.class);
		Root<MyData> root = query.from(MyData.class);
		query.select(root);
		list = manager.createQuery(query)
				.setFirstResult(offset)
				.setMaxResults(limit)
				.getResultList();
		return list;
	}

JSPにページング用のリンクを追加する。

mydata.jsp

	<a href="mydata?offset=0">1</a>&nbsp;<a href="mydata?offset=5">2</a>

コントローラでリクエストパラメータを受け取る。@RequestParam アノテーションを追加し、Integer型のoffsetパラメータを追加する。

MyDataController.java

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

DAOにパラメータつきのgetList()をオーバーロードで追加する。

MyDataDao.java

public interface MyDataDao <T> extends Serializable {
	public List<T> getAll();
	public List<T> getList();
	public List<T> getList(int offset, int max);
	public List<T> find(String param);

DAOの実装にgetList()を追加する。

MyDataDaoImpl.java

	public List<MyData> getList(int offset, int max) {
		EntityManager manager = factory.createEntityManager();
		List<MyData> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<MyData> query = builder.createQuery(MyData.class);
		Root<MyData> root = query.from(MyData.class);
		query.select(root);
		list = manager.createQuery(query)
				.setFirstResult(offset)
				.setMaxResults(max)
				.getResultList();
		return list;
	}

コントローラでリクエストパラメータから受け取ったオフセットをDAOに渡すようにする。

MyDataController.java

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(@RequestParam(required = false) Integer offset, Model model) {
		model.addAttribute("title", "Sample " + offset);
		model.addAttribute("message", "MyDataのサンプルです");
		MyData mydata = new MyData();
		model.addAttribute("myData", mydata);
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		int off = offset == null ? 0 : offset;
		List<MyData> list = dao.getList(off, 5);
		model.addAttribute("datalist", list);
		return "mydata";
	}

7月7日

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

Tomcatサーバーを再起動するとデータベースに保存したデータが消えてしまう問題を修正する。

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/mydatabase" />
    </properties>
  </persistence-unit>
</persistence>

database.properties

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

データを削除するときに例外が発生する問題を修正する。
MyDataDaoImpl.java

	public void delete(MyData mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		manager.remove(manager.merge(mydata));
		transaction.commit();
		manager.close();
	}

複数の名前つきパラメータ

入力された文字列を、idだけでなく、名前とメールアドレスからも検索できるようにする。

MyDataDaoImple.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.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();
		String sql = "from MyData where id = " + id;
		MyData mydata = (MyData)manager.createQuery(sql).getSingleResult();
		return mydata;
	}

	public MyData findByName(String name) {
		return null;
	}

	public List<MyData> find(String param) {
		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(param);
		} catch (NumberFormatException e) {}
		Query query = manager.createQuery(qstr)
					 .setParameter("fid", fid)
					 .setParameter("fname", "%" + param + "%")
					 .setParameter("fmail", "%" + param + "%");
		list = query.getResultList();
		manager.close();
		return list;
	}

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

	public void update(MyData mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		manager.merge(mydata);
		transaction.commit();
		manager.close();
	}

	public void delete(MyData mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		manager.remove(manager.merge(mydata));
		transaction.commit();
		manager.close();
	}

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

データベースマネージャからSQLをダイレクトに実行する方法

  1. 以下のファイルをローカルにコピーする。
    \\KGAKUSEI1\share\澤田\hsqldb-2.3.2.zip
  2. C:\Users\se3\db の下に解凍する。
  3. コマンドプロンプトを起動。
  4. 以下のコマンドを実行する
    > cd C:\Users\se3\db\hsqldb-2.3.2\hsqldb
    > java -cp lib/hsqldb.jar org.hsqldb.util.DatabaseManager
    

hsqldb

spring12

hsqldbmanager

「?」による番号指定のパラメータと @NamedQuery による名前付きクエリーはパス(余裕がある人は試してもよい)。

Criteria APIによる検索

MyDataDao.javaにgetList()メソッドを追加。

package jp.abc;

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

public interface MyDataDao <T> extends Serializable {
	public List<T> getAll();
	public List<T> getList();
	public List<T> find(String param);
	public T findById(long id);
	public 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.java

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

MyDataController.java
mydata()メソッド内の dao.getAll() を dao.getList() に書き換える。

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

MyDataDao.java に search()メソッドを追加する。

package jp.abc;

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

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

MyDataDaoImpl.java にも search()メソッドを追加する。

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

MyDataController.java で dao.find() を呼び出しているところを search() に書き換える。

	@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.getList();
		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.search(param);
		model.addAttribute("datalist", list);
		return "find";
	}

7月3日

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

ファイルに保存するように設定を修正

src/main/resources/spring/database.properties

database.driverClassName=org.hsqldb.jdbc.JDBCDriver
database.url=jdbc:hsqldb:file:../workspace/SpringMyApp/db/mydata
database.username=sa
database.password=

src/main/resources/META-INF/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="create" />
      <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>

IDでの検索機能

find.jsp

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

<html>
<head>
	<meta charset="utf-8">
	<title>${title}</title>
</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>

MyDataController.java

	@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.java

package jp.abc;

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

public interface MyDataDao <T> extends Serializable {
	public List<T> getAll();
	public List<T> find(String param);
	public T findById(long id);
	public 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.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.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();
		String sql = "from MyData where id = " + id;
		MyData mydata = (MyData)manager.createQuery(sql).getSingleResult();
		return mydata;
	}

	public MyData findByName(String name) {
		return null;
	}

	public List<MyData> find(String param) {
		EntityManager manager = factory.createEntityManager();
		Query query = manager.createQuery("from MyData where id = " + param);
		List<MyData> list = query.getResultList();
		manager.close();
		return list;
	}

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

	public void update(MyData mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		manager.merge(mydata);
		transaction.commit();
		manager.close();
	}

	public void delete(MyData mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		manager.remove(mydata);
		transaction.commit();
		manager.close();
	}

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

spring10

インメモリモードやファイルモードがうまく動作しないので、サーバーモードで動作させる。
Eclipseマーケットプレイスから HSQLDB Database Server Plugin をインストールする。

spring11

6月30日

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

6月26日のページに掲載されたコードを入力して動作確認する。

http://localhost:8080/SpringMyApp/mydataにアクセスして、入力フォームが表示されること。

入力フォームに入力して送信すると、画面の下に入力した名前が追加されること。

spring9

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

<html>
<head>
	<meta charset="utf-8">
	<title>${title}</title>
</head>

<body>
	<h1>${title}</h1>
	<p>${message}</p>
	<table>
	<form:form modelAttribute="myData">
		<form:errors path="*" element="div" />
		<form:hidden path="id"/>
		<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" size="20" /></td>
		</tr>
		<tr>
			<td><form:label path="memo">メモ</form:label></td>
			<td><form:input path="memo" cols="20" rows="5" /></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></tr>
		<c:forEach var="obj" items="${datalist}" varStatus="status">
			<tr>
				<td><c:out value="${obj.id}" />
				<td><c:out value="${obj.name}" />
			</tr>
		</c:forEach>
	</table>
	</c:if>
</body>
</html>

エンティティの基本操作

インタフェースにメソッドを追加する。

MyDataDao.java

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 T findByName(String name);
	public void add(T data);
	public void update(T data);
	public void delete(T data);
	public void delete(long id);
}

実装クラスにメソッドだけを追加してコンパイルエラーをなくす。

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) {
		return null;
	}

	public MyData findByName(String name) {
		return null;
	}

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

	public void update(MyData mydata) {
		//
	}

	public void delete(long id) {
		//
	}

	public void delete(MyData mydata) {
		//
	}
}

DAOの実装を追加する。
ただし、データベースアクセスのコードは省略しておく。
まずはURLにアクセスしたときに動作するようにする。

MyDataDaoImple.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.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) {
		return null;
	}

	public MyData findByName(String name) {
		return null;
	}

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

	public void update(MyData mydata) {
		//
	}

	public void delete(long id) {
		//
	}

	public void delete(MyData mydata) {
		//
	}
}

コントローラに実装を追加する。
テキストでは

    return "redirect:/helo";

としているが、ここでは

    return "redirect:/mydata";

とする。

MyDataController.java

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

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(Model model) {
		model.addAttribute("title", "Sample");
		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) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "更新のページ");
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		dao.update(mydata);
		return "redirect:/update?id=" + mydata.getId();
	}

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

}

MyDataDaoImple.java に findMyId() の実装を追加すると、
http://localhost:8080/SpringMyApp/update?id=1
にアクセスしたときに、id=1のデータがフォームに表示される。

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

update() メソッドの実装を追加すると、データの更新ができるようになる。

	public void update(MyData mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		manager.merge(mydata);
		transaction.commit();
		manager.close();
	}

MyDataDaoImple.javaに削除を実装する。

	public void delete(MyData mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction transaction = manager.getTransaction();
		transaction.begin();
		manager.remove(mydata);
		transaction.commit();
		manager.close();
	}

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

6月19日

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

MemoFormModel.java のバリデーション用アノテーションにメッセージ引数を追加することで、エラーメッセージをカスタマイズできる。

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

未入力でクエリ送信すると、カスタマイズされたエラーメッセージを表示した。

spring7

ValidatorMessages.propertiesを追加する

  1. Javaリソースの下の src/main/resources を右クリック
  2. [新規]-[その他]を選択
  3. 「一般」-「ファイル」を選択して「次へ」をクリック
  4. ファイル名に ValidatorMessages.properties を入力して「完了」をクリック

ファイルに以下の内容を入力。

NotEmpty = may not be empty.
Max = must be less than or equal to {1}.
Min = must be greater than or equal to {1}.
NotNull = may not be null.

日本語のエラーメッセージファイルも用意する。

  1. 作成した ValidatorMessages.properties を右クリックしてコピーする。
  2. src/java/resources を右クリックして貼り付ける。
  3. ファイル名を ValidatorMessages_ja.properties に変更して「OK」をクリック。

ファイルに以下の内容を入力して保存。

NotEmpty = {0} には、何か入力してください。
Max = {0} は、{1} 以上は入力できません。
Min = {0} は、{1} 以下は入力できません。
NotNull = {0} には、何か入力してください。

src/main/java/webapp/WEB-INF/mvc-config.xml に以下の内容を追加する。この設定によって、ValidatorMessages.properties と ValidatorMessages_ja.properties がエラーメッセージのファイルとして読み込まれる。

	<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<property name="basename" value="classpath:ValidatorMessages" />
	</bean>

spring8

ValidatorMessages_ja.properties に記述したメッセージを表示しない場合は、以下の操作を試してみる。

  • サーバーを再起動する
  • サーバーを右クリックして「クリーン」する
  • ファイル名が間違っていないか確認する

オリジナルのバリデータを作成する

金額をチェックするための PriceValidator を作成する。

jp.abc を右クリックして、[新規]-[クラス]を選択する。
クラス名: PriceValidator
インタフェース: ConstraintValidator<Price, Integer>

package jp.abc;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PriceValidator implements ConstraintValidator<Price, Integer> {

	public void initialize(Price price) {
	}

	public boolean isValid(Integer input, ConstraintValidatorContext context) {
		if (input == null) {
			return false;
		}
		return true;
	}

}

jp.abc を右クリックして、[新規]-[注釈]を選択する。
名前: Price

package jp.abc;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Constraint(validatedBy = PriceValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Price {
	String message() default "please input a price.";
	Class<?>[] groups() default {};
	Class<? extends Payload>[] payload() default {};
}

MemoFormModel.java の金額部分のアノテーションを @Price に変更する。

public class MemoFormModel {
	@NotEmpty
	private String item;
	@Price
	private Integer price;
	private Date buydate;
	private String memo;

マイナスの金額をエラーにする。

PriceValidator.java を変更する。

	public boolean isValid(Integer input, ConstraintValidatorContext context) {
		if (input == null) {
			return false;
		}
		return input.intValue() >= 0;
	}

6月16日

バリデーションの利用

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

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>

Missing artifact のエラーが出た人は、以下のサイトに書いてある内容を試してみること。
Resolve Error “ArtifactTransferException: Could not transfer artifact” or “Failure to Transfer” in Ma

  1. エクスプローラで C:\Users\se3\.m2 フォルダを選択
  2. lastUpdated で検索する
  3. ファイル名が lastUpdated で終わるファイルをすべて削除する
  4. プロジェクトエクスプローラでプロジェクトを右クリックし、[Maven]-[プロジェクトの更新]を実行する

MemoFormModelの変更

MemoFormModel.java にアノテーションを追加する。

public class MemoFormModel {
	@NotEmpty
	private String item;
	@Min(0)
	private Integer price;
	private Date buydate;
	private String memo;
	:
	以下略

memo.jspの変更

エラー表示用のタグを追加する。

	<table>
	<form:form modelAttribute="formModel">
		<tr>
			<td></td>
			<td><form:errors path="*" element="div" /></td>
		</tr>
		<tr>
			<td><form:label path="item">商品名</form:label></td>
			<td><form:input path="item" size="20"/></td>
		</tr>

MyMemoControllerの変更

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

spring6

なぜかJSPにメッセージが埋め込まれない。
こちらを参考にして、validation のテストを作ってみた。

package jp.abc;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.junit.Test;

public class MemoFormModelTest {

	@Test
	public void testItem() {
		ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
		Validator v = vf.getValidator();
		MemoFormModel m = new MemoFormModel();
		Set&lt;ConstraintViolation&lt;MemoFormModel>> violations = v.validate(m);
        assertThat("", violations.size(), is(2));
        for (ConstraintViolation&lt;MemoFormModel> violation : violations) {
            System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
        }

	}

}

コンソールには以下の出力があるので、メッセージは生成できている。

INFO  Version - HV000001: Hibernate Validator 5.0.1.Final
item may not be empty
price may not be null

以下のページに書かれいる対策で表示されるようになった。
Spring 3 MVC – form:errors not showing the errors

MyMemoController.java

	@RequestMapping(value = "/memo", method = RequestMethod.POST)
	public String form(@Valid @ModelAttribute("formModel") MemoFormModel fm,
					   BindingResult result, Model model) {

または、JSPとのやりとりに使っているFormModelを特定するためのキー文字列 formModel を、MemoFormModel の先頭1文字を小文字にしてやれば、エラーメッセージを表示されるようになる。

MyMemoController.java

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

memo.jsp

	<form:form modelAttribute="memoFormModel">
		<tr>
			<td></td>
			<td><form:errors path="*" element="div" /></td>
		</tr>

6月9日

フォームの基本(続き)

複数のチェックボックスをまとめて作る

FormModel.java

package jp.abc;

public class FormModel {
	private String input1;
	private String pass1;
	private String area1;
	private boolean check1;
	private String[] checks;

	public String getInput1() {
		return input1;
	}

	public void setInput1(String input1) {
		this.input1 = input1;
	}

	public String getPass1() {
		return pass1;
	}

	public void setPass1(String pass1) {
		this.pass1 = pass1;
	}

	public String getArea1() {
		return area1;
	}

	public void setArea1(String area1) {
		this.area1 = area1;
	}

	public boolean isCheck1() {
		return check1;
	}

	public void setCheck1(boolean check1) {
		this.check1 = check1;
	}

	public String[] getChecks() {
		return checks;
	}

	public void setChecks(String[] checks) {
		this.checks = checks;
	}
}

showMessage.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 charset="utf-8">
		<title>Welcome</title>
	</head>
	<body>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="formModel">
			<tr><td><form:input path="input1"/></td></tr>
			<tr><td><form:password path="pass1" showPassword="on" /></td></tr>
			<tr><td><form:textarea path="area1" cols="40" rows="3"/></td></tr>
			<tr><td><form:checkbox path="check1" label="checkbox 1"/></td></tr>
			<tr><td><form:checkboxes items="${checkItems}" path="checks" delimiter=" "/></td></tr>
			<tr><td><input type="submit" /></td></tr>
		</form:form>
		</table>
	</body>
</html>

MyAppController.java

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 MyAppController {
	private List<String> getList() {
		List<String> list = new ArrayList<String>();
		list.add("Mac OS X");
		list.add("Windows");
		list.add("Linux");
		return list;
	}

	@RequestMapping(value = "/helo", method = RequestMethod.GET)
	public String helo(Model model) {
		FormModel fm = new FormModel();
		fm.setCheck1(true);
		fm.setChecks(new String[]{"Windows"});
		model.addAttribute("title", "ModelAndView sample");
		model.addAttribute("message", "これはModelAndViewのテストです。");
		model.addAttribute("formModel", fm);
		model.addAttribute("checkItems", getList());
		return "showMessage";
	}

	@RequestMapping(value = "/helo", method = RequestMethod.POST)
	public String form(@ModelAttribute FormModel fm, Model model) {
		String[] selected = fm.getChecks();
		String res = "<ul><li>" + fm.getInput1()
				   + "</li><li>" + fm.getPass1()
				   + "</li><li>" + fm.getArea1()
				   + "</li><li> checked:" + fm.isCheck1()
				   + "</li></ul>"
				   + "<ol>";
		for (String sel : selected) {
			res += "<li>" + sel + "</li>";
		}
		res += "</ol>";
		model.addAttribute("title", "Sample");
		model.addAttribute("message", res);
		model.addAttribute("formModel", fm);
		model.addAttribute("checkItems", getList());
		return "showMessage";
	}
}

spring3

ラジオボタンを使用する

テキストとは異なる方法で実装する。

新しくRadioFormModelクラスを作る。

  1. プロジェクトエクスプローラで SpringMyApp→Javaリソース→src/main/java→jp.abcを右クリック
  2. [新規]-[クラス]を選択する
  3. クラス名を RadioFormModel にして完了
  4. RadioFormModelクラスに private String radio1; を追加
  5. [ソース]-[getterおよびsetterの生成]でgetter/setterを生成
package jp.abc;

public class RadioFormModel {
	private String radio1;

	public String getRadio1() {
		return radio1;
	}

	public void setRadio1(String radio1) {
		this.radio1 = radio1;
	}
}

radiosample.jsp を作成する。

  1. プロジェクトエクスプローラで src→main→webapp→WEB-INF→view を右クリック
  2. [新規]-[JSP File]を選択
  3. ファイル名は radiosample.jsp で「完了」

radiosample.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<title>Welcome</title>
	</head>

<body>
	<h1>${title}</h1>
	<p>${message}</p>
	<table>
	<form:form modelAttribute="formModel">
		<tr><td>
		<form:radiobutton path="radio1" name="radio1"
			label="男性" value="male"/>
		<form:radiobutton path="radio1" name="radio1"
			label="女性" value="female"/>
		</td></tr>
		<tr><td><input type="submit" /></td></tr>
	</form:form>
	</table>
</body>

</html>

MyRadioController を作成する。

  1. プロジェクトエクスプローラで SpringMyApp→Javaリソース→src/main/java→jp.abcを右クリック
  2. [新規]-[クラス]を選択する
  3. クラス名を MyRadioController にして完了
  4. [ソース]-[getterおよびsetterの生成]でgetter/setterを生成
package jp.abc;

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

	@RequestMapping(value = "/radio", method = RequestMethod.GET)
	public String radio(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "Radiobuttonのサンプルです。");
		RadioFormModel fm = new RadioFormModel();
		fm.setRadio1("male");
		model.addAttribute("formModel", fm);
		return "radiosample";
	}

	@RequestMapping(value = "/radio", method = RequestMethod.POST)
	public String form(@ModelAttribute RadioFormModel fm, Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "selected: " + fm.getRadio1());
		model.addAttribute("formModel", fm);
		return "radiosample";

	}
}

ラジオボタンをまとめて作成する

radiosample.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<title>Welcome</title>
	</head>

<body>
	<h1>${title}</h1>
	<p>${message}</p>
	<table>
	<form:form modelAttribute="formModel">
		<tr><td>
		<form:radiobutton path="radio1" name="radio1"
			label="男性" value="male"/>
		<form:radiobutton path="radio1" name="radio1"
			label="女性" value="female"/>
		</td></tr>
		<tr><td><form:radiobuttons path="radio2" name="radio2"
			items="${radioList}" delimiter=" " /></td></tr>
		<tr><td><input type="submit" /></td></tr>
	</form:form>
	</table>
</body>

</html>

RadioFormModel.java に radio2 を追加する。

package jp.abc;

public class RadioFormModel {
	private String radio1;
	private String radio2;

	public String getRadio1() {
		return radio1;
	}

	public void setRadio1(String radio1) {
		this.radio1 = radio1;
	}

	public String getRadio2() {
		return radio2;
	}

	public void setRadio2(String radio2) {
		this.radio2 = radio2;
	}
}

MyRadioController.java

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

	private List<String> getList() {
		List<String> list = new ArrayList<String>();
		list.add("Mac OS X");
		list.add("Windows");
		list.add("Linux");
		return list;
	}

	@RequestMapping(value = "/radio", method = RequestMethod.GET)
	public String radio(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "Radiobuttonのサンプルです。");
		RadioFormModel fm = new RadioFormModel();
		fm.setRadio1("male");
		fm.setRadio2("Linux");
		model.addAttribute("formModel", fm);
		model.addAttribute("radioList", getList());
		return "radiosample";
	}

	@RequestMapping(value = "/radio", method = RequestMethod.POST)
	public String form(@ModelAttribute RadioFormModel fm, Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "selected: " + fm.getRadio1() + ", " + fm.getRadio2());
		model.addAttribute("formModel", fm);
		model.addAttribute("radioList", getList());
		return "radiosample";
	}
}

select による選択リストを使用する

ラジオボタンを参考にして、選択リストを実装する。
URL は、http://localhost:8080/SpringMyApp/select
・selectsample.jsp
・SelectFormModel.java
・MySelectController.java

selectsample.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<title>Welcome</title>
	</head>

<body>
	<h1>${title}</h1>
	<p>${message}</p>
	<table>
	<form:form modelAttribute="formModel">
		<tr><td>
		<tr><td><form:select path="select1" name="select1"
			items="${selectList}" delimiter=" " /></td></tr>
		<tr><td><input type="submit" /></td></tr>
	</form:form>
	</table>
</body>

</html>

SelectFormModel.java

package jp.abc;

public class SelectFormModel {
	private String select1;

	public String getSelect1() {
		return select1;
	}

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

MySelectController.java

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

	private List<String> getList() {
		List<String> list = new ArrayList<String>();
		list.add("Mac OS X");
		list.add("Windows");
		list.add("Linux");
		return list;
	}

	@RequestMapping(value = "/select", method = RequestMethod.GET)
	public String select(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "selectのサンプルです。");
		SelectFormModel fm = new SelectFormModel();
		fm.setSelect1("Linux");
		model.addAttribute("formModel", fm);
		model.addAttribute("selectList", getList());
		return "selectsample";
	}

	@RequestMapping(value = "/select", method = RequestMethod.POST)
	public String form(@ModelAttribute SelectFormModel fm, Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "selected: " + fm.getSelect1());
		model.addAttribute("formModel", fm);
		model.addAttribute("selectList", getList());
		return "selectsample";
	}

}