【第十回】Spring Frameworkを使ってみる ~データベースにアクセスする④~
前回の第九回ではデータベースに接続し絞込みを行いログイン処理を実装しました。
今回は、テーブルの結合をしてデータを取得していきます。
Spring Framework連載記事 目次
【第一回】Spring Frameworkを使ってみる ~Spring Framework概要と準備~
【第二回】Spring Frameworkを使ってみる ~プロジェクト作成からビルドまで~
【第三回】Spring Frameworkを使ってみる ~サーバで実行~
【第四回】Spring Frameworkを使ってみる ~画面遷移~
【第五回】Spring Frameworkを使ってみる ~データ受け渡し~
【第六回】Spring Frameworkを使ってみる ~入力値チェック~
【第七回】Spring Frameworkを使ってみる ~データベースにアクセスする①~
【第八回】Spring Frameworkを使ってみる ~データベースにアクセスする②~
【第九回】Spring Frameworkを使ってみる ~データベースにアクセスする③~
【第十回】Spring Frameworkを使ってみる ~データベースにアクセスする④~
準備
テーブルの再作成
まずは、前回まで使用していたテーブルをいったん削除して下記のテーブル作成スクリプトを実行します。
CREATE TABLE department ( id INTEGER PRIMARY KEY, name VARCHAR(40) ); CREATE TABLE user ( id INTEGER PRIMARY KEY, name VARCHAR(40), department_id INTEGER, FOREIGN KEY (department_id) REFERENCES department (id) );
テーブルにデータ挿入
下記のスクリプトを実行し、テーブルにデータを挿入します。
INSERT INTO department (id,name) VALUES (1,'人事部'); INSERT INTO department (id,name) VALUES (2,'営業部'); INSERT INTO user (id,name,department_id) VALUES (1,'田中',1); INSERT INTO user (id,name,department_id) VALUES (2,'佐藤',1); INSERT INTO user (id,name,department_id) VALUES (3,'鈴木',2);
モデルの削除
JPAを使用してモデル作成
モデルの作成
前々回と同様にJPAを使用してモデルを作成していきます。
「model」パッケージを右クリック⇒「New」⇒「other…」を選択します。
「JPA」⇒「JPA Entities from Tables」を選択します。
Connectionを選択して、先ほど作成した「department」テーブルと「user」テーブルにチェックを入れます。
チェック後、「Finish」を選択します。
モデルの内容確認
作成方法は前々回と同様ですが、今回は、テーブルにプライマリキーと外部キーがしっかりと張られています。
そのことによりJPAからテーブルを作成したときに、すでに結合した結果が取得できるようになっています。
具体的には作成されたモデルの下記の部分を見てみましょう。
User.java
package jp.ssie.helloworld.model; import java.io.Serializable; import javax.persistence.*; /** * The persistent class for the user database table. * */ @Entity @NamedQuery(name="User.findAll", query="SELECT u FROM User u") public class User implements Serializable { private static final long serialVersionUID = 1L; @Id private int id; private String name; //bi-directional many-to-one association to Department @ManyToOne private Department department; public User() { } public int getId() { return this.id; } public void setId(int id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public Department getDepartment() { return this.department; } public void setDepartment(Department department) { this.department = department; } }
20行目、21行目に「@ManyToOne」アノテーションと「Department」クラスの変数が出来上がっています。
この記述があると「User」テーブルのデータを取得した際に、それに紐づく「Department」テーブルのデータを取得することができます。
つまり、テーブルの外部キーなどがしっかりと貼られていれば、SQLを記述することなくテーブルの結合した結果を取得することができます。
アノテーションの「@ManyToOne」は多対1という意味になります。
ここでは「ユーザ:多」に対し「部署:1」になります。
「Department.java」についても確認してみます。
Department.java
package jp.ssie.helloworld.model; import java.io.Serializable; import javax.persistence.*; import java.util.List; /** * The persistent class for the department database table. * */ @Entity @NamedQuery(name="Department.findAll", query="SELECT d FROM Department d") public class Department implements Serializable { private static final long serialVersionUID = 1L; @Id private int id; private String name; //bi-directional many-to-one association to User @OneToMany(mappedBy="department") private List<User> users; public Department() { } public int getId() { return this.id; } public void setId(int id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public List<User> getUsers() { return this.users; } public void setUsers(List<User> users) { this.users = users; } public User addUser(User user) { getUsers().add(user); user.setDepartment(this); return user; } public User removeUser(User user) { getUsers().remove(user); user.setDepartment(null); return user; } }
21行目、22行目で「User」テーブルと同様に、「@OneToMany」アノテーションと「User」クラスのリスト変数が出来上がっています。
Userと違い、「部署:1」に対し「ユーザ:多」になるので、それをあらわすアノテーションが付与されています。
また、「部署:1」に対し「ユーザ:多」なので、取得する「User」クラスはリストになっています。
出力内容の変更
ログイン後に前回出力した名前だけでなく、部署名を出力していきます。
LoginControllerの編集
ログイン時に取得する値に部署名を追加します。
JPAが結合を自動で行ってくれるので、取得した結果から「getDepartment」するだけで部署テーブルの内容を取得することができます。
LoginController.java
package jp.ssie.helloworld.web; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import jp.ssie.helloworld.form.LoginForm; import jp.ssie.helloworld.model.User; import jp.ssie.helloworld.repository.UserRepository; import jp.ssie.helloworld.validation.GroupOrder; @Controller public class LoginController { @Autowired private UserRepository userRep; @RequestMapping(value = "/", method = RequestMethod.GET) public String index(Model model) { return "index"; } @RequestMapping(value = "/login", method = RequestMethod.POST) public String login(Model model, @Validated(GroupOrder.class) @ModelAttribute("loginForm") LoginForm loginForm, BindingResult result) { if(result.hasErrors()) { return "index"; } List<User> userList = userRep.findById(loginForm.getUserId()); if(userList.size() > 0) { model.addAttribute("userName", userList.get(0).getName()); model.addAttribute("departmentName", userList.get(0).getDepartment().getName()); return "top"; } else { return "index"; } } }
39行目でとくに難しいことはせずに、EntityのGetterメソッドのみで部署名を取得していきます。
top.jspの編集
設定した部署名を画面に出力します。
top.jspを下記のように変更します。
top.jsp
<!DOCTYPE html> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <html> <head> <meta charset="utf-8"> <title>トップ</title> </head> <body> ようこそ<c:out value="${departmentName}" />の<c:out value="${userName}" />さん </body> </html>
実行結果
実行
非常に簡単にテーブルの結合を実現することができました。
次回について
今回はデータベースのテーブルを結合して値を取得しました。簡単なものであればこれで十分と思われるので、次回からは画面の出力について調査していきます。