8月29日

MyShopの実装続き

ItemDaoImple.java は、MyDataDaoCriteria.java を参考に実装する。
MyData を Item に置換すれば動作する。

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 ItemDaoImpl implements ItemDao<Item> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

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

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

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

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

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

	public void delete(Item o) {
		EntityManager manager = factory.createEntityManager();
		EntityTransaction tx = manager.getTransaction();
		tx.begin();
		Item entity = manager.merge(o);
		manager.remove(entity);
		tx.commit();
		manager.close();
	}

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

}

コントローラでは、update と delete に対応するメソッドを用意する。

ItemController.java

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

JSPには、更新と削除が簡単にできるように、アンカーを追加する。
各アンカーのURLで、idに対応するリクエストパラメータを含めておけば、アンカーをクリックするだけで更新と削除が可能になる。

		<c:if test="${datalist != null}">
		<table border="1">
			<tr>
				<th>ID</th>
				<th>商品名<a href="?s=d">↓</a>
				<a href="?s=a">↑</a></th>
			</tr>
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<tr>
					<td><c:out value="${obj.id}" /></td>
					<td><c:out value="${obj.name}" /></td>
					<td><a href="update?id=<c:out value="${obj.id}" />">更新</a></td>
					<td><a href="delete?id=<c:out value="${obj.id}" />">削除</a></td>
				</tr>
			</c:forEach>

商品のリストが表示されない場合は、以下の箇所を確認する。

<hr /> タグが水平線で、その下に商品のリストが表示されるが、水平線以下に商品のリストが表示されない場合、datalist が渡されていない可能性がある。

以下の c:if タグで datalist が null でない場合だけ商品のリストを表示している。

		<c:if test="${datalist != null}">

ItemController に、model.addAttribute(“datalist”, list) のコードがあるかどうかを確認すること。

削除前に確認のダイアログを表示するには
head 要素の中に、JavaScript で function を定義する。

		<script type="text/javascript"><!--
		function deleteconfirm(id) {
			if(window.confirm("削除してもいいですか?")) {
				location.href = "delete?id=" + id;
			}
		}
		--></script>

削除のアンカー部分を以下のように修正する。

	<a href="javascript:void(0)" onclick="deleteconfirm(${obj.id})">削除</a>

ユーザー向けフロントページの作成

サイトにアクセスしたユーザーが商品の一覧を参照できるページを作成する。
URLは、 /MyShop/home とする。

商品名 価格 説明  
プレミアムモルツ 220 超クリーミー カートに入れる
エビス 210 おすすめ! カートに入れる
一番搾り 200 さらにおいしくなりました。 カートに入れる

CSSファイルを作成する
src/main/webapp フォルダに css フォルダを新規作成する。
作成した css フォルダ内に home.css を作成する。

CSSファイルを読み込めるようにする
mvc-config.xml ファイルに、CSSフォルダを参照できる設定を追加する。

<?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 />
	<mvc:resources mapping="/css/**" location="/css/" />

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

8月26日

HSQLDBを動かす

HSQLDBの設定に、MyShop用データベースインスタンスを追加する。

C:\pleiades45\hsqldb-2.3.4\hsqldb\lib\server.properties を編集する。

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

デスクトップに hsqldb.bat を作成する。

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

hsqldb.bat をダブルクリックして、HSQLDBを起動する。

Tomcat8サーバーも再起動すると、データベース接続エラーが出なくなる。

ItemDaoImple.java の実装を行う。

SpringMyApp の、MyDataDaoCriteria.java の内容をコピーして MyData を Item に修正する。

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 ItemDaoImpl implements ItemDao<Item> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

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

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

}

CRUDを実装する

現状では、全Itemの取得と追加しかできてない。
更新や削除、クエリなどを実装しCRUDを充実させる。

まずは ItemDao.java にメソッドを追加で定義する。

package jp.abc;

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

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

ItemDao.java にメソッドを追加して保存すると、ItemDaoImple.java がコンパイルエラーになる。
ItemDaoImpl.java のクラス宣言にマウスカーソルを移動させ、「実装されていないメソッドの追加」を選択する。

各メソッドの内容は、MyDataDaoCriteria.java を参考に実装する。

コントローラも、MyDataController.java を参考に、/update と /delete のURLに対応するメソッドを追加する。

items.jsp には、更新と削除が簡単にできるように、テーブルにリンクを追加する。

8月22日

復習のために新しいWebアプリを作成する

新しく「MyShop」プロジェクトを作成する。(テキストp.39)

作成したプロジェクトを右クリックし、[Maven]-[プロジェクトの更新]を実行する。
完了したら、プロジェクトを右クリックし、[実行]-[maven install]を実行する。

Tomcat8サーバーに MyShop プロジェクトを追加して Tomcat8 サーバーを起動する。

ブラウザから http://localhost:8080/MyShop/ にアクセスする。

「Click to enter」と表示されればOK。(テキストp.49)

showMessage.jsp を表示するための Controller を追加する

MyShop
 +Javaリソース
  + src/main/java を右クリックし、[新規]-[クラス]を選択する。

パッケージ名: jp.abc
クラス名: MsgController

以下のコードを記述する。

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

	@RequestMapping(value = "/msg", method = RequestMethod.GET)
	public String msg(Model model) {
		model.addAttribute("message", "this is sample. ok?");
		return "showMessage";
	}
}

mvc-config.xml の変更

作成するクラスをSpringMVCに読み込んでもらうための設定をする。

src
 + main
  + webapp
   + WEB-INF
    + mvc-config.xml ←このファイルを開く。

9行目の部分がコメントアウトされているので、コメントタグを削除する。
base-package 属性の値を jp.abc に設定する。

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

設定ファイルを変更したので、Tomcat8サーバーを再起動する。
http://localhost:8080/MyShop/msg/ にアクセスする。

MsgControllerで指定したメッセージが表示されればOK。

次の目標は商品を登録できるようにすること

目標となるのは、テキストp.290の MyData のサンプル。
MyData の代わりに、Item を登録できるようにする。

pom.xml に必要な内容を追加するのは大変!
なので、ほぼ同じことをやろうとしているSpringMyAppのpom.xmlをまるごとコピーする。
pom.xmlを変更したら、Tomcat8サーバーを停止し、
[Maven]-[プロジェクトの更新]
[実行]-[maven install]
を実行する。

以下のファイルも、SpringMyAppからコピーする。あとで必要な箇所があれば修正する。

  • database.properties
  • persistence.xml
  • application-config.xml

とりあえず、データベースインスタンスだけ変更する。
database.properties

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

persistence.xml

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

文字化け対策

テキストp.187に書かれているweb.xmlファイルの設定を行う。
SpringMyApp の web.xml から、最後の filter要素と filter-mapping要素をコピーする。

	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

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

商品に対応する Item クラスを作成する。
src/main/java にある jp.abc パッケージを右クリックして[新規]-[クラス]を選択する。
クラス名に Item を入力しOKする。

@Entityアノテーションを追加し、4つのフィールドを追加する。

package jp.abc;

import javax.persistence.Entity;

@Entity
public class Item {
	private long id;
	private String name;
	private int price;
	private String desc;
}

[ソース]-[getterおよびsetterの生成]で、getter と setter を生成する。

id・name・price・descの各フィールドに必要なアノテーションを追加する。

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

	@Column(nullable = false)
	private String name;

	@Column
	@Min(0)
	private int price;

	@Column(nullable = true)
	private String desc;

DAOとDAOの実装クラスを作成する

src/main/java にある jp.abc パッケージを右クリックして[新規]-[インターフェース]を選択する。
クラス名に ItemDao を入力しOKする。(参考はテキストp.281)

package jp.abc;

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

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

src/main/java にある jp.abc パッケージを右クリックして[新規]-[クラス]を選択する。
クラス名に ItemDaoImpl を入力しOKする。(参考はテキストp.283)
実装は後で行うことにする。

package jp.abc;

import java.util.List;

public class ItemDaoImpl implements ItemDao<Item> {

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

	public void add(Item item) {

	}

}

コントローラの作成

テキストp.287を参考に、コントローラを作成する。

src/main/java にある jp.abc パッケージを右クリックして[新規]-[クラス]を選択する。
クラス名に ItemController を入力しOKする。

package jp.abc;

public class ItemController {

}

コントローラに最小限のコードを記述する。

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

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

src/main/webapp/WEB-INF/viewを右クリックして[新規]-[JSPファイル]を選択する。
ファイル名に items.jsp を入力しOKする。
items.jsp の内容は、SpringMyApp の mydata.jsp の内容をまるごとコピーする。

http://localhost:8080/MyShop/items/ にアクセスすると「HTTPステータス 500 – An exception occurred processing JSP page …」エラーになることを確認する。

JSPをItemにあわせる。

<!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="item">
			<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="price">価格</form:label>
				</td>
				<td>
					<form:input path="price" size="20" />
				</td>
			</tr>
			<tr>
				<td>
					<form:label path="desc">説明</form:label>
				</td>
				<td>
					<form:textarea path="desc" 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>商品名<a href="?s=d">↓</a>
				<a href="?s=a">↑</a></th>
			</tr>
			<c:forEach var="obj" items="${datalist}" varStatus="status">
				<tr>
					<td><c:out value="${obj.id}" /></td>
					<td><c:out value="${obj.name}" /></td>
				</tr>
			</c:forEach>
		</table>
		</c:if>
		<div id="footer"></div>
		<input type="button" value="テスト" onclick="testClicked()">
	</body>
</html>

コントローラの修正

動作するように、コントローラを修正する。

@Controller
public class ItemController {

	@RequestMapping(value = "/items", method = RequestMethod.GET)
	public String items(Model model) {
		Item item = new Item();
		model.addAttribute("item", item);
		return "items";
	}
}

http://localhost:8080/MyShop/items/ にアクセスすると、エラーなく表示される。