51日目(Spring Framework9)
Hibernate ORM
データベースとのやり取り
ORM…Object Relational Mapping
データベースの情報とJavaのdomainクラスの情報を対応させる
オブジェクトを操作する感覚で、メソッドによってデータを取ってきたりできる
ただ細かいところに手が届かないため、細かい操作に対応したHQL (Hibernate Query Language)という言語も用意されている
データベースとオブジェクトの対応関係の指定の方法
※マッピングファイル…domainクラスとテーブルを紐づけることを示すxmlファイル
※授業ではバリデーションをアノテーションで行うため、マッピングファイルでの指定を採用
HibernateORM単品で利用もできるが、その場合手順がけっこう多くなる
Springと連携させることで簡略化
準備
①ライブラリ追加
- hibernate-core
- spring-orm
②Bean定義ファイル
名前空間にjee、txを追加(名前空間タブでjeeとtxにチェックを入れる)
データソース指定とHibernateORMの設定を記述
以下はBean定義ファイルに記述
・データソース指定
<property name="dataSource" ref="dataSource" />
・マッピングファイルの指定
<property name="mappingResources">
<list>
<value>hbm/Member.hbm.xml</value>
</list>
</property>
・利用するデータベースの方式の指定
<property name="hibernateProperties">
<props>
★<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>出力用
<prop key="hibernate.format_sql">true</prop>改行用
</props>
</property>
★MySQLを利用する場合この記述は必須
・Transaction Manager
<bean id="txManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
-------------------------
↑ここまでがBean定義ファイルの記述。長い(汗)
③マッピングファイル
<property name="mappingResources">の部分の、valueタグで指定したものに合わせた場所に作成
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="domain">
<class name="Member" table="members">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="name" column="name" type="string" />
<property name="age" column="age" type="integer" />
<property name="typeId" column="type_id" type="integer" />
<property name="created" column="created" type="date" />
</class>
</hibernate-mapping>
classタグ
name属性(というかname属性全部)=domainクラス
tableがデータベースのテーブル名と対応。
PRIMARY KEYで設定されてるidは特殊な書き方。class="native"で指定。
(nativeにするとDB固有のid生成をしてくれる。AUTO_INCREMENTが有効)
propertyタグ
name属性はdomainクラスのフィールド名
column属性はテーブルのカラム名
type属性はデータ型
ここまでが下準備。
DBのmembersテーブル全体のデータを取得
・DAOを用意する
クラス宣言の前にアノテーション
MemberDao.java(実装例)
@Transactional
@Repository
public class MemberDao {
// フィールドでDI
@Autowired
private SessionFactory sessionFactory;
private Session getSession() {
return sessionFactory.getCurrentSession();
}
// 全員のデータを取得
public List<Member> findAll(){
// HQLの記述 select * from membersに相当
// ⇒ from Member(SQLを省略したような形、またdomainクラス)
return getSession().createQuery("from Member", Member.class)
.getResultList();
}
}
・Controllerクラスの作成
MemberController.java
クラス宣言前に@Controller
以下中身
@Autowired
private MemberDao dao;
@RequestMapping("/listMember")
public String list(Model model) {
List<Member> members = dao.findAll();
model.addAttribute("members", members);
return "listMember";
}
・ビューの作成
listMember.jsp
tableで会員情報一覧を表示する
<c:out value="${member.name}" />
などで氏名等を出力
●個別にデータ取得
URIテンプレート変数でidごとに区切る
(id=3なら/member/3みたいな)
・先に作ったlistMember.jspの会員情報一覧のtableに個別表示の枠を追加、IDごとのリンクを作成
<td>
<a href="member/<c:out value="${member.id}" />">
<c:out value="${member.id}" />
</a>
</td>
・MemberController.javaにメソッド追加
@GetMapping("/member/{id}")
public String member(
@PathVariable("id") Integer id,
Model model) {
// idから1人分の情報を取得
※Member member = dao.findById(id);
// 取得した情報をjspで表示
※model.addAttribute(member);
return "member";
}
※ここの実装前に下記のDAOを書いてしまう
・MemberDao.java
// 1人分のデータを取得
public Member findById(Integer id) {
// select * from members where id=Xに相当
return getSession().get(Member.class, id);
}
・個別のビュー
member.jsp
これは普通にmemberのフィールドをcoutで出力するだけ
<h1>個別表示</h1>
<p>氏名:<c:out value="${member.name}" /></p>
<p>年齢:<c:out value="${member.age}" /></p>
●データの追加
.save()メソッドを使う
※SQL文を書くことなくデータの追加ができる!
・まずは入力フォーム
form:selectでは今回はデータベースから種別を取ってくるのではなくform:optionで用意。
<form:form modelAttribute="member">
<p>氏名:
<form:input path="name"/></p>
<p>年齢:
<form:input path="age"/></p>
<p>住所:
<form:input path="address"/></p>
<p>会員種別:
<form:select path="typeId">
<form:option value="1">通常会員</form:option>>
<form:option value="2">プレミアム会員</form:option>>
</form:select>
</p>
<input type="submit" value="追加"/>
</form:form>
・Controllerクラス
MemberController.java
@GetMapping("/addMember")
public String addMember(Model model) {
model.addAttribute("member", new Member());
return "addMember";
}
@PostMapping("/addMember")
public String addMemberPost(
@Valid Member member,
Errors errors) {
if(errors.hasErrors()) {
return "addMember";
} else {
dao.insert(member);※MemberDaoにinsert()メソッド記述後に追加
return "redirect:/listMember";
}
}
※簡単にバリデーションを実装
Member.javaのフィールドにアノテーションを追加
pom.xmlにhibernate.Validatorを追加
・データを追加するメソッドをDAOに記述
MemberDao.java
public void insert(Member member) {
member.setCreated(new Date());
getSession().save(member);
}
編集 update
削除 update
個別表示ページに更新ボタンと削除ボタンを追加
<input type="submit" name="btn" value="更新"/>
<input type="submit" name="btn" value="削除"/>
●MemberDao
// 会員情報を削除するメソッド
public void deleteById(Integer id) {
Member member = findById(id);
getSession().delete(member);
}
// 会員情報を更新するメソッド
public void updateById(Member newInfo, Integer id) {
// 更新したいIDのデータを取得
Member member = findById(id);
member.setName(newInfo.getName());
member.setAge(newInfo.getAge());
member.setAddress(newInfo.getAddress());
member.setTypeId(newInfo.getTypeId());
getSession().save(member);
}
●MemberController.java
MemberDaoで定義した更新、削除のメソッドを利用する
@PostMapping("/member/{id}")
public String memberPost(
@PathVariable("id") Integer id,
@Valid Member member,
Errors errors,
@RequestParam String btn) {
if(btn.equals("更新")) {
if(errors.hasErrors()) {
return "member";
} else {
// 更新処理
dao.updateById(member, id);
return "redirect:/listMember";
}
} else {
// 削除処理
dao.deleteById(id);
return "redirect:/listMember";
}
}
※@GetMappingは記述済
今日はここまで
CRUDがわりと簡略化されて嬉しい
ただ、処理の流れを追いきれてない感じがあるので要復習