Try   HackMD

六角鼠年鐵人賽 Week 26 - Spring Boot - Spring Data & JPA 範例

大家好,我是 "為了拿到金角獎盃而努力著" 的文毅青年 - Kai

Bill Gates

If you can't make it good, at least make it look good.

主題

上週已經提完了關於 JPA、ORM、Spring Data & JPA 的部分。

這週就來做一個簡單的實作範例。

如何透過 Entity、Repository 的方式掌控著以往使用 DAO 處理 DB 的方式。

範例

延續前幾週的範例方式,Kai 全部都實作在同一個專案中,有興趣的人可以私信我分享。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'
}

在 dependencies 加入 spring data jpa 的套件,並還有使用 H2 DB 作為範例DB使用。

有興趣的人可以研究一下 H2 DB,他是一個非常輕量版,幾乎只需要使用套件即可運行,不需要任何安裝動作的 DB

Entity

Kai 建立一個屬於員工的 Entity 作為示範範例

package kai.com.jpa.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import java.sql.Date; @Entity public class Employee { public Employee (){} public Employee(String name, String team, Date birthDate){ this.emp_name = name; this.emp_team = team; this.emp_birthDate = birthDate; } @Id @GeneratedValue(strategy= GenerationType.AUTO) private Long emp_id; private String emp_name; private String emp_team; private Date emp_birthDate; public Long getEmp_id() { return emp_id; } public void setEmp_id(Long emp_id) { this.emp_id = emp_id; } public String getEmp_name() { return emp_name; } public void setEmp_name(String emp_name) { this.emp_name = emp_name; } public String getEmp_team() { return emp_team; } public void setEmp_team(String emp_team) { this.emp_team = emp_team; } public Date getEmp_birthDate() { return emp_birthDate; } public void setEmp_birthDate(Date emp_birthdate) { this.emp_birthDate = emp_birthdate; } }

Repository

package kai.com.jpa.repository; import kai.com.jpa.entity.Employee; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import java.util.List; import java.util.Optional; public interface EmployeeRepository extends CrudRepository<Employee, Long> { List<Employee> findAll(); Optional<Employee> findById(Long id); void deleteById(Long id); @Query(value="SELECT * FROM EMPLOYEE as e WHERE e.EMP_ID BETWEEN ?1 AND ?2 " ,nativeQuery = true) List<Employee> findByPriorityBetween(Long number1, Long number2); }

Controller

因為需要一些資料當作測試用,因此有多寫一支 API 專門用來建立資料這樣,其實也可以透過 Class build 起來時就直接建立好。

不過為了當作範例,就想說必須要有明確地做點什麼。

package kai.com.jpa.controller; import kai.com.jpa.entity.Employee; import kai.com.jpa.repository.EmployeeRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.sql.Date; import java.util.List; import java.util.Optional; @RestController @RequestMapping("/getEmp") public class JPATestController { @Autowired EmployeeRepository employeeRepository; @GetMapping("/build") public String buildTableAndData(){ /*** 建立測試資料 ***/ Employee emp = new Employee(); emp.setEmp_name("Michael"); emp.setEmp_team("IT"); emp.setEmp_birthDate(new Date(19920101)); employeeRepository.save(emp); emp = new Employee(); emp.setEmp_name("Cherry"); emp.setEmp_team("Salse"); emp.setEmp_birthDate(new Date(19900101)); employeeRepository.save(emp); emp = new Employee(); emp.setEmp_name("Stanley"); emp.setEmp_team("Product"); emp.setEmp_birthDate(new Date(19960101)); employeeRepository.save(emp); return "Done build."; } @GetMapping() public List<Employee> getAll(){ return employeeRepository.findAll(); } @GetMapping("/{number1}/{number2}") public List<Employee> getByRange(@PathVariable("number1") Long number1, @PathVariable("number2") Long number2){ return employeeRepository.findByPriorityBetween(number1,number2); } @GetMapping("/{id}") public Optional<Employee> getById(@PathVariable("id") Long Id){ return employeeRepository.findById(Id); } @DeleteMapping("/{id}") public String deleteById(@PathVariable("id") Long Id){ employeeRepository.deleteById(Id); if(!employeeRepository.findById(Id).isPresent()) return "Delete Successfully."; return "Delete failed."; } }

測試

  1. 建立測試用的資料

  2. 搜尋全部人的資料

  3. 搜尋 ID 為 1 的單筆資料

  4. 搜尋 ID 為 1 到 2 的範圍資料

  5. 刪除 ID 為 1 的單筆資料

再查詢全部後會發現少了 ID 為 1 的資料
另外提一點是,這邊 Kai 的設計方法做的差了,實際應用上的取資料路徑盡量避免與處理 update 和 delete 的路徑一樣

結語

這篇算是簡單的給出了一個應用上的範例,我們可以看到透過 Repository 的方式,少寫了非常多的 DAO class,以及不會因為少了 DAO 就無法進行客製化的動作,Repository 的 QUERY 提供了 JPQL 超級多的作法以滿足開發者的需求!

詳細的可以參閱 Kai 找到的一篇整理非常詳細的 @Query 應用文章
Spring Data JPA Custom Queries using @Query Annotation

希望這兩篇關於 JPA 的文章可以帶給尚未嘗試使用 JPA 的朋友們一點了解~

下一篇來介紹 @Query 比較細節的部分
六角鼠年鐵人賽 Week 27 - Spring Boot - Spring Data & JPA @Query Annotation

首頁 Kai 個人技術 Hackmd

tags: Spring Boot,Spring Data,w3HexSchool