TOP →
Java →
spring → This Page
3.3.2.(JpaRepository)(N:1テーブルのCRUD+自由なクエリ) Spring+MVC+DB+Test構築サンプル
前提
このページに記載している内容は 2018/09/30 に書かれたものです。
掲載している画面や方法が将来的に変更されている場合があります。
また、掲載しているインストール方法は Windows 8.1 の場合です。
開発環境は
・Windows 8.1
・JDK 8
・STS(Spring Tool Suite) 3.9.5
・PostgreSQL 9.5.14
とします。
目次
1.Entityクラスの作成
2.Repositoryインタフェースの作成
3.Daoインタフェースの作成
4.Daoクラスの作成
5.Serviceインタフェースの作成
6.Serviceクラスの作成
7.TestController.java編集
8.index.jsp編集
9.確認実行
1.Entityクラスの作成
今回は「N:1テーブルのCRUD」ということで、
準備編で用意したテーブル「staff」テーブルを使うことにします。
「staff」テーブルは「department」テーブルと外部結合でつながっています。
「staff」テーブルからみると「department」テーブルとの関係は「N:1」です。
(複数のスタッフが同じ1つの部門に属している状態)
1テーブルにつき対応した1Entityクラスを作成します。
プロジェクト名を右クリックして「New」>「Class」を選択します。
「New Java Class」ダイアログが表示されます。
・「Package」は「jp.mitchy.entity」と入力
・「Name」は「Staff」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
作成された「Staff.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="staff")
public class Staff {
@Id
@Column
private Long id;
@Column(length=50,nullable=false)
private String name;
@Column(nullable=false)
private int age;
@ManyToOne
@JoinColumn(name="deptid", referencedColumnName="id")
private Department department;
public Staff() {
department = new Department();
}
public Staff(Long id, String name, int age, Long deptId) {
this();
this.id = id;
this.name = name;
this.age = age;
this.department.setId(deptId);
}
public Staff(Long id, String name, int age, Department department) {
this();
this.id = id;
this.name = name;
this.age = age;
this.department = department;
}
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Department getDepartment() {
return department;
}
@Override
public String toString() {
return "[id=" + id + ",name=" + name + ",age=" + age
+ ",dept:id=" + department.getId() + ",dept:name=" + department.getName() + "]";
}
}
前章と同じ箇所は説明を割愛します。
テーブルのカラムに合わせて id, name, age をメンバフィールドに持ちます。
カラムにある deptid のかわりに department をメンバフィールドに持ちます。
Department クラスのフィールドに @ManyToOne アノテーションをつけています。
これで Staff:Department が N:1 ということを設定できます。
@JoinColumn(name="deptid", referencedColumnName="id") アノテーションは
Staff テーブルと Department テーブルとの結合条件を示します。
(列名が同じ場合は省略可能)
Staff テーブルの deptid と Department テーブルの id で結合します。
後述しますがこれで Staff と Department のレコードを一度に取得することもできます。
そのため、toString() メソッドを見ると分かると思いますが、
レコード検索後は department.getId(), department.getName() で
Department テーブルの情報も取ることができます。
2.Repositoryインタフェースの作成
次にリポジトリをインタフェースとして作成します。
同じく1テーブルにつき対応した1リポジトリ・インタフェースを作成します。
プロジェクト名を右クリックして「New」>「Interface」を選択します。
「New Java Interface」ダイアログが表示されます。
・「Package」は「jp.mitchy.repository」と入力
・「Name」は「StaffRepository」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
作成された「StaffRepository.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import jp.mitchy.entity.Staff;
@Repository
public interface StaffRepository extends JpaRepository<Staff, Long> {
public Staff findById(Long id);
// s.deptid = 2 とするとエラーになるので注意
@Query("select s from Staff s where s.department.id = 2")
List<Staff> findSales();
@Query("select s from Staff s where s.age >= :min and age <= :max")
List<Staff> findRangeAges(@Param("min") int min, @Param("max") int max);
}
前章と同じ箇所は説明を割愛します。
findSales メソッドと findRangeAges メソッドに @Query アノテーションをつけています。
アノテーションの中に JPQL を記載することで、この JPQL を元に SQL を発行するメソッドになります。
パラメータを使いたい場合はメソッドの引数に @Param アノテーションをつけます。
これだけで全章と同様に実装なしで動作します。
3.Daoインタフェースの作成
同じく1テーブルにつき対応した1DAOインタフェースを作成します。
プロジェクト名を右クリックして「New」>「Interface」を選択します。
「New Java Interface」ダイアログが表示されます。
・「Package」は「jp.mitchy.dao」と入力
・「Name」は「StaffDao」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
作成された「StaffDao.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.dao;
import java.util.List;
import jp.mitchy.entity.Staff;
public interface StaffDao {
public List<Staff> getAllEntity();
public Staff findById(Long id);
public void addEntity(Staff entity);
public void updateEntity(Staff entity);
public void removeEntity(Staff data);
public void removeEntity(Long id);
}
メソッド名を見てなんとなく何をするメソッドか想像はつくと思いますが、
上からそれぞれ
・全レコード取得
・1レコード取得
・レコード追加
・レコード更新
・レコード削除(引数がエンティティ)
・レコード削除(引数がID)
です
4.Daoクラスの作成
先ほど作成したインタフェースを実装したクラスを作成します。
同じく1テーブルにつき対応した1DAOクラスを作成します。
プロジェクト名を右クリックして「New」>「Class」を選択します。
「New Java Class」ダイアログが表示されます。
・「Package」は「jp.mitchy.dao.impl」と入力
・「Name」は「StaffDaoImpl」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
作成された「StaffDaoImpl.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.dao.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
// import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import jp.mitchy.dao.StaffDao;
import jp.mitchy.entity.Staff;
import jp.mitchy.repository.StaffRepository;
@Repository
public class StaffDaoImpl implements StaffDao {
@Autowired
private StaffRepository repository;
public StaffDaoImpl() {
init();
}
public void init(){
// @Autowired がうまく機能しない場合は以下のコメントを外す
// SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public List<Staff> getAllEntity() {
System.out.println("getAllEntity()");
return repository.findAll();
}
public Staff findById(Long id) {
System.out.println("findById(id)");
return repository.findById(id);
}
public void addEntity(Staff entity) {
System.out.println("addEntity(entity)");
repository.saveAndFlush(entity);
}
public void updateEntity(Staff entity) {
System.out.println("updateEntity(entity)");
repository.saveAndFlush(entity);
}
public void removeEntity(Staff entity) {
System.out.println("removeEntity(entity)");
repository.delete(entity);
}
public void removeEntity(Long id) {
System.out.println("removeEntity(id)");
Staff entity = repository.findOne(id);
repository.delete(entity);
}
public List<Staff> getSalesEntity() {
System.out.println("getSalesEntity()");
return repository.findSales();
}
public List<Staff> getRangeAgesEntity(int min, int max) {
System.out.println("getRangeAgesEntity(min, max)");
return repository.findRangeAges(min, max);
}
}
前章からとクラスやメソッドが変わっただけなので説明を割愛します。
5.Serviceインタフェースの作成
次にサービス層のインタフェース・クラスを作ります。
今回もまずはインタフェースを作成します。
プロジェクト名を右クリックして「New」>「Interface」を選択します。
「New Java Interface」ダイアログが表示されます。
・「Package」は「jp.mitchy.service」と入力
・「Name」は「StaffService」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
作成された「StaffService.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.service;
import jp.mitchy.dto.TestResultDto;
import jp.mitchy.entity.Staff;
public interface StaffService {
public TestResultDto<Staff> execute(Staff entity);
}
エンティティを引数とし、TestResultDto を返す execute メソッドのみのシンプルなインタフェースです
6.Serviceクラスの作成
先ほど作成したインタフェースを実装したクラスを作成します。
プロジェクト名を右クリックして「New」>「Class」を選択します。
「New Java Class」ダイアログが表示されます。
・「Package」は「jp.mitchy.service.impl」と入力
・「Name」は「StaffServiceImpl」と入力
・それ以外の項目はそのまま
「Finish」ボタンを押します。
作成された「StaffServiceImpl.java」が開くので、内容を以下のように書き換えて保存しましょう。
package jp.mitchy.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jp.mitchy.dao.StaffDao;
import jp.mitchy.dto.TestResultDto;
import jp.mitchy.entity.Staff;
import jp.mitchy.service.StaffService;
@Service
public class StaffServiceImpl implements StaffService {
@Autowired
private StaffDao dao;
public StaffServiceImpl() {
init();
}
public void init(){
// @Autowired がうまく機能しない場合は以下のコメントを外す
// SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public TestResultDto<Staff> execute(Staff entity) {
TestResultDto<Staff> result = new TestResultDto<Staff>();
// INSERT
dao.addEntity(entity);
// UPDATE
entity.setName("退職太郎3");
dao.updateEntity(entity);
// DELETE
dao.removeEntity(entity.getId());
// SELECT 単体
Staff entity2 = dao.findById(102L);
result.setEntity(entity2);
// SELECT 複数
List<Staff> list = dao.getAllEntity();
result.setList(list);
return result;
}
}
こちらも基本的に前の章で作成した「DepartmentServiceImpl」とほぼ同じなので
説明は割愛します。
7.TestController.java編集
jp.mitchy.controller にある TestController.java を変更し、
今回作成したサービスを呼び出して実行するようにします。
内容を以下のように書き換えて保存しましょう。
赤文字が前回から追加になる箇所です。
package jp.mitchy.controller;
import org.springframework.beans.factory.annotation.Autowired;
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 jp.mitchy.dto.TestResultDto;
import jp.mitchy.entity.Department;
import jp.mitchy.entity.Staff;
import jp.mitchy.service.DepartmentService;
import jp.mitchy.service.StaffService;
@RequestMapping("/test/*")
@Controller
public class TestController {
@Autowired
private DepartmentService deptService;
@Autowired
private StaffService staffService;
@RequestMapping(value = "/dept", method = RequestMethod.GET)
public String dept(Model model) {
// ------------------------------
// 単テーブルのCURD確認
// ------------------------------
Department entity = new Department(4L, "新事業部");
// サービスの実行
TestResultDto<Department> dto = deptService.execute(entity);
// 結果をセット
model.addAttribute("data", dto.getEntity());
model.addAttribute("list", dto.getList());
// view/test/result.jsp を表示
return "test/result";
}
@RequestMapping(value = "/staff", method = RequestMethod.GET)
public String staff(Model model) {
// ------------------------------
// N:1 テーブルのCURD確認
// ------------------------------
Staff entity = new Staff(103L, "人事太郎3", 50, 1L);
// サービスの実行
TestResultDto<Staff> dto = staffService.execute(entity);
// 結果をセット
model.addAttribute("data", dto.getEntity());
model.addAttribute("list", dto.getList());
// view/test/result.jsp を表示
return "test/result";
}
}
こちらも基本的に前の章で作成したメソッドとほぼ同じなので
説明は割愛します。
8.index.jsp編集
最後に、作成した処理を呼び出せるように index.jsp を編集します。
src/main/webapp/index.jsp を開き、内容を以下のように書き換えて保存しましょう。
赤文字が前回から追加になる箇所です。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Welcome</title>
</head>
<body>
<c:url value="/test/dept" var="messageUrl1" />
<a href="${messageUrl1}">Department Test</a><br/>
<c:url value="/test/staff" var="messageUrl2" />
<a href="${messageUrl2}">Staff Test</a><br/>
</body>
</html>
9.確認実行
念のためにいつもの「Maven Clean」「Maven Install」をやっておきましょう。
エラーが出たら「Project」>「Clean」をやってから
再度「Maven Install」です。
プロジェクト名を右クリックして「Run As」>「Run On Server」を選択します。
少し時間がかかりますが「Console」に状況が表示されていきます。
しばらくすると内蔵ブラウザが立ち上がり、「Staff Test」と表示されます。
「Staff Test」のリンクをクリックしてみましょう。
リンク先 /test/staff に連動する TestController クラスの staff メソッドが呼び出され、
/WEB-INF/view/test/result.jsp が表示されることが確認できます。
テーブル操作も正常に実行されていますね。
(Consoleの出力内容も確認してみましょう)
以上で JpaRepository を使ったN:1テーブルのCRUD+自由なクエリの
サンプル構築は完了です。
ダウンロード
更新履歴
2018/09/30 新規作成
TOP →
Java →
spring → This Page