パラメータをURLに含める
たとえばidをURLに含める場合のJSP記述方法。
<a href="hoge?id=${obj.id}">${obj.title}</a>
Webアプリの講義内容と関連資料など
たとえばidをURLに含める場合のJSP記述方法。
<a href="hoge?id=${obj.id}">${obj.title}</a>
共有データベースを配置するパソコンを決める。
そのパソコンで、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
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が追加された状態で取り出せる。
ログインしたユーザー情報を取得するには、コントローラの引数に 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">
ユーザーとユーザの権限を管理するためのテーブルを作成する。
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>
課題は誰でも作れる。
課題を作るときに、担当者を割り当てる。
リーダーは課題「ロバストネス図を作成する」を追加する。
他のメンバーは課題「クローンする」を作成する。
Criteria API は3つのクラスを組み合わせて利用する。
テキストでは 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 自動生成されたメソッド・スタブ } }
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"; }
エンティティを削除するには、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)); }
別のアプリDatabaseManagerを使用することで、SQLを実行できる。
> cd C:\Users\se3\db\hsqldb-2.3.2\hsqldb > java -cp lib/hsqldb.jar org.hsqldb.util.DatabaseManager
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>
MyDataアプリケーションで検索機能を追加する。
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"; }
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; }
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
エンティティの削除の実装
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
5章のために、新規プロジェクトを作成する。
プロジェクト名: MyData
いつもの手順でプロジェクトを生成し、http://localhost:8080/MyData/ にアクセスする。
click to enter が表示されればOK。
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} に変更する。
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=
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>
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
<context:component-scan base-package="jp.abc"/>
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; } }
インタフェースを作成する。
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(); } }
入力フォームで生年月日を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; }