11月16日

共有データベースの作り方

共有データベースを配置するパソコンを決める。
そのパソコンで、server.properties を作成する。
作成する場所は、C:\Users\se3\db\hsqldb-2.3.2\hsqldb\data フォルダ。

server.properties

# Hsqldb Server cfg file.
# See the HyperSQL Network Listeners chapter of the HyperSQL User Guide.

# Each server.database.X setting defines a database "catalog".
# I.e., an independent set of data.
# Each server.database.X setting corresponds exactly to the jdbc:hsqldb:*
# JDBC URL you would use if you wanted to get a direct (In-Process)
# Connection to the catalog instead of "serving" it.
server.database.0=file:db0/mydatabase
server.dbname.0=mydatabase

# I suggest that, for every file: catalog you define, you add the
# connection property "ifexists=true" after the database instance
# is created (which happens simply by starting the Server one time).
# Just append ";ifexists=true" to the file: URL, like so:
# server.database.0=file:db0/db0;ifexists=true

# server.dbname.0 defaults to "" (i.e. server.dbname.n for n==0), but
# the catalog definition n will be entirely ignored for n > 0 if you do not
# set server.dbname.n.  I.e. dbname setting is required for n > 0, though it
# may be set to blank (e.g. "server.dbname.3=")

C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin にある、runServer.bat をダブルクリックして起動する。

コマンドプロンプトに次の出力があれば、データベースの作成に成功している。

C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin>cd ..\data
[Server@24d46ca6]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@24d46ca6]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@24d46ca6]: Startup sequence initiated from main() method
[Server@24d46ca6]: Loaded properties from [C:\Users\se3\db\hsqldb-2.3.2\hsqldb\data\server.properties]
[Server@24d46ca6]: Initiating startup sequence...
[Server@24d46ca6]: Server socket opened successfully in 15 ms.
[Server@24d46ca6]: Database [index=0, id=0, db=file:db0/mydatabase, alias=mydata
base] opened sucessfully in 484 ms.
[Server@24d46ca6]: Startup sequence completed in 499 ms.
[Server@24d46ca6]: 2015-11-16 11:12:14.474 HSQLDB server 2.3.2 is online on port 9001
[Server@24d46ca6]: To close normally, connect and execute SHUTDOWN SQL
[Server@24d46ca6]: From command line, use [Ctrl]+[C] to abort abruptly

C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin にある、runManager.bat をダブルクリックして起動する。
接続のために以下の設定をして、OKすると接続できる。

 Type : HSQL Database Engine Server
 URL  : jdbc:hsqldb:hsql://localhost/mydatabase

他のパソコンから接続するには、パソコンのIPアドレスを調べる必要がある。
コマンドプロンプトを起動して ipconfig コマンドを実行して、IPアドレスを調べる。

C:\Users\se3>ipconfig

Windows IP 構成


Wireless LAN adapter ワイヤレス ネットワーク接続:

   メディアの状態. . . . . . . . . . : メディアは接続されていません
   接続固有の DNS サフィックス . . . :

イーサネット アダプター ローカル エリア接続 2:

   接続固有の DNS サフィックス . . . :
   IPv4 アドレス . . . . . . . . . . : 172.25.20.23
   サブネット マスク . . . . . . . . : 255.255.0.0
   デフォルト ゲートウェイ . . . . . : 172.25.1.254

イーサネット アダプター ローカル エリア接続 3:

   接続固有の DNS サフィックス . . . :
   IPv4 アドレス . . . . . . . . . . : 192.168.56.1
   サブネット マスク . . . . . . . . : 255.255.255.0
   デフォルト ゲートウェイ . . . . . :

他のパソコンから接続する場合は、localhost の代わりにそのパソコンのIPアドレスを指定する。
C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin にある、runManager.bat をダブルクリックして起動する。
接続のために以下の設定をして、OKすると接続できる。

 Type : HSQL Database Engine Server
 URL  : jdbc:hsqldb:hsql://192.168.56.1/mydatabase

エンティティを1対多の関係にする

Onwerが複数のChildを持つ場合は、以下のようにエンティティを作成する。

Owner.java

@Entity
public class Onwer {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @NutNull
    public long id;

    @OneToMany(cascade=CascadeType.ALL)
    @Column(nullable = false)
    private List<Child> children;

    // gettere/setter を用意
}

Child.java

@Entity
public class Child {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @NutNull
    public long id;

    @ManyToOne
    @Column(nullable = false)
    private Owner owner;

    // getter/setter を用意
}

Onwerに複数のChildを追加した状態でエンティティを永続化すると、そのOwnerをDBから取り出したときは、追加した複数のChildが追加された状態で取り出せる。

10月9日

ログインしているユーザー情報の取得

ログインしたユーザー情報を取得するには、コントローラの引数に Principal を追加する。
追加した Princical から getName()メソッドでユーザー名を取得し、addAttribute() で name に値を設定している。

MyDataController.java

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(Model model, Principal p) {
		model.addAttribute("name", p.getName());
		model.addAttribute("title", "MyData");
		model.addAttribute("message", "データを入力してください");
		MyData mydata = new MyData();
		model.addAttribute("myData", mydata);
		MyDataDao<MyData> dao = new MyDataDaoCriteria();
		List<MyData> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "mydata";
	}

mydata.jsp

<body>
	<h1>${title}</h1>
	<p>${message}</p>
	<p>ようこそ ${name} さん</p>
	<table>
	<form:form modelAttribute="myData">

10月5日

データベースを使用した認証

ユーザーとユーザの権限を管理するためのテーブルを作成する。

CREATE TABLE users(
 user_id bigint NOT NULL identity,
 user_name varchar(50) NOT NULL,
 password varchar(50) NOT NULL,
 enabled tinyint NOT NULL,
 role varchar(100) NOT NULL
);

テーブルにテスト用のユーザーを登録する。

INSERT INTO users ( user_name , password , enabled, role)
   VALUES ( 'taro', 'abcd' , 1, 'ROLE_USER' );

spring-security.xml を、データベースを使った認証をするように書き換える。

spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-4.0.xsd">

    <http pattern="/" security="none"/>
    <http pattern="/index.jsp" security="none"/>
    <http auto-config="true" >
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        <form-login />
        <logout />
    </http>

    <beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <beans:property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver" />
        <beans:property name="url" value="jdbc:hsqldb:hsql://localhost/mydatabase" />
        <beans:property name="username" value="sa" />
        <beans:property name="password" value="" />
    </beans:bean>

    <!-- ユーザとROLEを定義 -->
    <authentication-manager>
        <authentication-provider>
            <jdbc-user-service data-source-ref="dataSource"
                 users-by-username-query="SELECT user_name, password, enabled FROM users WHERE user_name = ?"
                 authorities-by-username-query="SELECT user_name, role FROM users WHERE user_name = ?" />
        </authentication-provider>
    </authentication-manager>
</beans:beans>

9月28日

チームごとの決定事項

  • グループA
    • チーム名:つぶやき6ヶ
    • リーダー:新納
    • Webアプリ:Twitter
    • Webアプリ名:Digtter
  • グループB
    • チーム名:harunoumi
    • リーダー:芳賀
    • Webアプリ:匿名掲示板
    • Webアプリ名:はがちゃんねる(HGCH)
  • グループC
    • チーム名:kentomori
    • リーダー:森
    • Webアプリ:スケジュール管理
    • Webアプリ名:スケジュール管理
  • グループD
    • チーム名:SESオールスターズ
    • リーダー:篠原
    • Webアプリ:checkpad
    • Webアプリ名:checkpad
  • グループE
    • チーム名:歪みねぇやぴ軍団
    • リーダー:江藤
    • Webアプリ:Twitter
    • Webアプリ名:本格的♂TEITTER

課題の取り扱い

課題は誰でも作れる。
課題を作るときに、担当者を割り当てる。

  1. 課題を作成する(未対応)
  2. 課題に取り掛かる前に「処理中」に変更する
  3. 課題を済ませたら「処理済」に変更する
  4. 「処理済」の課題を他のメンバーに確認してもらう
  5. 確認OKなら、コミットしてプッシュする
  6. 確認したメンバーが「完了」に変更する

リーダーは課題「ロバストネス図を作成する」を追加する。
他のメンバーは課題「クローンする」を作成する。

9月14日

Criteria API による検索

Criteria API は3つのクラスを組み合わせて利用する。

  • CriteriaBuilder
  • CriteriaQUery
  • Root

テキストでは MyDataDaoImpl を書き換えているが、ここでは新しく実装クラスを作成する。
クラス名を MyDataDaoCriteria とし、Criteria API による実装であることを、クラス名で示す。

新規クラスを作成するときにインタフェース MyDataDao を追加する。総称型 T は、MyData に変更する。
実装されていないメソッドの追加をして、メソッドを生成してもらう。

MyDataDaoCriteria.java

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 MyData findByName(String name) {
		// TODO 自動生成されたメソッド・スタブ
		return null;
	}

	public List<MyData> find(String s) {
		// 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 自動生成されたメソッド・スタブ

	}

}

MyDataControllerの変更

MyDataDao に、MyDataDaoCriteria のインスタンスを設定する。

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(Model model) {
		model.addAttribute("title", "MyData");
		model.addAttribute("message", "データを入力してください");
		MyData mydata = new MyData();
		model.addAttribute("myData", mydata);
		MyDataDao<MyData> dao = new MyDataDaoCriteria();
		List<MyData> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "mydata";
	}

クエリの実装

MyDataController の find() メソッドで Criteria API を使用する。

MyDataController.java

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

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

MyDataDaoCriteria の find() を実装する。

MyDataDaoCriteria.java

	public List<MyData> find(String s) {
		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);
		List<Predicate> preds = new ArrayList<Predicate>();
		if (s != null) {
			preds.add(builder.like(root.<String>get("name"), "%" + s + "%"));
		}
		query.where(builder.and(preds.toArray(new Predicate[0])));
		query.select(root);
		list = manager.createQuery(query).getResultList();
		return list;
	}

さらに、id と mail でも検索できるようにする。

MyDataDaoCriteria.java

	public List<MyData> find(String s) {
		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);
		List<Predicate> preds = new ArrayList<Predicate>();
		if (s != null) {
			try {
				long id = Long.parseLong(s);
				preds.add(builder.equal(root.get("id"), id));
			} catch (NumberFormatException e) {}
			preds.add(builder.like(root.<String>get("name"), "%" + s + "%"));
			preds.add(builder.like(root.<String>get("mail"), s + "@%"));
		}
		query.where(builder.or(preds.toArray(new Predicate[0])));
		query.select(root);
		list = manager.createQuery(query).getResultList();
		return list;
	}

エンティティの連携

1対多のオブジェクト構造を持つエンティティに対して、永続化の実装を追加する。
ここでは、MsgData クラスを追加し、MyData が複数の MsgData 要素を保持できるようにする。

まず MsgData クラスを作成する。

MsgData.java

package jp.abc;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.NotEmpty;

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

	private String title;

	@NotEmpty
	private String message;

	@ManyToOne
	private MyData mydata;

	public long getId() {
		return id;
	}

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

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public MyData getMydata() {
		return mydata;
	}

	public void setMydata(MyData mydata) {
		this.mydata = mydata;
	}
}

MyData が複数の MsgData を保持できるようにする。

MyData.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;
import javax.validation.constraints.Size;

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

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

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

	@Column(nullable = true)
	private Integer age;

	@Column(nullable = true)
	private String memo;

	@OneToMany(cascade = CascadeType.ALL)
	private List<MsgData> msgdatas;

	public long getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

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

	public String getMail() {
		return mail;
	}

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

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}

	public List<MsgData> getMsgdatas() {
		return msgdatas;
	}

	public void setMsgdatas(List<MsgData> msgdatas) {
		this.msgdatas = msgdatas;
	}
}

MsgDataDao の用意

MsgDataDao.java

package jp.abc;

import java.util.List;

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

MsgDataDaoの実装クラスを作成する。

MsgDataDaoImpl.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 MsgDataDaoImpl implements MsgDataDao<MsgData> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

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

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

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

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

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

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

}

ビューテンプレートの作成

src/main/webapp/WEB-INF/view の中に、JSPファイル msgdata.jsp を新規作成する。

msgdata.jsp

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

MyDataContoller に、新しいマッピングを追加する。

MyDataController.java

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

9月11日

CRUDの実装

エンティティの削除

エンティティを削除するには、remove を使用するが、その前に merge する必要がある。(テキストp.297)

MyDataDaoImpl.java

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

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

別のアプリDatabaseManagerを使用することで、SQLを実行できる。

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

hsqldb

spring12

hsqldbmanager

JSPに編集と削除のリンクを追加する

mydata.jsp のテーブル部分に、編集と削除のリンクをanchorタグで追加する。

mydata.jsp

	<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>
					<td><a href="/MyData/update?id=${obj.id}">編集</a></td>
					<td><a href="/MyData/delete?id=${obj.id}">削除</a></td>
				</tr>
			</c:forEach>
		</table>
	</c:if>

JPQLを活用する

MyDataアプリケーションで検索機能を追加する。

find.jspの作成

find.jsp

<!DOCTYPE html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>${title}</title>
</head>
<body>
	<h1>${title}</h1>
	<p>${message}</p>

	<table>
	<form action="/MyData/find" method="post">
		<tr>
			<td>FIND:</td>
			<td><input type="text" name="fstr" size="20" /></td>
		</tr>
		<tr>
			<td></td><td><input type="submit" /></td>
		</tr>
	</form>
	</table>

	<hr />
	<c:if test="${datalist != null}">
		<table border="1">
			<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>

コントローラの追加

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

MyDataController.java

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

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

DAOにfindメソッドを追加する

MyDataDao.java

package jp.abc;

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

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

MyDataDaoImpl.java

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

9月7日

CRUD

CRUDとは?

CRUD(クラッド)とは、ほとんど全てのコンピュータソフトウェアが持つ永続性[1]の4つの基本機能のイニシャルを並べた用語。その4つとは、Create(生成)、Read(読み取り)、Update(更新)、Delete(削除)である。ユーザインタフェースが備えるべき機能(情報の参照/検索/更新)を指す用語としても使われる。
https://ja.wikipedia.org/wiki/CRUD

現状では、CreateとReadしかないので、UpdateとDeleteを追加していく。

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

MyDataDao.java

package jp.abc;

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

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

MyDataDao.java を保存すると MyDataDaoImple.java がコンパイルエラーになる。
必要なメソッドを追加する。

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

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

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

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

}

MyDataDaoImpl の実装が終わったら、次にコントローラに更新のためのメソッドを追加する。

MyDataController.java

package jp.abc;

import java.util.List;

import javax.validation.Valid;

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

@Controller
public class MyDataController {

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(Model model) {
		model.addAttribute("title", "MyData");
		model.addAttribute("message", "データを入力してください");
		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 errors, Model model) {
		if (errors.hasErrors()) {
			model.addAttribute("title", "MyData - エラー");
			model.addAttribute("message", "値をチェックしてください");
			return "mydata";
		}
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		dao.add(mydata);
		return "redirect:/mydata";
	}

	@RequestMapping(value = "/update", method = RequestMethod.GET)
	public String edit(@RequestParam(value = "id")int id, Model model) {
		model.addAttribute("title", "MyData更新");
		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";
	}
}

URLでリクエストパラメータに id を指定すれば、現在の値が表示される。

http://localhost:8080/MyData/update?id=4

update-1

エンティティの削除の実装

MyDataController.java

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

URLでリクエストパラメータに id を指定すれば、対応するエンティティが削除される。

http://localhost:8080/MyData/delete?id=2

8月31日

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

5章のために、新規プロジェクトを作成する。

プロジェクト名: MyData

いつもの手順でプロジェクトを生成し、http://localhost:8080/MyData/ にアクセスする。
click to enter が表示されればOK。

pom.xmlの変更

pom.xml に以下の内容を追加する。

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.1</version>
		</dependency>

		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<version>2.3.2</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>

pom.xml を保存したらエラーが出るかも。
エラーが出たらダイアログで「OK」してダイアログを閉じる。

プロジェクトを右クリックして、
[maven]-[プロジェクトの更新]
[実行]-[maven install]
を実行する。

134行目の ${spring.version} でエラーが出る場合は、${spring-framework.version} に変更する。

database.propertiesの作成

Javaリソースの下の src/main/resources の下の spring フォルダを右クリックし[新規]-[ファイル]を選択する。
ファイル名に database.properties を指定して、テキスト p.270 のリスト5-4の内容を入力して保存する。

database.properties

database.driverClassName=org.hsqldb.jdbc.JDBCDriver
database.url=jdbc:hsqldb:mem:mydata
database.username=sa
database.password=

persistence.xmlの作成

Javaリソースの下の src/main/resources を右クリックし[新規]-[フォルダ]を選択する。
フォルダ名に META-INF と入力して完了。

作成した META-INF フォルダを右クリックして[新規]-[XMLファイル]を選択する。(XMLファイルがなければ「その他」から探す)
ファイル名に persistence.xml と入力して完了。

テキスト p.272 の内容を入力する。

persistence.xml

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

application-config.xml の変更

Javaリソースの下の src/main/resources の下の spring フォルダにある 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>

mvc-config.xmlの変更

mvc-config.xml

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

MyDataクラスの作成

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

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

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

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

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

	@Column(nullable = true)
	private Integer age;

	@Column(nullable = true)
	private String memo;

	public long getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

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

	public String getMail() {
		return mail;
	}

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

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}
}

Data Access Object の作成

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

MyDataDao.java

package jp.abc;

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

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

実装クラスを作成する。
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 MyDataImpl 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();
	}

}

8月28日

年齢計算アプリを作成する

入力フォームで生年月日をSelectで入力する。

生年月日を入力してください。
「    」年「  」月「  」日
[計算]

計算ボタンを押すと、生年月日と曜日、満年齢を表示する。

生年月日はxxxx年xx月xx日x曜日です。
満xx歳です。

プロジェクト名: Age
テンプレート: Simple Spring Web Maven

form.jsp

<!DOCTYPE html>

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

<html>
    <head>
        <meta charset="utf-8">
        <title>年齢計算</title>
    </head>
    <body>
        <h1>年齢計算</h1>
        <div style="font-size: 24pt;">${result}</div>
        <h2>${message}</h2>
        <form:form modelAttribute="formModel">
        <form:select path="year" name="year"
            items="${years}" multiple="false" />年
        <form:select path="month" name="month"
            items="${months}" multiple="false" />月
        <form:select path="day" name="day"
            items="${days}" multiple="false" />日
        <br />
        <input type="submit" value="計算" />
        </form:form>
    </body>
</html>

FormModelを作成する。
ここでは生年月日なので、Year・Month・Dayがあればよい。

FormModel.java

package jp.abc;

public class FormModel {
	private String year;
	private String month;
	private String day;
	public String getYear() {
		return year;
	}
	public void setYear(String year) {
		this.year = year;
	}
	public String getMonth() {
		return month;
	}
	public void setMonth(String month) {
		this.month = month;
	}
	public String getDay() {
		return day;
	}
	public void setDay(String day) {
		this.day = day;
	}
}

コントローラでSelectの要素をListにして渡す。

AgeController.java

	@RequestMapping(value = "/form", method = RequestMethod.GET)
	public String helo(Model model) {
	    model.addAttribute("title", "ModelAndView sample");
	    model.addAttribute("message", "年齢を計算します。");
	    FormModel fm = new FormModel();
	    model.addAttribute("formModel", fm);
	    model.addAttribute("years", getYears());
	    model.addAttribute("months", getMonths());
	    model.addAttribute("days", getDays());
	    return "form";
	}

getYears()・getMonths()・getDays() の各メソッドでは、Listを返す。

getYears()の例

	private List<String> getYears() {
		List<String> list = new ArrayList<String>();
		for (int i = 1900; i <= 2015; i++) {
			list.add(String.valueOf(i));
		}
		return list;
	}

コントローラにPOSTメソッドをリクエストされたときの処理を実装する。

AgeController.java

	@RequestMapping(value = "/form", method = RequestMethod.POST)
	public String rating(@ModelAttribute FormModel formModel, Model model) {
	        model.addAttribute("message", "年齢を計算します。");
	        int y = Integer.parseInt(formModel.getYear());
	        int m = Integer.parseInt(formModel.getMonth());
	        int d = Integer.parseInt(formModel.getDay());
	        String s = getBirthday(y, m, d);
	        s += "<br />";
	        s += "満" + getAge(y, m, d) + "歳です。";
	        model.addAttribute("result", s);
	        FormModel fm = new FormModel();
	        model.addAttribute("formModel", fm);
		    model.addAttribute("years", getYears());
		    model.addAttribute("months", getMonths());
		    model.addAttribute("days", getDays());
	    return "form";
	}

getBirthday() と getAge() を追加する。

	private String getBirthday(int y, int m, int d) {
		Calendar c = Calendar.getInstance();
		c.set(y, m - 1, d);
		SimpleDateFormat f = new SimpleDateFormat("yyyy年MM月dd日 E曜日");
		return f.format(c.getTime());
	}

	private int getAge(int y, int m, int d) {
		Calendar c = Calendar.getInstance();
		int ty = c.get(Calendar.YEAR);
		int tm = c.get(Calendar.MONTH) + 1;
		int td = c.get(Calendar.DATE);
		int age = ty - y;
		if (tm > m) return age - 1;
		if (tm == m && td > d) return age - 1;
		return age;
	}