10月2日

これからのチーム開発のやりかた

  1. 毎朝、それぞれが取り組む課題を決定する。
  2. Backlogに課題を登録する。
  3. 課題を「未対応」→「処理中」に変更する。
  4. 課題に取り組む。
  5. ファイルを新規で作った場合はGitに追加する。
  6. 終わったらGitにコミットする(コミットメッセージは課題のIDのみ)
  7. 課題を「処理中」→「処理済み」に変更する。
  8. チームのほかのメンバーに確認してもらう。
  9. 確認したメンバーが課題を「処理済み」→「完了」に変更する。
  10. Backlogのリモートリポジトリにプッシュする。
  11. ほかのメンバーにプッシュしたことを伝え、プルしてもらう。
  12. 1に戻る。

課題の内容は、当日(1~2現の3時間)で完了できる内容にすること。

課題のタイトルは、ロバストネス図に書いた、画面・コントローラ・エンティティなどを書いて、それに対してどのような変更をするのかを記載し、課題で何を解決しようとしているのかが一目でわかるようにすること。

課題の詳細欄には、変更する具体的な内容や、変更するファイル名などを記載する。タイトルだけでわかるのであれば、書かなくてもよい。

9月15日

SpringMVCにおけるユーザー認証

SpringMVCでは、spring-securityを使ってユーザー認証を行う。
そのために、pom.xmlに以下の内容を追加する。

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>4.0.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>4.0.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>4.0.1.RELEASE</version>
</dependency>

web.xmlの最後にフィルターを追加する。

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
  
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

src/main/resources/spring フォルダに、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/mydata" />
        <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>

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

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

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

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

チーム開発

チームで開発するWebアプリケーションを決めよう!

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

以下のことを決めよう。

  • 作成するサービスを決める(候補を出す)
  • チーム名を決める
  • リーダーを決める
  • サービスの名前(プロジェクト名)を決める
  • 基本的な画面遷移図(ロバストネス図)を作成する

ロバストネス図は、astah community で作れる。

チーム1

チーム名:やりたい
リーダー:西田
サービス名:やりたま
プロジェクト名:Yaritama

チーム2

チーム名:ナイトプール
リーダー:中尾
サービス名: 写真共有アプリ
プロジェクト名: PhotoSharing

チーム3

チーム名:ボビーオロゴン
リーダー:前田
サービス名:診断メーカー
プロジェクト名:ShindanMaker

チーム4

チーム名:ママ、早く!
リーダー:山本
サービス名:掲示板
プロジェクト名:3chan

チーム5

チーム名:ゲームウィキ麻生支部
リーダー:宮崎
サービス名:ゲームウィキ
プロジェクト名:GameWiki

9月11日

Gitの練習

todo.jsp を変更してみる。

<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<h3>未完了</h3>
<div id="todo">
<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <c:if test="${t.done == null}">
        <div id="check${t.id}">
      	  <input type="checkbox" name="items" value="${t.id}" />${t.item} <span class="days">${t.days}日前</span>
        </div>
      </c:if>
    </c:forEach>
  </form>
</c:if>
</div>

変更して保存すると、プロジェクトエクスプローラ上のファイル名の左側に「>」が表示される。
これは、リポジトリの最新の状態から変更があったことを示す。

プロジェクトを右クリックして[チーム]-[コミット]を選択すると、todo.jsp がファイルリストに表示される。
todo.jspをダブルクリックすると変更箇所が確認できる。
変更内容が間違いなければ、コミットメッセージを入力してコミットを実行する。

未完了項目の経過日数表示

未完了項目の右側に登録してからの経過日数を表示するようにする。
経過日数はサーバー側で計算した方が実装が簡単そうなので、ToDoエンティティに経過日数を格納する days を追加する。
このデータはデータベースに保存する必要はないので @Transient アノテーションを追加しておく。

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.Transient;

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

	@Column
	private String item;

	@Column
	private Date created;

	@Column
	private Date done;

	@Transient
	private int days;

	public long getId() {
		return id;
	}

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

	public String getItem() {
		return item;
	}

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

	public Date getCreated() {
		return created;
	}

	public void setCreated(Date created) {
		this.created = created;
	}

	public Date getDone() {
		return done;
	}

	public void setDone(Date done) {
		this.done = done;
	}

	public int getDays() {
		return days;
	}

	public void setDays(int days) {
		this.days = days;
	}
}

コントローラを見ると、あちこちで dao.getAll() を使っているので、コントローラではなくDAO実装内で追加すると一か所の変更で済ませることができる。

	public List<ToDo> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<ToDo> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<ToDo> q = builder.createQuery(ToDo.class);
		Root<ToDo> r = q.from(ToDo.class);
		q.select(r);
		list = (List<ToDo>)manager.createQuery(q).getResultList();
		manager.close();
		Date now = new Date();
		for (ToDo t : list) {
			long diff = now.getTime() - t.getCreated().getTime();
			diff = diff / (1000 * 60 * 60 * 24);
			t.setDays((int)diff);
		}
		return list;
	}

todo.jsp の未完了項目の右側に値を追加してみる。

<h3>未完了</h3>
<div id="todo">
<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <c:if test="${t.done == null}">
        <div id="check${t.id}">
      	  <input type="checkbox" name="items" value="${t.id}" />${t.item} ${t.days}日前
        </div>
      </c:if>
    </c:forEach>
  </form>
</c:if>
</div>

「○日前」の文字サイズや色を変更するために span タグで囲む。

      	  <input type="checkbox" name="items" value="${t.id}" />${t.item} <span class="days">${t.days}日前</span>

days クラス用のCSSを用意する。

<title>ToDoアプリ</title>
<style type="text/css">
span.days {
  font-size: 9pt;
  color: gray;
  margin-left: 20px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

動作確認したら、プロジェクトを右クリックして[チーム]-[コミット]を選択する。
ToDo.java
ToDoDaoImpl.java
todo.jsp
の3ファイルがリストされる。
それぞれのファイルをダブルクリックして変更箇所を確認し、問題がなければコミットメッセージを入力してコミットを実行する。

完了済みの項目の経過日数

完了済みの項目の経過日数は、完了した日からの経過日数を表示する。

まずは、未完了項目と同じように、登録日からの経過日数を表示してみる。

<h3>完了済み</h3>
<div id="done">
<c:if test="${list != null}">
  <c:forEach var="t" items="${list}">
    <c:if test="${t.done != null}">
      <div id="check${t.id}">
        <input type="checkbox" name="items" value="${t.id}" checked="checked" />${t.item} <span class="days">${t.days}日前</span>
      </div>
    </c:if>
  </c:forEach>
</c:if>
</div>

完了項目に対しての days の値は、完了日からの経過日数となるように、サーバー側の ToDoDaoImpl.java で計算する。

	public List<ToDo> getAll() {
		EntityManager manager = factory.createEntityManager();
		List<ToDo> list = null;
		CriteriaBuilder builder = manager.getCriteriaBuilder();
		CriteriaQuery<ToDo> q = builder.createQuery(ToDo.class);
		Root<ToDo> r = q.from(ToDo.class);
		q.select(r);
		list = (List<ToDo>)manager.createQuery(q).getResultList();
		manager.close();
		Date now = new Date();
		for (ToDo t : list) {
			long from;
			if (t.getDone() == null) {
				from = t.getCreated().getTime();
			} else {
				from = t.getDone().getTime();
			}
			long diff = now.getTime() - from;
			diff = diff / (1000 * 60 * 60 * 24);
			t.setDays((int)diff);
		}
		return list;
	}

新しく項目を追加したり、チェックボックスをチェックすると「○日前」の表示が消えてしまう。
これは、上記操作をしたときに、jQueryでHTML要素を生成しなおしているため。
span要素を追加する処理を、jQueryで記述することで解決する。

function init() {
	$('input[name="items"]').change(function(){
		console.log($(this).prop('checked'));
		var url;
		if ($(this).prop('checked')) {
			url = 'done';
		} else {
			url = 'redo';
		}
		$.post(
			url,
			'id=' + $(this).val(),
			function(data) {
				console.log(data);
				$('#todo form').children().remove();
				$('#done').children().remove();
				for (var i = 0; i < data.length; i++) {
					var div = $('<div>');
					div.attr('id', 'check' + data[i].id);
					var cb = $('<input>')
								.attr('type', 'checkbox')
								.attr('name', 'items')
								.attr('value', data[i].id);
					div.append(cb).append(data[i].item)
					var s = $('<span>');
					s.addClass('days');
					s.text(data[i].days + '日前');
					div.append(s);
					if (data[i].done == null) {
						$('#todo form').append(div);
					} else {
						cb.attr('checked', 'checked');
						$('#done').append(div);
					}
				}
				init();
			});
	});
}

動作確認できたら、[チーム]-[コミット]で変更内容をGitリポジトリに反映させる。

これまでの変更内容は、[チーム]-[ヒストリーに表示]で確認できる。

9月8日

サーバーから受信したデータをもとに画面を更新するようにしたところ、最初のチェックに対してはToDo項目が完了済みに移動したが、2個目からは移動しなくなってしまった。

これは、change()イベントを拾う処理が画面読み込み完了時(load)のみに行われているため。

新しく生成した input[name=”items”] のセレクタで指定した要素にはイベントを拾う処理が登録されていないために動作しない。

この対策を実施する。
まずはload時の処理をfunctionに分割する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	init();
})

function init() {
	$('input[name="items"]').change(function(){
		console.log($(this).parent());
		$('#done').append($(this).parent());
		$.post(
			'done',
			'id=' + $(this).val(),
			function(data) {
				console.log(data);
				$('#todo form').children().remove();
				$('#done').children().remove();
				for (var i = 0; i < data.length; i++) {
					var div = $('<div>');
					div.attr('id', 'check' + data[i].id);
					var cb = $('<input>')
								.attr('type', 'checkbox')
								.attr('name', 'items')
								.attr('value', data[i].id);
					div.append(cb).append(data[i].item);
					if (data[i].done == null) {
						$('#todo form').append(div);
					} else {
						cb.attr('checked', 'checked');
						$('#done').append(div);
					}
				}
			});
	});
}
</script>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<div id="todo">
<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <c:if test="${t.done == null}">
        <div id="check${t.id}">
      	  <input type="checkbox" name="items" value="${t.id}" />${t.item}
        </div>
      </c:if>
    </c:forEach>
  </form>
</c:if>
</div>

<hr />
<h3>完了済み</h3>
<div id="done">
<c:if test="${list != null}">
  <c:forEach var="t" items="${list}">
    <c:if test="${t.done != null}">
      <div id="check${t.id}">
        <input type="checkbox" name="items" value="${t.id}" checked="checked" />${t.item}
      </div>
    </c:if>
  </c:forEach>
</c:if>
</div>



</body>
</html>

この変更ではいままでどおりの動作となる。

さらに、サーバーからデータを受信して、新規に要素を生成して画面上に追加した処理のあとに init() を呼ぶようにすることで、チェックボックスのイベントに対しての処理を行うようにする。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	init();
})

function init() {
	$('input[name="items"]').change(function(){
		console.log($(this).parent());
		$('#done').append($(this).parent());
		$.post(
			'done',
			'id=' + $(this).val(),
			function(data) {
				console.log(data);
				$('#todo form').children().remove();
				$('#done').children().remove();
				for (var i = 0; i < data.length; i++) {
					var div = $('<div>');
					div.attr('id', 'check' + data[i].id);
					var cb = $('<input>')
								.attr('type', 'checkbox')
								.attr('name', 'items')
								.attr('value', data[i].id);
					div.append(cb).append(data[i].item);
					if (data[i].done == null) {
						$('#todo form').append(div);
					} else {
						cb.attr('checked', 'checked');
						$('#done').append(div);
					}
				}
				init();
			});
	});
}
</script>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<div id="todo">
<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <c:if test="${t.done == null}">
        <div id="check${t.id}">
      	  <input type="checkbox" name="items" value="${t.id}" />${t.item}
        </div>
      </c:if>
    </c:forEach>
  </form>
</c:if>
</div>

<hr />
<h3>完了済み</h3>
<div id="done">
<c:if test="${list != null}">
  <c:forEach var="t" items="${list}">
    <c:if test="${t.done != null}">
      <div id="check${t.id}">
        <input type="checkbox" name="items" value="${t.id}" checked="checked" />${t.item}
      </div>
    </c:if>
  </c:forEach>
</c:if>
</div>



</body>
</html>

チェックボックスのチェックを外された時は、ToDo項目を完了済みから未完了に移動させるようにする。

サーバー側では、URL /redo を用意する。処理の内容は、done()とほぼ同じで、ToDoエンティティのcreatedの値を現在時刻にして、doneの値をnullに戻すだけの違い。

 	@RequestMapping(value = "/redo", method = RequestMethod.POST)
	@ResponseBody
	@ResponseStatus(value = HttpStatus.OK)
	public List<ToDo> redo(@RequestParam(value = "id") String id, Model model) {
		ToDoDao<ToDo> dao = new ToDoDaoImpl();
		ToDo todo = dao.findById(Long.parseLong(id));
		todo.setCreated(new Date());
		todo.setDone(null);
		dao.update(todo);
		List<ToDo> list = dao.getAll();
		return list;
	}

ブラウザ側では、完了済みにあるチェックボックスのチェックが外されたときは、redo に POST 送信するように、JavaScriptコードを書き換えればよい。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	init();
})

function init() {
	$('input[name="items"]').change(function(){
		console.log($(this).prop('checked'));
		var url;
		if ($(this).prop('checked')) {
			url = 'done';
		} else {
			url = 'redo';
		}
		$.post(
			url,
			'id=' + $(this).val(),
			function(data) {
				console.log(data);
				$('#todo form').children().remove();
				$('#done').children().remove();
				for (var i = 0; i < data.length; i++) {
					var div = $('<div>');
					div.attr('id', 'check' + data[i].id);
					var cb = $('<input>')
								.attr('type', 'checkbox')
								.attr('name', 'items')
								.attr('value', data[i].id);
					div.append(cb).append(data[i].item);
					if (data[i].done == null) {
						$('#todo form').append(div);
					} else {
						cb.attr('checked', 'checked');
						$('#done').append(div);
					}
				}
				init();
			});
	});
}
</script>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<div id="todo">
<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <c:if test="${t.done == null}">
        <div id="check${t.id}">
      	  <input type="checkbox" name="items" value="${t.id}" />${t.item}
        </div>
      </c:if>
    </c:forEach>
  </form>
</c:if>
</div>

<hr />
<h3>完了済み</h3>
<div id="done">
<c:if test="${list != null}">
  <c:forEach var="t" items="${list}">
    <c:if test="${t.done != null}">
      <div id="check${t.id}">
        <input type="checkbox" name="items" value="${t.id}" checked="checked" />${t.item}
      </div>
    </c:if>
  </c:forEach>
</c:if>
</div>



</body>
</html>

Gitによるバージョン管理

Eclipseでプロジェクトを右クリックし、[チーム]-[プロジェクトの共用]を選択する。
リポジトリタイプは「Git」を選択し「次へ」をクリックする。
リポジトリの「作成」をクリックし、リポジトリディレクトリに「C:\Users\name\git」が指定されている。
「完了」ボタンが押せない場合は、フォルダ名を適当に変更して「完了」ボタンが有効になるようにし、「完了」をクリックする。
「完了」すると、プロジェクト名の右側に「NO-HEAD」の表示が出る。

プロジェクトを右クリックし、[チーム]-[コミット]を選択すると、画面の下にコミット対象となるファイルの一覧が表示される。余計なファイルがたくさん含まれているので、これを除外する設定を行う。
リポジトリ内にあるプロジェクトのフォルダ内に「.gitignore」ファイルを作成する。
エクスプローラでは新規ファイルでテキストファイル「gitignore.txt」を作成する。
コマンドプロンプトを起動してファイル名を変更する。

> ren gitignore.txt .gitignore

.gitignore ファイル内に、除外するファイルやフォルダ名を記載する。

/target
.settings/
.classpath
.project
/pleiades45

.gitignore ファイルを保存したら、Eclipseでプロジェクトを右クリックし「リフレッシュ」を選択する。
プロジェクトを右クリックし[チーム]-[コミット]を選択する。
コミット対象のファイル一覧に余計なファイルが含まれていないことを確認したら、コミットメッセージに変更理由(今回は最初なので「新規作成」でもよい)などを記載して「コミット」をクリックする。

コミットが成功したら、プロジェクト名の右側が「master」に変化する。

9月4日

前回は、ToDo項目にチェックすると、AJAXでサーバーにデータを送信して、完了日時をエンティティに登録し、データベースを更新するところまで実装した。

この状態でToDo項目の画面にアクセスすると、完了済みの項目が未完了に表示されてしまう。

未完了のToDo項目と、完了済みのToDo項目をそれぞれの領域に表示するよう修正する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	$('input[name="item"]').change(function(){
		console.log($(this).parent());
		$('#done').append($(this).parent());
		$.post('done', 'id=' + $(this).val());
	});
})
</script>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <c:if test="${t.done == null}">
        <div id="check${t.id}">
      	  <input type="checkbox" name="item" value="${t.id}" />${t.item}
        </div>
      </c:if>
    </c:forEach>
  </form>
</c:if>

<hr />
<h3>完了済み</h3>
<div id="done">
<c:if test="${list != null}">
  <c:forEach var="t" items="${list}">
    <c:if test="${t.done != null}">
      <div id="check${t.id}">
        <input type="checkbox" name="item" value="${t.id}" checked="checked" />${t.item}
      </div>
    </c:if>
  </c:forEach>
</c:if>
</div>



</body>
</html>

テキストフィールドに入力して「登録」ボタンを押すと、テキストフィールドが完了済みに移動してしまう問題を解決する。

jQueryで input[name=”item”] というセレクタを指定していると、これがテキストフィールドにも該当してしまう。
チェックボックスのnameをitemsに変更してchangeイベントを拾うところもinput[name=”items”]とする。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	$('input[name="items"]').change(function(){
		console.log($(this).parent());
		$('#done').append($(this).parent());
		$.post('done', 'id=' + $(this).val());
	});
})
</script>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <c:if test="${t.done == null}">
        <div id="check${t.id}">
      	  <input type="checkbox" name="items" value="${t.id}" />${t.item}
        </div>
      </c:if>
    </c:forEach>
  </form>
</c:if>

<hr />
<h3>完了済み</h3>
<div id="done">
<c:if test="${list != null}">
  <c:forEach var="t" items="${list}">
    <c:if test="${t.done != null}">
      <div id="check${t.id}">
        <input type="checkbox" name="items" value="${t.id}" checked="checked" />${t.item}
      </div>
    </c:if>
  </c:forEach>
</c:if>
</div>



</body>
</html>

pom.xmlにJSONを扱うためのライブラリを追加する。

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>2.8.8</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.8.9</version>
		</dependency>

追加したら、[maven]-[プロジェクトの更新]と[実行]-[maven install]を実行する。

ToDo項目を更新するための /done に対してPOST送信したら、その応答で、JSONデータを返すようにする。

	@RequestMapping(value = "/done", method = RequestMethod.POST)
	@ResponseBody
	@ResponseStatus(value = HttpStatus.OK)
	public List<ToDo> done(@RequestParam(value = "id") String id, Model model) {
		ToDoDao<ToDo> dao = new ToDoDaoImpl();
		ToDo todo = dao.findById(Long.parseLong(id));
		todo.setDone(new Date());
		dao.update(todo);
		List<ToDo> list = dao.getAll();
		return list;
	}

jQueryでPOSTしたときに応答を受信してJavaScriptコンソールにデータを出力してみる。

<script type="text/javascript">
$(function(){
	$('input[name="items"]').change(function(){
		console.log($(this).parent());
		$('#done').append($(this).parent());
		$.post(
			'done',
			'id=' + $(this).val(),
			function(data) {
				console.log(data);
			});
	});
})
</script>

チェックして、サーバーからデータを受け取ったら、受け取ったデータに基づいてToDo項目を更新する。
まずは、既存の項目をすべて削除する。

<script type="text/javascript">
$(function(){
	$('input[name="items"]').change(function(){
		console.log($(this).parent());
		$('#done').append($(this).parent());
		$.post(
			'done',
			'id=' + $(this).val(),
			function(data) {
				console.log(data);
				$('#todo form').children().remove();
				$('#done').children().remove();
			});
	});
})
</script>

受信したJSONデータにもとづいてdiv要素を作り直す。
完了日時が設定されていなければ未完了側に、設定されていれば完了側にdiv要素を追加する。

$(function(){
	$('input[name="items"]').change(function(){
		console.log($(this).parent());
		$('#done').append($(this).parent());
		$.post(
			'done',
			'id=' + $(this).val(),
			function(data) {
				console.log(data);
				$('#todo form').children().remove();
				$('#done').children().remove();
				for (var i = 0; i < data.length; i++) {
					var div = $('<div>');
					div.attr('id', 'check' + data[i].id);
					var cb = $('<input>')
								.attr('type', 'checkbox')
								.attr('name', 'items')
								.attr('value', data[i].id);
					div.append(cb).append(data[i].item);
					if (data[i].done == null) {
						$('#todo form').append(div);
					} else {
						cb.attr('checked', 'checked');
						$('#done').append(div);
					}
				}
			});
	});
})
</script>

9月1日

jQueryとAJAXでTODO項目を更新する。

jQueryライブラリを追加する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <input type="checkbox" name="item" value="${t.id}" />${t.item}<br />
    </c:forEach>
  </form>
</c:if>



</body>
</html>

jQueryでチェックボックスのイベントを取得するためのコードを追加する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	$('input[name="item"]').change(function(){
		console.log("change");
	});
})
</script>
</head>
(略)

チェックボックスをクリックすると、JavaScriptコンソールに change が出力されるのが確認できる。

次に、チェックボックスをクリックしたときに、完了済みのエリアにチェックボックスを移動するように処理を追加する。
そのために、完了済みのチェックボックスを配置するための場所を用意する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	$('input[name="item"]').change(function(){
		console.log("change");
	});
})
</script>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <input type="checkbox" id="check${t.id}" name="item" value="${t.id}" />${t.item}<br />
    </c:forEach>
  </form>
</c:if>

<hr />
<h3>完了済み</h3>
<div id="done"></div>

</body>
</html>

実際にチェックボックスをクリックしてみると、□だけが移動してしまう。
文字も移動させるために、div要素でまとめる。

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <div id="check${t.id}">
      	<input type="checkbox" name="item" value="${t.id}" />${t.item}
      </div>
    </c:forEach>
  </form>
</c:if>

チェックボックスがクリックされたイベントが発生したら、完了済みに移動する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	$('input[name="item"]').change(function(){
		console.log($(this).parent());
		$('#done').append($(this).parent());
	});
})
</script>
</head>

コントローラに、完了を受け取るためのメソッドを用意する。
パラメータを受け取れたかどうかを確認するためのコードを書いておく。

	@RequestMapping(value = "/done", method = RequestMethod.POST)
	public void done(@RequestParam(value = "id") String id, Model model) {
		System.out.println(id);
	}

ブラウザでチェックボックスをチェックすると、そのIDがサーバー側のコンソールに表示されることがわかる。

ToDoエンティティを更新できるようにする。

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

package jp.abc;

import java.util.List;

public interface ToDoDao<T> {
	public List<T> getAll();
	public void add(T item);
	public T findById(long id);
	public void update(T item);
}

ToDoDaoImplに実装を追加する。

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

public class ToDoDaoImpl implements ToDoDao<ToDo> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

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

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

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

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

}

コントローラでToDoエンティティを更新するコードを追加する。

	@RequestMapping(value = "/done", method = RequestMethod.POST)
	public void done(@RequestParam(value = "id") String id, Model model) {
		ToDoDao<ToDo> dao = new ToDoDaoImpl();
		ToDo todo = dao.findById(Long.parseLong(id));
		todo.setDone(new Date());
		dao.update(todo);
	}

8月28日

SpringMVCによるWebアプリを作成する練習問題

ToDoリストアプリ

プロジェクト名: ToDo
パッケージ名: jp.abc
コントローラクラス名: ToDoController
エンティティクラス名: ToDo
JSPファイル名: todo.jsp

最初に基本動作となる画面遷移部分を作成する。

  1. プロジェクトを作成する。
  2. [Maven]-[プロジェクトの更新]を実行する。
  3. [実行]-[maven install]を実行する。
  4. Tomcatサーバーに作成したプロジェクトを追加する。
  5. Tomcatサーバーを起動する。
  6. http://localhost:8080/ToDo/ にアクセスする。
    → 「click to enter」表示でOK
  7. mvc-config.xml を修正して jp.abc パッケージを読み込むようにする。
  8. ToDoControllerを作成する。
  9. ToDoControllerで指定したURLにアクセスする。
    → todo.jsp がないのでエラー
  10. todo.jspを作成する。
  11. ToDoControllerで指定したURLにアクセスする。
    → todo.jsp の内容が表示されればOK
  12. 「登録」ボタンを押す。→ POSTメソッドに未対応なのでエラー
  13. ToDoControllerにPOSTメソッドを受け付けるメソッドを追加してtodo.jspにリダイレクトする。
  14. 「登録」ボタンを押す。
    → todo.jspが表示されればOK
  15. 日本語は文字化けするのでweb.xmlを変更して文字化け対策をする。

コントローラは、単純に todo.jsp を表示させるだけのシンプルなものを作成する。

ToDoController.java

package jp.abc;

import java.util.List;

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

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

}

JSPは、ToDo項目を入力するフィールドと登録ボタンを用意する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

</body>
</html>

画面遷移ができるようになったら、エンティティとDAOを用意してToDo項目をデータベースに保存できるようにする。

エンティティ: ToDo
DAO: ToDoDao
DAO実装: ToDoDaoImpl

設定ファイルなどの準備作業を行う。

  1. pom.xml にデータベースアクセス関連の依存関係を追加する。
  2. database.properties ファイルを作成する。
  3. persistence.xmlファイルを作成する。
  4. application-config.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.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>

エンティティとDAOとDAO実装を作成して、コントローラからデータベースにアクセスする。

  1. ToDoエンティティを作成する。
  2. DAOとDAOの実装を作成する。
  3. ToDoControllerに、DAOを通してデータベースにアクセスするコードを追加する。

ToDoエンティティでは、ToDoの内容をitem、作成した日時 created、完了日 done のメンバーを持たせる。

ToDo.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;

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

	@Column
	private String item;

	@Column
	private Date created;

	@Column
	private Date done;

	public long getId() {
		return id;
	}

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

	public String getItem() {
		return item;
	}

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

	public Date getCreated() {
		return created;
	}

	public void setCreated(Date created) {
		this.created = created;
	}

	public Date getDone() {
		return done;
	}

	public void setDone(Date done) {
		this.done = done;
	}
}

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

ToDoDao.java

package jp.abc;

import java.util.List;

public interface ToDoDao<T> {
	public List<T> getAll();
	public void add(T item);
}

DAOの実装を作成する。

ToDoDaoImple.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 ToDoDaoImpl implements ToDoDao<ToDo> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

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

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

}

コントローラからデータベースにアクセスするコードを追加する。

ToDoController.java

package jp.abc;

import java.util.Date;
import java.util.List;

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

@Controller
public class ToDoController {

	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public String todo(Model model) {
		ToDoDao<ToDo> dao = new ToDoDaoImpl();
		List<ToDo> list = dao.getAll();
		model.addAttribute("list", list);
		return "todo";
	}

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String add(@RequestParam(value = "item") String item, Model model) {
		ToDo todo = new ToDo();
		ToDoDao<ToDo> dao = new ToDoDaoImpl();
		todo.setItem(item);
		todo.setCreated(new Date());
		dao.add(todo);
		return "redirect:/list";
	}
}

todo.jsp に、ToDo項目のリストを表示するコードを追加する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
</head>
<body>
<h1>ToDo項目</h1>

<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>

<c:if test="${list != null}">
  <form method="post" action="check">
    <c:forEach var="t" items="${list}">
      <input type="checkbox" name="item" value="${t.id}" />${t.item}<br />
    </c:forEach>
  </form>
</c:if>

</body>
</html>

8月25日

Webアプリ「Shindan」で診断した内容をデータベースに保存する機能を追加する。

まずはDAOを作成する。

ShindanDao.java

package jp.abc;

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

public interface ShindanDao<T> extends Serializable {
	public List<T> getAll();
	public void add(Shindan s);
}

ShindanDao の実装クラス ShindanDaoImpl を作成する。
今回は、クエリ部分を CriteriaAPI で実装する。

ShindanDaoImpl.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 ShindanDaoImpl implements ShindanDao<Shindan> {
	private static EntityManagerFactory factory =
			Persistence.createEntityManagerFactory("persistenceUnit");

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

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

}

コントローラに、DAOを通してDBにアクセスするコードを追加する。
入力チェックは、バリデーション機能を使わずに、独自で簡単に実装しておく。

package jp.abc;

import java.util.Date;
import java.util.List;

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

@Controller
public class ShindanController {

	@RequestMapping(value = "/input", method = RequestMethod.GET)
	public String shindan(Model model) {
		Shindan s = new Shindan();
		ShindanDao<Shindan> dao = new ShindanDaoImpl();
		List<Shindan> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "shindan";
	}

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String form(@RequestParam(value = "name") String name,
					   @RequestParam(value = "type") String type,
					   Model model) {
		if (name == null || type == null) {
			model.addAttribute("message", "入力が不足しています。");
			return "shindan";
		}
		model.addAttribute("name", name);
		model.addAttribute("type", type);
		String s = name + type;
		int h = Math.abs(s.hashCode());
		h = h % 101;
		model.addAttribute("percent", h);

		Shindan shindan = new Shindan();
		ShindanDao<Shindan> dao = new ShindanDaoImpl();
		shindan.setName(name);
		shindan.setType(type);
		shindan.setValue(h);
		shindan.setTime(new Date());
		dao.add(shindan);
		return "redirect:/input";
	}
}

JSPに、DBから取得した履歴データを表示するコードを追加する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>診断アプリ</title>
</head>
<body>

<c:if test="${message != null}">
<p style="color:red;">${message}</p>
</c:if>

<form method="post" action="input">
<input type="text" name="name">さんの<br>
<input type="text" name="type">度を診断します<br>
<input type="submit" value="診断">

</form>

<div style="margin: 10px 50px;font-size: 20pt;">
<c:if test="${name != null}">
${name} さんの ${type} 度は、${percent}%です。<br>
</c:if>
</div>

<hr>
<c:if test="${datalist != null}">
<table border="1">
<tr><th>名前</th><th>診断内容</th><th>値</th></tr>
<c:forEach var="s" items="${datalist}">
  <tr>
    <td>${s.name}</td>
    <td>${s.type}</td>
    <td>${s.value} %</td>
  </tr>
</c:forEach>
</table>
</c:if>

</body>
</html>

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

pom.xml の HSQLDB のバージョンも修正する。

		<dependency>
		    <groupId>org.hsqldb</groupId>
		    <artifactId>hsqldb</artifactId>
		    <version>2.3.4</version>
		</dependency>

データベースへの接続でエラーが発生する場合は、hsqldb.bat で パラメータを追加する。

hsqldb.bat

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

DB登録までできた人は、診断結果の値でソートする機能を追加してみること。

8月21日

復習としてSpringMVCを使ったWebアプリケーションを作成する。

ServletとJSPを使って作成した診断アプリを、SpringMVCを使って作成してみよう。

プロジェクト名: Shindan

5月29日の内容を参考にしてプロジェクトを作成する。

5月29日

6月2日の内容を参考にして mvc-config.xml を編集する。

6月2日

コントローラを作成する。
コントローラ: ShindanController.java

コントローラから shindan.jsp を表示させるコードを書く。

package jp.abc;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class ShindanController {

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

この状態で、http://localhost:8080/Shindan/input にアクセスすると404エラーが発生する。
エラーで WEB-INF/view/shindan.jsp が見つからないといわれるので、shindan.jsp を作成する。

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

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>診断アプリ</title>
</head>
<body>

<form method="post" action="ShindanServlet">
<input type="text" name="name">さんの<br>
<input type="text" name="type">度を診断します<br>
<input type="submit" value="診断">

</form>

</body>
</html>

コントローラにPOSTメソッドのリクエストを受け取るためのメソッドを追加する。

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

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

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String form(Model model) {
		return "shindan";
	}
}

フォームのあとに、「○○さんの○○度はXX%です。」と表示する部分を追加する。
nameにデータがあるときだけ表示するように、JSTLの c:if タグで条件を指定する。

<!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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>診断アプリ</title>
</head>
<body>

<form method="post" action="input">
<input type="text" name="name">さんの<br>
<input type="text" name="type">度を診断します<br>
<input type="submit" value="診断">

</form>

<c:if test="${name != null}">
${name} さんの ${type} 度は、${percent}%です。<br>
</c:if>

</body>
</html>

名前と診断内容を表示するために、リクエストパラメータから値を取得する。
そのために、POSTメソッドを受け取る form メソッドに、@RequestParam アノテーションを追加した引数を追加する。

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String form(@RequestParam(value = "name") String name,
					   @RequestParam(value = "type") String type,
					   Model model) {
		model.addAttribute("name", name);
		model.addAttribute("type", type);
		return "shindan";
	}

これで、名前と診断内容は表示できるようになる。

次に診断結果を表示できるようにする。
以前の ShindanServlet を参考にコードを追加する。

	@RequestMapping(value = "/input", method = RequestMethod.POST)
	public String form(@RequestParam(value = "name") String name,
					   @RequestParam(value = "type") String type,
					   Model model) {
		model.addAttribute("name", name);
		model.addAttribute("type", type);
		String s = name + type;
		int h = Math.abs(s.hashCode());
		h = h % 101;
		model.addAttribute("percent", h);
		return "shindan";
	}

これまでの診断結果をデータベースに保存するようにしてみよう!

そのためには、pom.xml にデータベース関連のライブラリを追加する必要があるので、
6月19日の内容を参照して pom.xml を変更する。

6月19日

さらに、database.properties ファイルと persistence.xml を追加する。
これも6月19日を参照すればOK。

また、6月19日の記録を参照し、application-config.xml ファイルも変更する。

ここまでやれば、データベースを利用する準備が完了。

デスクトップに作成した hsqldb.bat をダブルクリックして HSQLDB を起動する。

Shindan エンティティの作成

jp.abc パッケージを右クリックして、[新規]-[クラス]を選択する。
クラス名は「Shindan」とする。

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;

@Entity
public class Shindan {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	private long id;

	@Column
	private Date time;

	@Column
	private String name;

	@Column
	private String type;

	@Column
	private int value;

	public long getId() {
		return id;
	}

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

	public Date getTime() {
		return time;
	}

	public void setTime(Date time) {
		this.time = time;
	}

	public String getName() {
		return name;
	}

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

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}
}

次回予定

  • DAOインタフェースの作成
  • DAO実装クラスの作成
  • コントローラの修正
  • JSPの修正

以上を行えば、データベースにアクセスできるようになるはず。