9月30日

課題提出方法

記名
プロジェクトの src/main/webapp にある index.jsp を開き、bodyタグのすぐ下に番号と名前を記入する。

<!DOCTYPE html>

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>

<html>
	<head>
		<meta charset="utf-8">
		<title>Welcome</title>
	</head>
	<body>
		<h1>00 氏名</h1>
		<c:url value="/showMessage.html" var="messageUrl" />
		<a href="${messageUrl}">Click to enter</a>
	</body>
</html>

WARファイルの設定
プロジェクトを右クリックし、[プロパティー]を選択。
左側で「Tomcat」を選択する。
「全般」タブで「Tomcatプロジェクト」をチェックする。
「コンテキスト名」を「00name」(自分の番号と名前)になっていることを確認(違っていれば修正)する。
「WARエクスポート設定」タブを選択する。
「エクスポートするWARファイル」で出力先を確認する。
(例: C:\pleiades45\workspace\00name\00name.war)
「.javaファイルをエクスポートする」のチェックが入っていることを確認する。
「OK」をクリックしてプロパティーのダイアログを閉じる。

WARファイルの生成
プロジェクトを右クリックし、[Tomcatプロジェクト]-[プロジェクト設定に従いWARファイルを作成]を選択する。
数秒で「操作が成功しました」と表示され、WARファイルが生成が完了。

Tomcat Manager の設定
C:\pleiades45\tomcat\8\conf\tomcat-users.xml を編集する。
最後の tomcat-users タグを閉じる直前に以下の2行を追加する。

<?xml version='1.0' encoding='utf-8'?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
<!--
  NOTE:  By default, no user is included in the "manager-gui" role required
  to operate the "/manager/html" web application.  If you wish to use this app,
  you must define such a user - the username and password are arbitrary.
-->
<!--
  NOTE:  The sample user and role entries below are wrapped in a comment
  and thus are ignored when reading this file. Do not forget to remove
  <!.. ..> that surrounds them.
-->
  <role rolename="manager-gui"/>
  <user username="admin" password="0000" roles="manager-gui"/>
<!--
  <role rolename="tomcat"/>
  <role rolename="role1"/>
  <user username="tomcat" password="tomcat" roles="tomcat"/>
  <user username="both" password="tomcat" roles="tomcat,role1"/>
  <user username="role1" password="tomcat" roles="role1"/>
-->
  <role rolename="manager-gui"/>
  <user username="admin" password="0000" roles="manager-gui"/>
</tomcat-users>

アプリケーションの配備
Eclipseの「サーバー」ビューで動作中のサーバーを停止する。
Eclipseのメニューバーで[ウィンドウ]-[設定]を選択する。
左側で「Tomcat」を展開し「JVM設定」を選択する。
「JRE」で「java8」を選択する。
「OK」して設定を反映する。
ツールバーからTomcatを起動する(猫のアイコン)。
http://localhost:8080/manager/ にアクセスする。
ユーザー名: admin
パスワード: 0000
を入力してログインする。
下のほうに「アップロードするWARファイルの選択」があるので「ファイルを選択」をクリックする。
生成したWARファイルを選択する。
「配備」をクリックする。
アプリケーションの一覧に「00name」が追加されたことを確認する。

動作確認
http://localhost:8080/00name/ にアクセスし、動作確認する。

動作しない場合は、以下の方法でWARファイルを作ってみる。
プロジェクトを右クリックし[エクスポート]-[WARファイル]を選択する。
「Webプロジェクト」に「00name」が指定されていることを確認。
「あて先」は「C:\pleiades45\workspace\00name\00name.war」を指定する。
「特定のサーバー・ランタイムに最適化」をチェックする。
その下で「Tomcat8(Java8)」を選択する。
「ソース・ファイルのエクスポート」をチェックする。
「既存ファイルを上書き」をチェックする。
「完了」をクリックするとWarファイルが生成される。
配備済みのアプリケーションを「配備解除」し、改て配備しなおす。

提出
生成したWARファイルを、以下のフォルダにコピーする。
\\kgakusei1\share\澤田\SE3Java2016

※提出期限は10月3日AM10:00

採点基準

得点 要件
10 提出したWARファイルが配備できる
10 /00name/ にアクセスすると番号と名前を表示する
10 /00name/home にアクセスすると入力フォームを表示する
10 メールアドレスとパスワードの入力チェックが動作する
10 正しく入力すれば登録を実行しDBに保存する
10 登録されたIDとメールアドレスのリストが表示する
10 /00name/timeline にアクセスすると入力フォームと送信済みツイート一覧を表示する
10 登録済みメールアドレスがリストで選択できツイートを送信するとDBに保存する
10 ツイートを編集できる
10 ツイートを削除できる

9月26日

ツイートをDBに保存する
ツイートをDBに保存し、保存したツイートを表示できるようにする。

TweetDao.java

package jp.abc;

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

public interface TweetDao<T> extends Serializable {
	public List<T> getAll();
	public void add(T t);
}

TweetDaoImpl.java

package jp.abc;

import java.util.List;

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

public class TweetDaoImpl implements TweetDao<Tweet> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

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

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

}

コントローラで URL:timeline でツイート一覧を表示するコードを実装する。
ユーザーからツイートを受信したら、POSTメソッドでツイートをDBに保存する。

HomeController.java

 
	@RequestMapping(value = "/timeline", method = RequestMethod.GET)
	public String timeline(Model model) {
		model.addAttribute("title", "タイムライン");
		model.addAttribute("message", "ツイート一覧");
		UserDao<User> dao = new UserDaoImpl();
		List<User> list = dao.getAll();
		model.addAttribute("list", list);
		model.addAttribute("tweetModel", new TweetModel());
		TweetDao<Tweet> tdao = new TweetDaoImpl();
		List<Tweet> tweets = tdao.getAll();
		model.addAttribute("tweets", tweets);
		return "timeline";
	}

	@RequestMapping(value = "/timeline", method = RequestMethod.POST)
	public String tweet(@Valid @ModelAttribute TweetModel tm, Errors result, Model model) {
		if (result.hasErrors()) {
			model.addAttribute("title", "Sample [ERROR]");
			model.addAttribute("message", "値を再チェックしてください");
			return "timeline";
		}
		model.addAttribute("title", "タイムライン");
		model.addAttribute("message", "ツイート一覧");
		UserDao<User> dao = new UserDaoImpl();
		User u = dao.findById(tm.getUserId());
		Tweet t = new Tweet();
		t.setUser(u);
		t.setDate(new Date());
		t.setContent(tm.getText());
		TweetDao<Tweet> tdao = new TweetDaoImpl();
		tdao.add(t);
		return "redirect:/timeline";
	}

JSPでツイートの一覧を表示する。
ツイートした人のメールアドレスと日時、ツイート内容を表示する。

		<hr />
		<h2>${message}</h2>
				<c:if test="${tweets != null}">
			<table>
				<tr><th>ユーザー</th><th>日時</th><th>ツイート</th></tr>
				<c:forEach var="t" items="${tweets}" varStatus="status">
					<tr><td>${t.user.mail}</td><td>${t.date}</td><td>${t.content}</td></tr>
				</c:forEach>
			</table>
		</c:if>
	</body>

9月23日

チーム開発で作るものを決める

  • 2ちゃんねる
  • Twitter
  • LINE
  • SNS
  • Wiki
  • EC(ネットショップ)

提出用課題の作成

前回はユーザー登録できるところまで作ったので、ユーザーを指定してツイートする機能を追加する。
ログインは設定が必要なので、ここではログインなしで画面上でユーザーを指定してツイートさせる。

ツイートを表示する画面を作成する
まだツイートに対応するクラスを作ってないので、ツイートするユーザーを選択できるUIを作成する。
UIは、ラジオボタンまたはリストを使い、ツイートする内容はテキストエリアを使う。

timeline.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>
		<title>${title}</title>
		<link rel="stylesheet" type="text/css" href="css/home.css">
	</head>
	<body>
		<h1>${title}</h1>
		<c:if test="${list != null}">
			<form:form modelAttribute="tweetModel">
			<table>
			<tr>
				<td>
				<form:select path="userId">
					<form:option value="-1" label="--- Select ---" />
					<form:options items="${list}" itemLabel="mail" itemValue="id"/>
				</form:select>
				</td>
			</tr>
			<tr>
				<td><form:textarea cols="40" rows="5" path="text"/></td>
			</tr>
			<tr>
				<td><input type="submit"></td>
			</tr>
			</table>
			</form:form>
		</c:if>
		<hr />
		<h2>${message}</h2>
	</body>
</html>

フォームモデルを作成する
ユーザーを指定してツイートするためにフォームモデルを追加する。

TweetModel.java

package jp.abc;

public class TweetModel {
	private long userId;
	private String text;
	public long getUserId() {
		return userId;
	}
	public void setUserId(long userId) {
		this.userId = userId;
	}
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
}

コントローラの変更
新しいURLとJSPに対応するためにコントローラを変更する。

	@RequestMapping(value = "/timeline", method = RequestMethod.GET)
	public String timeline(Model model) {
		model.addAttribute("title", "タイムライン");
		model.addAttribute("message", "ツイート一覧");
		UserDao<User> dao = new UserDaoImpl();
		List<User> list = dao.getAll();
		model.addAttribute("list", list);
		model.addAttribute("tweetModel", new TweetModel());
		return "timeline";
	}

以下のURLにアクセスすると、ユーザーを選択するリストと、ツイート内容を入力するテキストエリアが表示される。

http://localhost:8080/00name/timeline

Tweetクラスの作成
いつ、誰が、何をツイートしたかを保存すればよい。

Tweet.java

package jp.abc;

import java.util.Date;

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

import org.hibernate.validator.constraints.NotEmpty;

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

	@Column(nullable = false)
	private Date date;

	@Column(nullable = false)
	@NotEmpty
	private String content;

	@ManyToOne
	private User user;

	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
}

9月16日

「Backlog」を検索する

リーダーがプロジェクトを作成する

  1. リーダーがBacklogにユーザー登録する
  2. ユーザー登録したらプロジェクトを追加する
  3. 作成したプロジェクトに他のメンバーを招待する
  4. も招待する

メンバーは招待されたURLにログインする。
ログインしたら、個人設定でパスワードを変更し、メールの設定で「メールの受信」のチェックをはずして保存する。

・課題の追加

・課題の編集
課題を完了させるときは、必ず別の人に確認してもらい、確認者の名前をコメントに記載して完了にする。

・Wiki
各自の名前でWikiページを作成する。
ホームからそれぞれのWikiページへのリンクを作成する。

・ファイル
Backlogのファイルシステムに、ネットワークドライブでアクセスできる。

・Git
リーダーはGitリポジトリを作成する。

9月12日

成績判定用のWebアプリ作成

UserとTweetの2つのエンティティを持つアプリを作成する。

プロジェクト名: 00name
00 : 番号
name : 名前をアルファベットで

SpringMVCプロジェクトを作成する。

[maven]-[プロジェクトの更新] と [実行]-[maven install]を実行する。
Tomcatサーバーにプロジェクトを追加してサーバーを起動する。

http://localhost:8080/00name にアクセスして「click to enter」が表示されればOK。

mvc-config.xmlの修正
以下の1行を修正する。

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.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">

    <context:component-scan base-package="jp.abc"/>

    <mvc:annotation-driven />

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

</beans>

pom.xml にライブラリを追加する。(MyShopからコピー)

		<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.3.4</version>
		</dependency>
		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>3.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>3.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
				<exclusion>
					<groupId>xml-apis</groupId>
					<artifactId>xml-apis</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

	</dependencies>
</project>

pom.xml を修正したので、[maven]-[プロジェクトの更新] と [実行]-[maven install]を実行する。

ホーム画面を作成する。

<!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>
		<title>${title}</title>
		<link rel="stylesheet" type="text/css" href="css/home.css">
	</head>
	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table>
		<form:form modelAttribute="user">
			<form:errors path="*" element="div" />
			<tr>
				<td>
					<form:label path="mail">メール</form:label>
				</td>
				<td>
					<form:input path="mail" size="20" />
				</td>
			</tr>
			<tr>
				<td>
					<form:label path="password">パスワード</form:label>
				</td>
				<td>
					<form:password path="password" size="20" />
				</td>
			</tr>
			<tr><td><input type="submit"></td></tr>
		</form:form>
		</table>
		<hr />
		<c:if test="${list != null}">
			<table>
				<tr><th>ID</th><th>メール</th></tr>
				<c:forEach var="u" items="${list}" varStatus="status">
					<tr><td>${u.id}</td><td>${u.mail}</td></tr>
				</c:forEach>
			</table>
		</c:if>
	</body>
</html>

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

package jp.abc;

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

import org.hibernate.validator.constraints.NotEmpty;

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

	@Column(nullable = false)
	@NotEmpty
	@Email
	private String mail;

	@Column(nullable = false)
	@NotEmpty
	@Size(min = 8, max = 64)
	private String password;

	@Column(nullable = false)
	private String role;

	public long getId() {
		return id;
	}

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

	public String getMail() {
		return mail;
	}

	public void setMail(String mail) {
		this.mail = mail;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getRole() {
		return role;
	}

	public void setRole(String role) {
		this.role = role;
	}
}

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", "ホーム");
		model.addAttribute("message", "ユーザー");
		model.addAttribute("list", null);
		model.addAttribute("user", new User());
		return "home";
	}

}

http://localhost:8080/00name/home にアクセスして入力フォームが表示されればOK。

データベースの設定
ユーザーをデータベースに格納できるようにする。

HSQLDB のデータベースインスタンスを追加する。

C:\pleiades45\hsqldb-2.3.4\hsqldb\lib\server.properties を編集する。
新しいデータベース名を twi にする。

server.database.0=file:db/mydatabase
server.dbname.0=mydatabase
server.database.1=file:db/myshop
server.dbname.1=myshop
server.database.2=file:db/twi
server.dbname.2=twi

HSQLDBを再起動し、コマンドプロンプトに以下の1行が表示されていればOK。

Database [index=0, id=0, db=file:db/twi, alias=twi] opened successfully in xxx ms.

Webアプリからデータベースにアクセスする設定を追加する

Javaリソースの src/main/resources の下の spring フォルダに、database.properties ファイルを作成する。
以下の内容を記述する。

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

Javaリソースの 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="update" />
      <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbc.JDBCDriver" />
      <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:hsql://localhost/twi" />
    </properties>
  </persistence-unit>
</persistence>

DAOを作成する

UserDao.java

package jp.abc;

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

public interface UserDao <T> extends Serializable {
	public List<T> getAll();
	public void add(T o);
}

UserDaoImpl.java

package jp.abc;

import java.util.List;

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

public class UserDaoImpl implements UserDao<User> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

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

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

}

HomeControllerを変更する。

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

	@RequestMapping(value = "/home", method = RequestMethod.GET)
	public String home(Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "ユーザー");
		model.addAttribute("list", null);
		model.addAttribute("user", new User());
		UserDao<User> dao = new UserDaoImpl();
		List<User> list = dao.getAll();
		model.addAttribute("list", list);
		return "home";
	}

	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String form(@Valid @ModelAttribute User user, Errors result, Model model) {
		if (result.hasErrors()) {
			model.addAttribute("title", "Sample [ERROR]");
			model.addAttribute("message", "値を再チェックしてください");
			return "/home";
		}
		user.setRole("user");
		UserDao<User> dao = new UserDaoImpl();
		dao.add(user);
		List<User> list = dao.getAll();
		model.addAttribute("list", list);
		return "redirect:/home";
	}
}

9月9日

ItemとPurchaseを関連付ける

Item.java

package jp.abc;

import java.util.List;

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

import org.hibernate.validator.constraints.NotEmpty;

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

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

	@Column
	@Min(0)
	private int price;

	@Column(nullable = true)
	private String desc;

	@OneToMany(cascade = CascadeType.MERGE)
	private List<Purchase> purchases;

	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 int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public String getDesc() {
		return desc;
	}
	public void setDesc(String desc) {
		this.desc = desc;
	}
	public List<Purchase> getPurchases() {
		return purchases;
	}
	public void setPurchases(List<Purchase> purchases) {
		this.purchases = purchases;
	}
}

Purchase.java

package jp.abc;

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

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

	@ManyToOne
	private Item item;

	public long getId() {
		return id;
	}

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

	public Item getItem() {
		return item;
	}

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

KartDaoImpl.java

package jp.abc;

import java.util.List;

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

public class KartDaoImpl implements KartDao<Kart> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

	public List<Kart> getAll() {
		return null;
	}

	public Kart findById(long id) {
		EntityManager manager = factory.createEntityManager();
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<Kart> query = builder.createQuery(Kart.class);
		Root<Kart> root = query.from(Kart.class);
		query.select(root).where(builder.equal(root.get("id"), id));
		Kart kart = manager.createQuery(query).getSingleResult();
		manager.close();
		return kart;
	}

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

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

Purchase を DB に保存するために、DAO を作成する。

PurchaseDao.java

package jp.abc;

import java.io.Serializable;

public interface PurchaseDao <T> extends Serializable {
	public void add(T o);
}

DAO の実装を作成する。

PurchaseDaoImpl.java

package jp.abc;

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

public class PurchaseDaoImpl implements PurchaseDao<Purchase> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

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

}

ItemContoller.java

package jp.abc;

import java.util.ArrayList;
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 ItemController {

	@RequestMapping(value = "/items", method = RequestMethod.GET)
	public String items(Model model) {
		Item item = new Item();
		model.addAttribute("title", "Sample");
		model.addAttribute("message", "MyShopのサンプル");
		ItemDao<Item> dao = new ItemDaoImpl();
		List<Item> list = dao.getAll();
		model.addAttribute("item", item);
		model.addAttribute("datalist", list);
		return "items";
	}

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

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

	@RequestMapping(value = "/update", method = RequestMethod.POST)
	public String update(@RequestParam(value = "id")int id,
			@Valid @ModelAttribute Item item,
			Errors result, Model model) {
		ItemDao<Item> dao = new ItemDaoImpl();
		dao.update(item);
		return "redirect:/items";
	}

	@RequestMapping(value = "/delete", method = RequestMethod.GET)
	public String delete(@RequestParam(value = "id")int id, Model model) {
		ItemDao<Item> dao = new ItemDaoImpl();
		dao.delete(id);
		return "redirect:/items";
	}

	@RequestMapping(value = "/home", method = RequestMethod.GET)
	public String home(Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "商品");
		ItemDao<Item> dao = new ItemDaoImpl();
		List<Item> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "home";
	}

	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String kart(@RequestParam(value = "id")int id, Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "商品");
		ItemDao<Item> dao = new ItemDaoImpl();
		KartDao<Kart> kdao = new KartDaoImpl();
		List<Item> list = dao.getAll();
		Item item = dao.findById(id);
		model.addAttribute("item", item);
		model.addAttribute("datalist", list);
		Kart kart = new Kart();
		List<Purchase> plist = kart.getPurchases();
		if (plist == null) plist = new ArrayList<Purchase>();
		Purchase p = new Purchase();
		p.setItem(item);
		plist.add(p);
		kart.setPurchases(plist);
		kdao.add(kart);
		model.addAttribute("kart", kart);
		return "/home";
	}
}

ItemControllerでPurchaseをDBに格納する処理を追加する。

	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String kart(@RequestParam(value = "id")int id, Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "商品");
		ItemDao<Item> dao = new ItemDaoImpl();
		KartDao<Kart> kdao = new KartDaoImpl();
		PurchaseDao<Purchase> pdao = new PurchaseDaoImpl();
		List<Item> list = dao.getAll();
		Item item = dao.findById(id);
		model.addAttribute("item", item);
		model.addAttribute("datalist", list);
		Kart kart = new Kart();
		List<Purchase> plist = kart.getPurchases();
		if (plist == null) plist = new ArrayList<Purchase>();
		Purchase p = new Purchase();
		p.setItem(item);
		pdao.add(p);
		plist.add(p);
		kart.setPurchases(plist);
		kdao.add(kart);
		model.addAttribute("kart", kart);
		return "/home";
	}

Purchaseを格納する処理を追加して実行すると、JSPのエラーが発生する。
${kart.items} でエラーとなっているので、Kart – Purchase – Item の関連に書き換える。

		<c:if test="${kart != null}">
			カートID: ${kart.id}
			<table>
				<tr><th>商品名</th><th>価格</th></tr>
				<c:forEach var="obj" items="${kart.purchases}" varStatus="status">
					<tr><td>${obj.item.name}</td><td>${obj.item.price}</td></tr>
				</c:forEach>
			</table>
		</c:if>
	</body>

「org.hibernate.LazyInitializationException: could not initialize proxy – no Session」が発生する。
Kartを取得したときに、同時にKartのPurchaseのリストも取得するように@OneToManyアノテーションにfetch引数を追加する。

Kart.java

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

	@OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
	@Column(nullable = true)
	private List<Purchase> purchases;

サーバー側でカートを取得できるように、カートのIDをhidden属性でフォームに追加する。

		<table border="1">
		<tr>
			<th class="id">ID</th>
			<th class="name">商品名</th>
			<th class="price">価格</th>
			<th class="desc">説明</th>
			<th >&nbsp;</th>
		</tr>
		<c:if test="${datalist != null}">
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<form:form modelAttribute="item">
					<input type="hidden" name="id" value="${obj.id}" />
					<c:if test="${kart != null}">
						<input type="hidden" name="kid" value="${kart.id}" />
					</c:if>
					<form:errors path="*" element="div" />
					<tr>
						<td><c:out value="${obj.id}" /></td>
						<td><c:out value="${obj.name}" /></td>
						<td class="price"><c:out value="${obj.price}" /></td>
						<td><c:out value="${obj.desc}" /></td>
						<td><input type="submit" value="カートに入れる" /></td>
					</tr>
				</form:form>
			</c:forEach>
		</c:if>
		</table>

サーバー側でカートのIDをリクエストパラメータの引数で取得する。
カートIDは存在しない場合もあるので、required = false にする。
その場合は、プリミティブ型ではなく、Long型のオブジェクトで受け取る。(存在しない場合はnull)
カートIDがある場合は KartDao でクエリを実行して取得する。

	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String kart(@RequestParam(value = "id")int id,
					   @RequestParam(value = "kid", required = false)Long kid, Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "商品");
		ItemDao<Item> dao = new ItemDaoImpl();
		KartDao<Kart> kdao = new KartDaoImpl();
		PurchaseDao<Purchase> pdao = new PurchaseDaoImpl();
		List<Item> list = dao.getAll();
		Item item = dao.findById(id);
		model.addAttribute("item", item);
		model.addAttribute("datalist", list);
		Kart kart;
		if (kid == null) {
			kart = new Kart();
		} else {
			kart = kdao.findById(kid);
		}
		List<Purchase> plist = kart.getPurchases();
		if (plist == null) plist = new ArrayList<Purchase>();
		Purchase p = new Purchase();
		p.setItem(item);
		pdao.add(p);
		plist.add(p);
		kart.setPurchases(plist);
		kdao.add(kart);
		model.addAttribute("kart", kart);
		return "/home";
	}

この状態で実行すると、2個目の商品を追加したときに「javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist」が発生する。

2回目はカートが存在しているので、add() ではなく update() する。

	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String kart(@RequestParam(value = "id")int id,
					   @RequestParam(value = "kid", required = false)Long kid, Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "商品");
		ItemDao<Item> dao = new ItemDaoImpl();
		KartDao<Kart> kdao = new KartDaoImpl();
		PurchaseDao<Purchase> pdao = new PurchaseDaoImpl();
		List<Item> list = dao.getAll();
		Item item = dao.findById(id);
		model.addAttribute("item", item);
		model.addAttribute("datalist", list);
		Kart kart;
		if (kid == null) {
			kart = new Kart();
		} else {
			kart = kdao.findById(kid);
		}
		List<Purchase> plist = kart.getPurchases();
		if (plist == null) plist = new ArrayList<Purchase>();
		Purchase p = new Purchase();
		p.setItem(item);
		pdao.add(p);
		plist.add(p);
		kart.setPurchases(plist);
		if (kid == null) {
			kdao.add(kart);
		} else {
			kdao.update(kart);
		}
		model.addAttribute("kart", kart);
		return "/home";
	}

9月5日

カートに商品を保存する

Kart – Item の関連は間違い。

購入する商品に対応するクラスとして、新しく Purchase エンティティを用意する。

package jp.abc;

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

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

	@Column(nullable = false)
	private Item item;

	public long getId() {
		return id;
	}

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

	public Item getItem() {
		return item;
	}

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

Kartに入れるのは購入する商品にする。

package jp.abc;

import java.util.List;

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

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

	@OneToMany(cascade = CascadeType.MERGE)
	@Column(nullable = true)
	private List<Purchase> purchases;

	public long getId() {
		return id;
	}

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

	public List<Purchase> getPurchases() {
		return purchases;
	}

	public void setPurchases(List<Purchase> purchases) {
		this.purchases = purchases;
	}
}

ItemからKartを削除する。

package jp.abc;

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

import org.hibernate.validator.constraints.NotEmpty;

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

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

	@Column
	@Min(0)
	private int price;

	@Column(nullable = true)
	private String desc;

	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 int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public String getDesc() {
		return desc;
	}
	public void setDesc(String desc) {
		this.desc = desc;
	}
}

コントローラの修正。
KartにはPurchaseを追加するようにして、PurchaseにはItemを設定する。

	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String kart(@RequestParam(value = "id")int id, Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "商品");
		ItemDao<Item> dao = new ItemDaoImpl();
		KartDao<Kart> kdao = new KartDaoImpl();
		List<Item> list = dao.getAll();
		Item item = dao.findById(id);
		model.addAttribute("item", item);
		model.addAttribute("datalist", list);
		Kart kart = new Kart();
		List<Purchase> plist = kart.getPurchases();
		if (plist == null) plist = new ArrayList<Purchase>();
		Purchase p = new Purchase();
		p.setItem(item);
		plist.add(p);
		kart.setPurchases(plist);
		kdao.add(kart);
		model.addAttribute("kart", kart);
		return "/home";
	}

9月2日

MyShop の 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>MyShop</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.3.4</version>
		</dependency>
		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>3.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>3.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
				<exclusion>
					<groupId>xml-apis</groupId>
					<artifactId>xml-apis</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

	</dependencies>
</project>

商品をカートに入れる処理を実装する

現状では、「カートに入れる」ボタンを押すとエラーになる。
これは、POSTメソッドに対応するマッピングが用意されていないから。
なので、POSTメソッドに対応するマッピングをコントローラに追加する。

ItemController.java

	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String kart(Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "商品");
		ItemDao<Item> dao = new ItemDaoImpl();
		List<Item> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "/home";
	}

JSP側はひとつのformに複数のsubmitがあるので、複数のformに分割する。

home.jsp

	<body>
		<h1>${title}</h1>
		<h2>${message}</h2>
		<table border="1">
		<tr>
			<th class="name">商品名</th>
			<th class="price">価格</th>
			<th class="desc">説明</th>
			<th >&nbsp;</th>
		</tr>
		<c:if test="${datalist != null}">
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<form:form modelAttribute="item">
				<form:errors path="*" element="div" />
					<tr>
						<td><c:out value="${obj.name}" /></td>
						<td class="price"><c:out value="${obj.price}" /></td>
						<td><c:out value="${obj.desc}" /></td>
						<td><input type="submit" value="カートに入れる" /></td>
					</tr>
				</form:form>
			</c:forEach>
		</c:if>
		</table>
		<hr />
	</body>

submitでidを受け取れるようにする
hidden属性のinput要素をform内に追加して、idをパラメータで渡せるようにする。
ボタンを押された商品名を、商品一覧の下に表示する。

		<tr>
			<th class="id">ID</th>
			<th class="name">商品名</th>
			<th class="price">価格</th>
			<th class="desc">説明</th>
			<th >&nbsp;</th>
		</tr>
		<c:if test="${datalist != null}">
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<form:form modelAttribute="item">
					<input type="hidden" name="id" value="${obj.id}" />
				<form:errors path="*" element="div" />
					<tr>
						<td><c:out value="${obj.id}" /></td>
						<td><c:out value="${obj.name}" /></td>
						<td class="price"><c:out value="${obj.price}" /></td>
						<td><c:out value="${obj.desc}" /></td>
						<td><input type="submit" value="カートに入れる" /></td>
					</tr>
				</form:form>
			</c:forEach>
		</c:if>
		</table>
		<hr />
		<c:if test="${item != null}">
			${item.name} がカートに追加されました。
		</c:if>

コントローラは、パラメータでIDを受け取る。
受け取ったIDでItemを検索して、JSPに渡す。

	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String kart(@RequestParam(value = "id")int id, Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "商品");
		ItemDao<Item> dao = new ItemDaoImpl();
		List<Item> list = dao.getAll();
		Item item = dao.findById(id);
		model.addAttribute("item", item);
		model.addAttribute("datalist", list);
		return "/home";
	}

Kartエンティティを用意する。

Kart.java

package jp.abc;

import java.util.List;

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

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

	@OneToMany(cascade = CascadeType.ALL)
	@Column(nullable = true)
	private List<Item> items;

	public long getId() {
		return id;
	}

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

	public List<Item> getItems() {
		return items;
	}

	public void setItems(List<Item> items) {
		this.items = items;
	}
}

DAOとDAOの実装も用意する。

KartDao.java

package jp.abc;

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

public interface KartDao<T> extends Serializable {
	public List<T> getAll();
	public T findById(long id);
	public void add(T o);
}

KartDaoImpl.java

package jp.abc;

import java.util.List;

public class KartDaoImpl implements KartDao<Kart> {
	public List<Kart> getAll() {
		return null;
	}

	public Kart findById(long id) {
		return null;
	}

	public void add(Kart o) {
	}

}

コントローラで、カートに入れられた商品をKartに追加して、そのKartをJSPに渡すようにする。

	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String kart(@RequestParam(value = "id")int id, Model model) {
		model.addAttribute("title", "ホーム");
		model.addAttribute("message", "商品");
		ItemDao<Item> dao = new ItemDaoImpl();
		List<Item> list = dao.getAll();
		Item item = dao.findById(id);
		model.addAttribute("item", item);
		model.addAttribute("datalist", list);
		Kart kart = new Kart();
		list = kart.getItems();
		if (list == null) list = new ArrayList<Item>();
		list.add(item);
		kart.setItems(list);
		model.addAttribute("kart", kart);
		return "/home";
	}

JSP側でカートの中身を表示してみる。

		<c:if test="${item != null}">
			${item.name} がカートに追加されました。
		</c:if>
		<c:if test="${kart != null}">
			<table>
				<tr><th>商品名</th><th>価格</th></tr>
				<c:forEach var="obj" items="${kart.items}" varStatus="status">
					<tr><td>${obj.name}</td><td>${obj.price}</td></tr>
				</c:forEach>
			</table>
		</c:if>

カートをDBに保存するため、KartDaoImpleの実装を追加する。

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

detached entity passed to persist というメッセージで例外が発生したので、Kartのコードを一部修正する。

	@OneToMany(cascade = CascadeType.MERGE)
	@Column(nullable = true)
	private List<Item> items;

カートがDBに保存されるとIDが割り振られるので、画面上に表示してIDを確認する。

		<c:if test="${kart != null}">
			カートID: ${kart.id}
			<table>
				<tr><th>商品名</th><th>価格</th></tr>
				<c:forEach var="obj" items="${kart.items}" varStatus="status">
					<tr><td>${obj.name}</td><td>${obj.price}</td></tr>
				</c:forEach>
			</table>
		</c:if>