職業訓練覚え書き

51日目(Spring Framework9)

Hibernate ORM

データベースとのやり取り
ORM…Object Relational Mapping
データベースの情報とJavaのdomainクラスの情報を対応させる

 

オブジェクトを操作する感覚で、メソッドによってデータを取ってきたりできる
ただ細かいところに手が届かないため、細かい操作に対応したHQL (Hibernate Query Language)という言語も用意されている

 

データベースとオブジェクトの対応関係の指定の方法

マッピングファイル…domainクラスとテーブルを紐づけることを示すxmlファイル

※授業ではバリデーションをアノテーションで行うため、マッピングファイルでの指定を採用

HibernateORM単品で利用もできるが、その場合手順がけっこう多くなる
Springと連携させることで簡略化

 

準備


①ライブラリ追加

②Bean定義ファイル
 名前空間jeetxを追加(名前空間タブで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.xmlhibernate.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がわりと簡略化されて嬉しい
ただ、処理の流れを追いきれてない感じがあるので要復習