6月28日

HSQLDBの起動を簡単にする
デスクトップ上で右クリックして、[新規作成]-[テキストドキュメント]を選択する。
デスクトップ上に作成されたファイルの名前を「hsqldb.bat」に変更する。
hsqldb.bat を右クリックして[編集]を選択する。
メモ帳が開かれるので、HSQLDBを起動するために入力していたコマンドをそのまま入力する。

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

以後は、デスクトップ上の「hsqldb.bat」をダブルクリックするだけで起動できる。

CriteriaAPIによるクエリ
JPQLはSQLに似た文字列を使うため、文字列に間違いがあってもコンパイルできるので、実行時にやっとエラーを検出できる。

これに対して、CriteriaAPIは、クエリの条件をメソッドで指定するので、文字列の間違いはコンパイルエラーで検出できるし、コードを書くときに補完も利用できるので、間違いが起こりにくい。

CriteriaAPIによる実装
jp.abc パッケージに新規クラスを作成する。
インタフェースは MyDataDao を指定する。
クラス名は、CriteriaAPIでの実装であることがわかりやすいように、MyDataDaoCriteriaとする。
クラスを生成したら、インタフェースの総称型の部分を MyData に変更する。
次に、クラス名のところに表示されているコンパイルエラーにマウスカーソルを移動し、「実装されていないメソッドの追加」を選択する。

すべてのメソッドのテンプレートが生成されるので、getAll()メソッドだけ、テキストp.313のリスト6-11を記述する。

package jp.abc;

import java.util.List;

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

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> query = builder.createQuery(MyData.class);
		Root<MyData> root = query.from(MyData.class);
		query.select(root);
		list = manager.createQuery(query).getResultList();
		return list;
	}

	public MyData findById(long id) {
		// TODO 自動生成されたメソッド・スタブ
		return null;
	}

	public List<MyData> findByName(String name) {
		// TODO 自動生成されたメソッド・スタブ
		return null;
	}

	public List<MyData> find(String param) {
		// TODO 自動生成されたメソッド・スタブ
		return null;
	}

	public void add(MyData data) {
		// TODO 自動生成されたメソッド・スタブ

	}

	public void update(MyData data) {
		// TODO 自動生成されたメソッド・スタブ

	}

	public void delete(MyData data) {
		// TODO 自動生成されたメソッド・スタブ

	}

	public void delete(long id) {
		// TODO 自動生成されたメソッド・スタブ

	}

}

コントローラで新しく作成したCriteriaAPIを使ったクラスを使うように書き換える。

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String helo(Model model) {
		model.addAttribute("title", "Sample");
		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";
	}

add()メソッドは、クエリを使わないので、MyDataDaoImplと同じ実装にする。
update()/delete()も同様に、MyDataDaoImpleの実装をコピーする。

find() は、テキストp.314 のリスト6-12のコードを記述する。
内容は、getAll()とほとんど同じで、selectメソッドを呼び出す行だけが異なる。

	public List<MyData> find(String fstr) {
		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"), fstr));
		list = manager.createQuery(query).getResultList();
		return list;
	}

find()で実装したコードは、名前の一致で判定しているので、findByName()の仕様に合致する。
findByName()の実装も同じものにする。

findById()はnameをidに変更し、結果を単一のオブジェクトを返すようにすればよい。

	public MyData findById(long id) {
		EntityManager manager = factory.createEntityManager();
		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("id"), id));
		MyData mydata = manager.createQuery(query).getSingleResult();
		return mydata;
	}

	public List<MyData> findByName(String fstr) {
		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"), fstr));
		list = manager.createQuery(query).getResultList();
		return list;
	}

MyDataDaoCriteriaのコードは、現状で以下のとおり。
まだ、findでは、名前の完全一致しか検索できない。

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.Path;
import javax.persistence.criteria.Root;

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> query = builder.createQuery(MyData.class);
		Root<MyData> root = query.from(MyData.class);
		query.select(root);
		list = manager.createQuery(query).getResultList();
		return list;
	}

	public MyData findById(long id) {
		EntityManager manager = factory.createEntityManager();
		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("id"), id));
		MyData mydata = manager.createQuery(query).getSingleResult();
		return mydata;
	}

	public List<MyData> findByName(String fstr) {
		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"), fstr));
		list = manager.createQuery(query).getResultList();
		return list;
	}

	public List<MyData> find(String fstr) {
		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"), fstr));
		list = manager.createQuery(query).getResultList();
		return list;
	}

	public void add(MyData mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.persist(mydata);
		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.close();
	}

	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.close();
	}

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

}

名前の部分一致に対応するために、コードを一部修正する。

	public List<MyData> find(String fstr) {
		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.like((Path)root.get("name"), "%" + fstr + "%"));
		list = manager.createQuery(query).getResultList();
		return list;
	}

次に、IDの一致とメールアドレスの部分一致にも対応する。
or()メソッドを使用して、複数条件を記述する。

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

6月24日

コントローラの実装

前回、DAOとDAOの実装クラスにCRUDを追加したので、その機能を呼び出すためのURLを用意するために、コントローラを実装する。

更新用のURL update と、削除用のURL delete に対応するメソッドを追加する。

MyDataController.java

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

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

実装が終わったら、Tomcatサーバー、HSQLDBサーバーを起動して動作を確認する。

http://localhost:8080/SpringMyApp/update?id=1

など、IDを指定してアクセスすると、そのIDに対応するデータが表示される。
内容を更新して submit すると、新しいデータに更新される。

IDを指定して削除用のURLにアクセスすると、対応するIDがDBから削除される。
http://localhost:8080/SpringMyApp/delete?id=1

JPQLを活用する
検索画面に対応する find.jsp を追加する。

<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>${title}</title>
		<style type="text/css">
		h1 {
			font-size: 16pt;
			background-color: #ccccff;
			padding:3px;
		}
		p {
			color: #000066;
		}
		</style>
	</head>
<body>
	<h1>${title}</h1>
	<h2>${message}</h2>
	<table>
	<form action="/SpringMyApp/find" method="post">
		<tr>
			<td>FIND: </td>
			<td><input type="text" name="fstr" size="20" /></td>
		</tr>
		<tr>
			<td><input type="submit" /></td>
		</tr>
	</form>
	</table>
	<hr />
	<c:if test="${datalist != null}">
		<table border="1">
			<tr><th>ID</th><th>名前</th></tr>
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<tr>
					<td>${obj.id}</td>
					<td>${obj.name}</td>
				</tr>
			</c:forEach>
		</table>
	</c:if>
</body>
</html>

コントローラにURL /find に対応するメソッドを実装する。

	@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(HttpServletRequest request, Model model) {
		String param = request.getParameter("fstr");
		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";
	}

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

package jp.abc;

import java.util.List;

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

MyDataDaoImple.javaにfind()の実装を追加する。

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

テキストのMyDataDaoImplにはバグがあるのでエラーが発生する。
以下の部分を修正する。

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

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

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

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

複数のパラメータで検索する。
MyDataDaoImple の find メソッドを修正する。

	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) {}
		Query query = manager.createQuery(qstr)
				.setParameter("fid", fid)
				.setParameter("fname", "%" + fstr + "%")
				.setParameter("fmail", fstr + "@%");
		list = query.getResultList();
		manager.close();
		return list;
	}

6月21日

MyDataエンティティクラスを作成する。

MyData.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="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;
	}
}

DAOインタフェースの準備

MyDataをデータベースに格納・取り出すためのインタフェースを用意する。
最初は、全データの取り出しと、ひとつのデータの追加をできるように、メソッドを定義する。

MyDataDao.java

package jp.abc;

import java.util.List;

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

Daoの実装として、MyDataDaoImpl.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 void add(MyData mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.persist(mydata);
		tx.commit();
		manager.close();
	}

}
種別 テキスト 変更後
Entityクラス MyData MyData
JSP showMessage.jsp mydata.jsp
コントローラ MyAppController MyDataController
URL /helo /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;

@Controller
public class MyDataController {

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String helo(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";
	}

}

mydata.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>${title}</title>
		<style type="text/css">
		h1 {
			font-size: 16pt;
			background-color: #ccccff;
			padding:3px;
		}
		p {
			color: #000066;
		}
		</style>
	</head>
	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="myData">
			<form:errors path="*" element="div" />
			<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: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 border="1">
			<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>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

DAOにCRUDを追加する。

package jp.abc;

import java.util.List;

public interface MyDataDao<T> {
	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);
}

DAOを実装する。

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 mydata) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		manager.persist(mydata);
		tx.commit();
		manager.close();
	}

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

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

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

	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.close();
	}

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

}

6月17日

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

データベースはHSQLDBを使用する。
データベースを利用するためのライブラリを追加するため、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>

spring-aspects の箇所でエラーが出た場合は、${spring.version} を ${spring-framework.version} に変更する。それでエラーが消えればOK。

ファイルを保存したら、プロジェクトを右クリックし、[実行]-[Maven install]を実行する。
コンソールに「BUILD SUCCESS」と表示されればOK。

HSQLDBのプラグインがなぜかインストールできないので、HSQLDBをダウンロードして、C:\pleiades45 の下に展開する。

HSQLDBをここからダウンロード

コマンドプロンプトを開き、javaコマンドを実行する。
$ java

コマンドが見つからない場合は、環境変数を追加する。
スタートメニューでコンピュータを右クリックし、「プロパティ」を選択する。
「システム詳細設定」をクリック。
「環境変数」をクリックし、「新規」をクリックし、以下の内容を入力する。

変数名: PATH
変数値: C:\pleiades45\java\8\bin

コマンドプロンプトを再起動して、以下のコマンドを実行する。

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

これでHSQLDBサーバーが起動する。

もうひとつコマンドプロンプトを起動して、HSQLDBクライアントを起動する。

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

database.properties ファイルを作成する
src/main/resources/spring フォルダを右クリックし、「新規」を選択する。
[一般]-[ファイル]を選択し、ファイル名に「database.properties」と入力して完了する。
ファイル内には以下の内容を記述する。

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

persistence.xml を作成する
src/main/resources フォルダを右クリックし、「新規」を選択する。
[一般]-[フォルダ]を選択し、フォルダ名に「META-INF」と入力して完了する。

src/main/resources/META-INF フォルダを右クリックし、「新規」を選択する。
[XML]-[XMLファイル]を選択し、ファイル名に「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: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>

エンティティの作成
src/main/java の jp.abc パッケージにクラス「MyData」を新規作成する。

最初にクラス名の前に @Entity と @Table アノテーションを追加し、インスタンス変数を定義する。
インスタンス変数を定義したら、「getter および setter の生成」でgetter/setterを生成する。

MyData.java

package jp.abc;

import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name="mydata")
public class MyData {
	private long id;
	private String name;
	private String mail;
	private Integer age;
	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;
	}
}

pom.xml 全体

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.samples.service.service</groupId>
  <artifactId>SpringMyApp</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

    <properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Web -->
		<jsp.version>2.2</jsp.version>
		<jstl.version>1.2</jstl.version>
		<servlet.version>2.5</servlet.version>


		<!-- Spring -->
		<spring-framework.version>3.2.3.RELEASE</spring-framework.version>

		<!-- Hibernate / JPA -->
		<hibernate.version>4.2.1.Final</hibernate.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

		<!-- Test -->
		<junit.version>4.11</junit.version>

	</properties>

	<dependencies>

		<!-- Spring MVC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Other Web dependencies -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>${servlet.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>${jsp.version}</version>
			<scope>provided</scope>
		</dependency>

		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

		<!-- Hibernate -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>


		<!-- Test Artifacts -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring-framework.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
		<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>
		<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>

	</dependencies>
</project>

6月14日

バリデーションの利用

プロジェクト直下にある pom.xml を開き、最後の部分に以下のXML要素を追加する。

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
		<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>

	</dependencies>
</project>

保存すると、自動的にビルドが実行される。
ビルド完了後、プロジェクトの下の Javaリソース-ライブラリ-Maven依存関係 の下に、XML要素で追加した二つのライブラリが追加されているはず。

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

memo.jsp にエラー表示用のタグを追加する。

	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="memoModel">
			<tr>
				<td></td>
				<td><form:errors path="*" element="div" /></td>
			</tr>
			<tr>
				<td>
					<form:label path="item">商品名</form:label>
				</td>

MemoController.java を変更する。入力チェックは、POSTメソッド側のみ。

	@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 {
			mm.setBuydate(new Date());
			buylist.add(mm);
			String res = "<ol>";
			res += "<li>" + mm.getItem() + "</li>";
			res += "<li>" + mm.getPrice() + "</li>";
			res += "<li>" + mm.getMemo() + "</li>";
			res += "<li>" + mm.getBuydate() + "</li>";
			res += "</ol>";
			res += "<p>" + buylist.size() + "</p>";
			model.addAttribute("title", "Sample");
			model.addAttribute("message", res);
			model.addAttribute("memoModel", new MemoModel());
		}
		model.addAttribute("datalist", buylist);
		return "memo";
	}

国際化対応したメッセージの表示

アノテーションのmessage引数で指定すると、言語設定に関係なく固定のメッセージが表示される。
国際化対応する正式な方法では、各言語用にプロパティファイルを用意する。

src/main/resources フォルダを右クリックし、[新規]-[その他]を選択する。[一般]-[ファイル]を選択して「次へ」をクリック。
ファイル名に「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}

作成した「ValidatorMessag.properties」ファイルを右クリックして「コピー」を選択し、src/main/resources フォルダに貼り付ける。ファイル名を「ValidatorMessages_ja.properties」に変更する。

以下の内容を記述する。
入力した文字列は、自動的にUNICODEに変換されるので注意すること!

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

作成したプロパティファイルを読み込ませるために、mvc-config.xml を修正する。
bean のクラス名を入力するときは、Ctrl+SPACEで補完して候補から選択すること。手入力して間違うと動作しない。

    <mvc:annotation-driven />
	<mvc:resources mapping="/resources/**" location="/resources/" />

	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	        <!-- Example: a logical view name of 'showMessage' is mapped to '/WEB-INF/jsp/showMessage.jsp' -->
	        <property name="prefix" value="/WEB-INF/view/"/>
	        <property name="suffix" value=".jsp"/>
	</bean>
	<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<property name="basename" value="classpath:ValidatorMessages" />
	</bean>

</beans>

個別にメッセージを表示するには、memo.jsp の、form:errors タグを修正する。

		<form:form modelAttribute="memoModel">
			<tr>
				<td>
					<form:label path="item">商品名</form:label>
				</td>
				<td>
					<form:input path="item" size="20"/>
					<form:errors path="item" cssStyle="color:red" />
				</td>
			</tr>
			<tr>
				<td>
					<form:label path="price">金額</form:label>
				</td>
				<td>
					<form:input path="price" size="20" />
					<form:errors path="price" cssStyle="color:red" />
				</td>
			</tr>

6月10日

selectによる選択リストの作成

テキストp.223~226では、以下のファイルを新規作成して、新しいURLでアクセスできるようにする。

種別 テキスト 変更後
Modelクラス FormModel SelectModel
JSP showMessage.jsp select.jsp
コントローラ MyAppController SelectController
URL /helo /select

SelectModel.java

package jp.abc;

public class SelectModel {
	private String select1;

	public String getSelect1() {
		return select1;
	}

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

select.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>Welcome</title>
	</head>
	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="selectModel">
			<tr>
				<td>
					<form:select path="select1" name="select1"
						items="${optionlist}" itemLabel="label"
						itemValue="data" size="5"
						multiple="false" />
				</td>
			</tr>
			<tr><td><input type="submit"></td></tr>
		</form:form>
		</table>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

SelectController.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 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"));
		return list;
	}

	@RequestMapping(value = "/select", method = RequestMethod.GET)
	public String helo(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "Selectのサンプルです。");
		SelectModel sm = new SelectModel();
		sm.setSelect1("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) {
		String res = "selected: " + sm.getSelect1();
		model.addAttribute("title", "Sample");
		model.addAttribute("message", res);
		model.addAttribute("selectModel", sm);
		model.addAttribute("optionlist", getList());
		return "select";
	}

}

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

テキストp.226~228では、以下のファイルを新規作成して、新しいURLでアクセスできるようにする。

種別 テキスト 変更後
Modelクラス FormModel SelectsModel
JSP showMessage.jsp selects.jsp
コントローラ MyAppController SelectsController
URL /helo /selects

SelectsModel.java

package jp.abc;

public class SelectsModel {
	private String[] select1;

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

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

selectes.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>Welcome</title>
	</head>
	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="selectsModel">
			<tr>
				<td>
					<form:select path="select1" name="select1"
						items="${optionlist}" itemLabel="label"
						itemValue="data" size="5"
						multiple="true" />
				</td>
			</tr>
			<tr><td><input type="submit"></td></tr>
		</form:form>
		</table>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

SelectsController.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 SelectsController {
	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 = "/selects", method = RequestMethod.GET)
	public String helo(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "Selectのサンプルです。");
		SelectsModel sm = new SelectsModel();
		sm.setSelect1(new String[]{"Mac"});
		model.addAttribute("selectsModel", sm);
		model.addAttribute("optionlist", getList());
		return "selects";
	}

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

}

バリデーションの利用

テキストp.230~234では、以下のファイルを新規作成して、新しいURLでアクセスできるようにする。

種別 テキスト 変更後
Modelクラス FormModel MemoModel
JSP showMessage.jsp memo.jsp
コントローラ MyAppController MemoController
URL /helo /memo

まずはバリデーションなしで動作するアプリを作成する。
不正な入力でもそのまま受け付ける。

MemoModel.java

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

memo.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>${title}</title>
		<style type="text/css">
		h1 {
			font-size: 16pt;
			background-color: #ccccff;
			padding:3px;
		}
		p {
			color: #000066;
		}
		</style>
	</head>
	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<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>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

MemoController.java

package jp.abc;

import java.util.ArrayList;
import java.util.Date;
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 MemoController {
	private List<MemoModel> buylist = new ArrayList<MemoModel>();

	@RequestMapping(value = "/memo", method = RequestMethod.GET)
	public String helo(Model model) {
		model.addAttribute("title", "買い物メモ");
		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(@ModelAttribute MemoModel mm, Model model) {
		mm.setBuydate(new Date());
		buylist.add(mm);
		String res = "<ol>";
		res += "<li>" + mm.getItem() + "</li>";
		res += "<li>" + mm.getPrice() + "</li>";
		res += "<li>" + mm.getMemo() + "</li>";
		res += "<li>" + mm.getBuydate() + "</li>";
		res += "</ol>";
		res += "<p>" + buylist.size() + "</p>";
		model.addAttribute("title", "Sample");
		model.addAttribute("message", res);
		model.addAttribute("datalist", buylist);
		model.addAttribute("memoModel", new MemoModel());
		return "memo";
	}

}

6月7日

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

テキストp.209~212では、以下のファイルを新規作成して、新しいURLでアクセスできるようにする。

種別 テキスト 変更後
Modelクラス FormModel ChecksModel
JSP showMessage.jsp checks.jsp
コントローラ MyAppController ChecksController
URL /helo /checks

ChecksModel.java

package jp.abc;

public class ChecksModel {
	private String[] checks;

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

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

checks.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>Welcome</title>
	</head>
	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="checksModel">
			<tr>
				<td>
					<form:checkboxes path="checks"
						items="${checkItems}" delimiter=" "/>
				</td>
			</tr>
			<tr><td><input type="submit"></td></tr>
		</form:form>
		</table>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

ChecksController.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 ChecksController {
	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 = "/checks", method = RequestMethod.GET)
	public String helo(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "CheckBoxのサンプルです。");
		ChecksModel cm = new ChecksModel();
		cm.setChecks(new String[] {"Windows"});
		model.addAttribute("checksModel", cm);
		model.addAttribute("checkItems", getList());
		return "checks";
	}

	@RequestMapping(value = "/checks", method = RequestMethod.POST)
	public String form(@ModelAttribute ChecksModel cm, Model model) {
		String[] selected = cm.getChecks();
		String res = "<ol>";
		for (String s : selected) {
			res += "<li>" + s + "</li>";
		}
		res += "</ol>";
		model.addAttribute("title", "Sample");
		model.addAttribute("message", res);
		model.addAttribute("checksModel", cm);
		model.addAttribute("checkItems", getList());
		return "checks";
	}

}

ラジオボタンを作る

テキストp.217~220では、以下のファイルを新規作成して、新しいURLでアクセスできるようにする。

種別 テキスト 変更後
Modelクラス FormModel RadioModel
JSP showMessage.jsp radio.jsp
コントローラ MyAppController RadioController
URL /helo /radio

RadioModel.java

package jp.abc;

public class RadioModel {
	private String radio1;

	public String getRadio1() {
		return radio1;
	}

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

radio.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>Welcome</title>
	</head>
	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="radioModel">
			<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>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

RadioController.java

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

	@RequestMapping(value = "/radio", method = RequestMethod.GET)
	public String helo(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "RadioButtonのサンプルです。");
		RadioModel rm = new RadioModel();
		rm.setRadio1("male");
		model.addAttribute("radioModel", rm);
		return "radio";
	}

	@RequestMapping(value = "/radio", method = RequestMethod.POST)
	public String form(@ModelAttribute RadioModel rm, Model model) {
		String res = "selected: " + rm.getRadio1();
		model.addAttribute("title", "Sample");
		model.addAttribute("message", res);
		return "radio";
	}

}

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

テキストp.220~223では、以下のファイルを新規作成して、新しいURLでアクセスできるようにする。

種別 テキスト 変更後
Modelクラス FormModel RadioModel(再利用)
JSP showMessage.jsp radios.jsp
コントローラ MyAppController RadiosController
URL /helo /radios

p.214 にある ListDataModel.javaが必要なので作成する。
最初にlabelとdataのメンバー宣言を追加し、getter/setterは自動生成する。
その後、コンストラクタを追加すればOK。

package jp.abc;

public class ListDataModel {
	private String label;
	private String data;

	public String getLabel() {
		return label;
	}
	public void setLabel(String label) {
		this.label = label;
	}
	public String getData() {
		return data;
	}
	public void setData(String data) {
		this.data = data;
	}
	public ListDataModel(String label, String data) {
		this.label = label;
		this.data = data;
	}
}

RadioModel.java は再利用なので作成する必要なし。

radios.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>Welcome</title>
	</head>
	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="radioModel">
			<tr>
				<td>
					<form:radiobuttons path="radio1" name="radio1"
						items="${radiolist}" itemLabel="label" itemValue="data"
						delimiter=" " />
				</td>
			</tr>
			<tr><td><input type="submit"></td></tr>
		</form:form>
		</table>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

RadisoController.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 RadiosController {
	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"));
		return list;
	}

	@RequestMapping(value = "/radios", method = RequestMethod.GET)
	public String helo(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "RadioButtonsのサンプルです。");
		RadioModel rm = new RadioModel();
		rm.setRadio1("Mac");
		model.addAttribute("radioModel", rm);
		model.addAttribute("radiolist", getList());
		return "radios";
	}

	@RequestMapping(value = "/radios", method = RequestMethod.POST)
	public String form(@ModelAttribute RadioModel rm, Model model) {
		String res = "selected: " + rm.getRadio1();
		model.addAttribute("title", "Sample");
		model.addAttribute("message", res);
		model.addAttribute("radiolist", getList());
		return "radios";
	}

}

6月3日

4.1 フォームを使いこなす

さまざまなテキスト入力

テキストp.202からの内容に対応。
テキストでは、作成済みのソースコードを修正しているが、ここでは、練習のためにも新規で追加していく。

まず、入力を受け付けるための Model クラスを作成する。テキストでは FormModel を修正しているが、ここでは TextModel クラスを新規作成する。

package jp.abc;

public class TextModel {
	private String input1;
	private String pass1;
	private String area1;
	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;
	}
}

JSPも、テキストでは showMessage.jsp を修正しているが、新規に text.jsp を作成する。
src/main/webapp/WEB-INF/view/showMessage.jsp をコピーし、同じ view フォルダに貼り付ける。ファイル名を聞かれるので、text.jsp と入力してOKする。

コードをテキストのリスト4-2に合わせて修正する。

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

<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>Welcome</title>
	</head>
	<body>
		<h1>${title}</h1>
		<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"></form:textarea></td></tr>
			<tr><td><input type="submit"></td></tr>
		</form:form>
		</table>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

コントローラを追加する。
テキストでは MyAppController を修正しているが、ここでは新しくコントローラを作成する。
クラスの責務を考慮すれば、新しい URL に対するクラスを新規作成するほうが自然。

新しいクラスは、MyAppControllerをコピーして、同じ jp.abc パッケージに貼り付ける。
名前を聞かれるので、TextControler と入力してOKする。
コード内で以下の修正を行う。

@RequestMapping の value パラメータの値を /helo から /text に修正。
メソッド戻り値の “showMessage” を “text” に修正。
メソッドで使用しているクラスの型 FormModel を TextModel に修正。
それに伴って、変数名 fm を tm に修正。
変数名の修正は、メニューの[リファクタリング]-[名前変更]を使うと修正漏れが起きない。

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

	@RequestMapping(value = "/text", method = RequestMethod.GET)
	public String helo(Model model) {
		TextModel tm = new TextModel();
		tm.setInput1("ここに書く");
		model.addAttribute("formModel", tm);
		model.addAttribute("message", "何か書いてください。");
		return "text";
	}

	@RequestMapping(value = "/text", method = RequestMethod.POST)
	public String form(@ModelAttribute TextModel tm, Model model) {
		model.addAttribute("message", "you typed: " + tm.getInput1());
		return "text";
	}

}

サーバーを再起動し、コンソールに /text に対するマッピングが受け付けられることを確認する。
http://localhost:8080/SpringMyApp/text にアクセスし、動作することを確認する。

「送信」ボタンを押すとエラーになった。(修正漏れ)

test.jsp は以下の箇所を修正。

		<table>
		<form:form modelAttribute="textModel">
			<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"></form:textarea></td></tr>
			<tr><td><input type="submit"></td></tr>
		</form:form>
		</table>

TextControllerは、以下の箇所を修正。

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

	@RequestMapping(value = "/text", method = RequestMethod.GET)
	public String helo(Model model) {
		TextModel tm = new TextModel();
		tm.setInput1("ここに書く");
		model.addAttribute("formModel", tm);
		model.addAttribute("message", "何か書いてください。");
		return "text";
	}

	@RequestMapping(value = "/text", method = RequestMethod.POST)
	public String form(@ModelAttribute TextModel tm, Model model) {
		model.addAttribute("message", "you typed: " + tm.getInput1());
		return "text";
	}

}

入力した文字列を表示するように、コントローラを修正する。

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

	@RequestMapping(value = "/text", method = RequestMethod.GET)
	public String helo(Model model) {
		TextModel tm = new TextModel();
		tm.setInput1("ここに書く");
		model.addAttribute("textModel", tm);
		model.addAttribute("message", "何か書いてください。");
		return "text";
	}

	@RequestMapping(value = "/text", method = RequestMethod.POST)
	public String form(@ModelAttribute TextModel tm, Model model) {
		String res = "<ul><li>" + tm.getInput1()
				  + "</li><li>" + tm.getPass1()
				  + "</li><li>" + tm.getArea1()
				  + "</li></ul>";
		model.addAttribute("title", "Sample");
		model.addAttribute("message", res);
		return "text";
	}

}

チェックボックスの利用

テキストp.206~208の部分は、テキストと同様に新規作成する。

種別 テキスト 変更後
Modelクラス FormModel CheckModel
JSP showMessage.jsp check.jsp
コントローラ MyAppController CheckController
URL /helo /check

CheckModel.java

package jp.abc;

public class CheckModel {
	private boolean check1;

	public boolean isCheck1() {
		return check1;
	}

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

check.jsp

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

<html>
	<head>
		<meta charset="utf-8">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
		<script src="<c:url value="/resources/js/main.js" />"></script>
		<title>Welcome</title>
	</head>
	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="checkModel">
			<tr>
				<td>
					<form:checkbox path="check1" label="checkbox 1"/>
				</td>
			</tr>
			<tr><td><input type="submit"></td></tr>
		</form:form>
		</table>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

CheckController.java

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

	@RequestMapping(value = "/check", method = RequestMethod.GET)
	public String helo(Model model) {
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "CheckBoxのサンプルです。");
		CheckModel cm = new CheckModel();
		cm.setCheck1(true);
		model.addAttribute("checkModel", cm);
		return "check";
	}

	@RequestMapping(value = "/check", method = RequestMethod.POST)
	public String form(@ModelAttribute CheckModel cm, Model model) {
		String res = "checked: " + cm.isCheck1();
		model.addAttribute("title", "Sample");
		model.addAttribute("message", res);
		return "check";
	}

}