Le Tutoriel de Spring Boot et Spring Data JPA
View more Tutorials:


Sur Eclipse, créez un projet Spring Boot.

Sélectionnez les technologies utilisées dans ce projet, y compris JPA et une base de données que vous connaissez bien.


Ajoutez l'extrait de configuration ci-dessous au fichier pom.xml si vous voulez travailler avec la base de données Oracle :
** Oracle **
<dependencies>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc7</artifactId>
<version>12.1.0.2</version>
</dependency>
</dependencies>
<repositories>
<!-- Repository for ORACLE ojdbc6. -->
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
</repositories>
Le contenu complet du fichier pom.xml :
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>SpringBootDataJPA</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SpringBootDataJPA</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc7</artifactId>
<version>12.1.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<!-- Repository for ORACLE ojdbc6. -->
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
SpringBootDataJpaApplication.java
package org.o7planning.sbdatajpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootDataJpaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDataJpaApplication.class, args);
}
}
Afin que Spring Boot puisse se connecter à la base de données, vous devez le configurer dans le fichier applications.properties. Vous pouvez utiliser n'importe quelle base de données que vous bien connaissez, ci-dessous sont 4 configurations correspondants au 4 catégories de base de données les plus populaires (MySQL, Oracle, SQL Server, PostGres).
En pratique, créez un schéma vide baptisé "mydatabase", JPA créera des tableaux correspondants aux Entity existant dans l'application.
application.properties (MySQL)
# ===============================
# DATABASE
# ===============================
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=root
spring.datasource.password=12345
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
application.properties (Oracle)
# ===============================
# DATABASE
# ===============================
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:db12c
spring.datasource.username=mydatabase
spring.datasource.password=12345
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
application.properties (SQL Server)
# ===============================
# DATABASE
# ===============================
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.url=jdbc:sqlserver://localhost\\SQLEXPRESS:1433;databaseName=mydatabase
spring.datasource.username=sa
spring.datasource.password=12345
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
application.properties (PostGres)
# ===============================
# DATABASE CONNECTION
# ===============================
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/mydatabase
spring.datasource.username=postgres
spring.datasource.password=12345
# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
# Fix Postgres JPA Error:
# Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented.
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
Dans JPA, chaque classe Entity correspondra à un table dans la base de données. Il y a plusieurs tables dans la base de données, donc il y aura beaucoup de classe Entity. Vous devez travailler souvent avec Entity, et écrire des classes DAO (Data Access Object) afin de manipuler les données via ces Entity. C'est un travail très ennuyeux.

OK, je vous expliquerai son ennuie. Imaginez que vous avez deux tables dans la base de données telles que EMPLOYEE & DEPARTMENT, et deux classes Entity correspondantes au Employee & Department.
Afin de manipuler avec Employee vous écrivez une classe DAO comprenant des méthodes similaires comme ci-dessous :
- Employee findById(Long id)
- List<Employee> findAll()
- List<Employee> findByName(String likeName)
- .....
Effectivement, pour manipuler dans Department vous devez de même choses, et au cas où le nombre de Entity est beaucoup, il vous prend énormément de temps.

Spring Data JPA est une bibliothèque de Spring. En accord avec Spring Data JPA vous devez simplement définir une interface étendue de l'interface Repository<T,ID>, et déclarer des méthodes pour manipuler des données de cette Entity. Ce Spring Data JPA créer une classe qui implémente (implements) cette interface pour vous.

Employee.java
package org.o7planning.sbdatajpa.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@Id
private Long id;
@Column(name = "Emp_No", length = 30, nullable = false)
private String empNo;
@Column(name = "Full_Name", length = 128, nullable = false)
private String fullName;
@Temporal(TemporalType.DATE)
@Column(name = "Hire_Date", nullable = false)
private Date hireDate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmpNo() {
return empNo;
}
public void setEmpNo(String empNo) {
this.empNo = empNo;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public Date getHireDate() {
return hireDate;
}
public void setHireDate(Date hireDate) {
this.hireDate = hireDate;
}
@Override
public String toString() {
return this.getEmpNo() + ", " + this.getFullName();
}
}
L'interface EmployeeRepository étend (extends) cette interface CrudRepository<Employee, Long>. Il possède des méthodes pour manipuler avec les entités Employee. Le Spring Data JPA créer automatiquement une classe qui implémente (implements) cette interface en même temps de l'exécution de l'application.
EmployeeRepository.java
package org.o7planning.sbdatajpa.repository;
import java.util.Date;
import java.util.List;
import org.o7planning.sbdatajpa.entity.Employee;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
// This is an Interface.
// No need Annotation here.
public interface EmployeeRepository extends CrudRepository<Employee, Long> { // Long: Type of Employee ID.
Employee findByEmpNo(String empNo);
List<Employee> findByFullNameLike(String fullName);
List<Employee> findByHireDateGreaterThan(Date hireDate);
@Query("SELECT coalesce(max(e.id), 0) FROM Employee e")
Long getMaxId();
}
Le Spring Data JPA écrira le code pour vos méthodes abstraites, donc vous devez informer au Spring Data JPA que vous voulez traverser le nom de méthode.
Keyword | Sample | Equivalent to |
---|---|---|
GreaterThan | findByAgeGreaterThan(int age) | Select e from Person e where e.age > :age |
LessThan | findByAgeLessThan(int age) | Select e from Person e where e.age < :age |
Between | findByAgeBetween(int from, int to) | Select e from Person e where e.age between :from and :to |
IsNotNull, NotNull | findByFirstnameNotNull() | Select e from Person e where e.firstname is not null |
IsNull, Null | findByFirstnameNull() | Select e from Person e where e.firstname is null |
Like | findByFirstnameLike(String name) | Select e from Person e where e.firstname like :name |
(No keyword) | findByFirstname(String name) | Select e from Person e where e.firstname = :name |
Not | findByFirstnameNot(String name) | Select e from Person e where e.firstname <> :name |
..... |
Vous pouvez également créer des interfaces avec des méthodes personnalisées. Dans ce cas, vous devez écrire la classe pour implémenter (implements) une telle interface.
EmployeeRepositoryCustom.java
package org.o7planning.sbdatajpa.repository;
import java.util.Date;
public interface EmployeeRepositoryCustom {
public Long getMaxEmpId();
public long updateEmployee(Long empId, String fullName, Date hireDate);
}
EmployeeRepositoryCustomImpl.java
package org.o7planning.sbdatajpa.repository;
import java.util.Date;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import org.o7planning.sbdatajpa.entity.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class EmployeeRepositoryCustomImpl implements EmployeeRepositoryCustom {
@Autowired
EntityManager entityManager;
@Override
public Long getMaxEmpId() {
try {
String sql = "SELECT coalesce(max(e.id), 0) FROM Employee e";
Query query = entityManager.createQuery(sql);
return (Long) query.getSingleResult();
} catch (NoResultException e) {
return 0L;
}
}
@Override
public long updateEmployee(Long empId, String fullName, Date hireDate) {
Employee e = entityManager.find(Employee.class, empId);
if (e == null) {
return 0;
}
e.setFullName(fullName);
e.setHireDate(hireDate);
entityManager.flush();
return 1;
}
}
MainController.java
package org.o7planning.sbdatajpa.controller;
import java.util.Date;
import java.util.List;
import java.util.Random;
import org.o7planning.sbdatajpa.entity.Employee;
import org.o7planning.sbdatajpa.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MainController {
@Autowired
private EmployeeRepository employeeRepository;
private static final String[] NAMES = new String[] { "Tom", "Jerry", "Donald" };
@ResponseBody
@RequestMapping("/")
public String home() {
String html = "";
html += "<ul>";
html += " <li><a href='/testInsert'>Test Insert</a></li>";
html += " <li><a href='/showAllEmployee'>Show All Employee</a></li>";
html += " <li><a href='/showFullNameLikeTom'>Show All 'Tom'</a></li>";
html += " <li><a href='/deleteAllEmployee'>Delete All Employee</a></li>";
html += "</ul>";
return html;
}
@ResponseBody
@RequestMapping("/testInsert")
public String testInsert() {
Long empIdMax = this.employeeRepository.getMaxId();
Employee employee = new Employee();
int random = new Random().nextInt(3);
long id = empIdMax + 1;
String fullName = NAMES[random] + " " + id;
employee.setId(id);
employee.setEmpNo("E" + id);
employee.setFullName(fullName);
employee.setHireDate(new Date());
this.employeeRepository.save(employee);
return "Inserted: " + employee;
}
@ResponseBody
@RequestMapping("/showAllEmployee")
public String showAllEmployee() {
Iterable<Employee> employees = this.employeeRepository.findAll();
String html = "";
for (Employee emp : employees) {
html += emp + "<br>";
}
return html;
}
@ResponseBody
@RequestMapping("/showFullNameLikeTom")
public String showFullNameLikeTom() {
List<Employee> employees = this.employeeRepository.findByFullNameLike("Tom");
String html = "";
for (Employee emp : employees) {
html += emp + "<br>";
}
return html;
}
@ResponseBody
@RequestMapping("/deleteAllEmployee")
public String deleteAllEmployee() {
this.employeeRepository.deleteAll();
return "Deleted!";
}
}
