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の修正

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