Dans l'article, je décrirai l'utilisation de Spring Data.
Spring Data est un mécanisme supplémentaire pratique pour interagir avec les entités de base de données, les organiser dans un référentiel, récupérer les données, changer, dans certains cas, pour cela, il suffira de déclarer une interface et une méthode, sans implémentation.
Contenu:
- DépÎt Spring
- Demander des méthodes au nom de la méthode
- Configuration et installation
- Traitement des paramÚtres spéciaux
- Implémentations de référentiel personnalisées
- Référentiel de base personnalisé
- MĂ©thodes de requĂȘte - RequĂȘte
1. Spring Repository
Le concept de base de Spring Data est le référentiel. Ce sont plusieurs interfaces qui utilisent l'entité JPA pour interagir avec elle. Ainsi, par exemple, une interface
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID>
fournit des opérations de base pour rechercher, enregistrer, supprimer des données (opérations CRUD)
T save(T entity); Optional findById(ID primaryKey); void delete(T entity);
et autres opérations.
Il existe d'autres abstractions, telles que PagingAndSortingRepository.
C'est-Ă -dire si la liste fournie par l'interface est suffisante pour interagir avec l'entitĂ©, vous pouvez dĂ©velopper directement l'interface de base de votre entitĂ©, la complĂ©ter avec vos mĂ©thodes de requĂȘte et effectuer des opĂ©rations. Je vais maintenant montrer briĂšvement les Ă©tapes nĂ©cessaires pour le cas le plus simple (sans ĂȘtre distrait jusqu'Ă prĂ©sent par la configuration, l'ORM, la base de donnĂ©es).
1. Créez une entité
@Entity @Table(name = "EMPLOYEES") public class Employees { private Long employeeId; private String firstName; private String lastName; private String email;
2. Hérité de l'une des interfaces Spring Data, par exemple de CrudRepository
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>
3. Utiliser dans le client (service) une nouvelle interface pour les opérations de données
@Service public class EmployeesDataService { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Transactional public void testEmployeesCrudRepository() { Optional<Employees> employeesOptional = employeesCrudRepository.findById(127L);
Ici, j'ai utilisé la méthode
findById prĂȘte Ă l'emploi. C'est-Ă -dire si rapidement et facilement, sans implĂ©mentation, nous obtenons une liste prĂȘte Ă l'emploi d'opĂ©rations de CrudRepository:
S save(S var1); Iterable<S> saveAll(Iterable<S> var1); Optional<T> findById(ID var1); boolean existsById(ID var1); Iterable<T> findAll(); Iterable<T> findAllById(Iterable<ID> var1); long count(); void deleteById(ID var1); void delete(T var1); void deleteAll(Iterable<? extends T> var1); void deleteAll();
Il est clair que cette liste n'est probablement pas suffisante pour interagir avec l'entitĂ©, et ici vous pouvez Ă©tendre votre interface avec des mĂ©thodes de requĂȘte supplĂ©mentaires.
2. Interroger les méthodes à partir du nom de la méthode
Les demandes Ă l'entitĂ© peuvent ĂȘtre gĂ©nĂ©rĂ©es directement Ă partir du nom de la mĂ©thode. Pour cela, les prĂ©fixes find ... By, read ... By, query ... By, count ... By et get ... By sont utilisĂ©s, plus loin du prĂ©fixe de la mĂ©thode, il commence Ă analyser le reste. La phrase introductive peut contenir des expressions supplĂ©mentaires, par exemple Distinct. Ensuite, le premier By agit comme un dĂ©limiteur pour indiquer le dĂ©but des critĂšres rĂ©els. Vous pouvez dĂ©finir des conditions pour les propriĂ©tĂ©s d'entitĂ© et les combiner Ă l'aide de Et et Ou. Des exemples
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> {
La documentation dĂ©finit la liste entiĂšre et les rĂšgles d'Ă©criture de la mĂ©thode. Le rĂ©sultat peut ĂȘtre une entitĂ© T, facultative, liste, flux. Dans un environnement de dĂ©veloppement, comme Idea, il existe une astuce pour Ă©crire des mĂ©thodes de requĂȘte.

Il suffit de dĂ©finir une mĂ©thode de cette maniĂšre, sans implĂ©mentation, et Spring prĂ©parera une requĂȘte pour l'entitĂ©.
@SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testFindByFirstNameAndLastName() { Optional<Employees> employeesOptional = employeesCrudRepository.findByFirstNameAndLastName("Alex", "Ivanov");
3. Configuration et installation
L'ensemble du projet est disponible sur github
github DemoSpringDataIci, je ne parlerai que de certaines fonctionnalités.
Les beans TransactionManager, dataSource et entityManagerFactory sont dĂ©finis dans context.xml. Il est important dây indiquer Ă©galement
<jpa:repositories base-package="com.example.demoSpringData.repositories"/>
chemin oĂč les rĂ©fĂ©rentiels sont dĂ©finis.
EntityManagerFactory est configuré pour fonctionner avec Hibernate ORM, et c'est, à son tour, avec la base de données Oracle XE, ici d'autres options sont possibles, dans context.xml tout cela est visible. Le fichier pom a toutes les dépendances.
4. Traitement spécial des paramÚtres
Dans les mĂ©thodes de requĂȘte, dans leurs paramĂštres, vous pouvez utiliser des paramĂštres spĂ©ciaux Pageable, Sort, ainsi que des restrictions Top et First.
Par exemple, comme ceci, vous pouvez prendre la deuxiĂšme page (index avec -0), la taille de trois Ă©lĂ©ments et triĂ©e par firstName, aprĂšs avoir spĂ©cifiĂ© le paramĂštre Pageable dans la mĂ©thode du rĂ©fĂ©rentiel, les critĂšres du nom de la mĂ©thode seront Ă©galement utilisĂ©s - «Recherche par FirstName commençant par%â
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> { List<Employees> findByFirstNameStartsWith(String firstNameStartsWith, Pageable page);
5. Implémentations personnalisées pour le référentiel
Supposons que vous ayez besoin d'une mĂ©thode dans le rĂ©fĂ©rentiel qui ne puisse pas ĂȘtre dĂ©crite par le nom de la mĂ©thode, alors vous pouvez l'implĂ©menter en utilisant votre propre interface et sa classe d'implĂ©mentation. Dans l'exemple ci-dessous, je vais ajouter au rĂ©fĂ©rentiel une mĂ©thode pour obtenir des employĂ©s avec un salaire maximum.
Déclarer l'interface
public interface CustomizedEmployees<T> { List<T> getEmployeesMaxSalary(); }
Implémente l'interface. En utilisant HQL (SQL) j'obtiens des employés avec un salaire maximum, d'autres implémentations sont possibles.
public class CustomizedEmployeesImpl implements CustomizedEmployees { @PersistenceContext private EntityManager em; @Override public List getEmployeesMaxSalary() { return em.createQuery("from Employees where salary = (select max(salary) from Employees )", Employees.class) .getResultList(); } }
Et également étendre les employés de Crud Repository avec CustomizedEmployees.
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees>
Il y a une caractéristique importante ici. L'interface d'implémentation de classe doit se terminer (postfix) sur
Impl , ou dans la configuration dont vous avez besoin pour mettre votre postfix
<repositories base-package="com.repository" repository-impl-postfix="MyPostfix" />
Vérification du fonctionnement de cette méthode via le référentiel
public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testMaxSalaryEmployees() { List<Employees> employees = employeesCrudRepository.getEmployeesMaxSalary(); employees.stream() .forEach(e -> System.out.println(e.getFirstName() + " " + e.getLastName() + " " + e.getSalary())); }
Un autre cas oĂč il est nĂ©cessaire de modifier le comportement d'une mĂ©thode existante dans l'interface Spring, par exemple, supprimer dans CrudRepository, j'ai besoin qu'au lieu de supprimer de la base de donnĂ©es, un signe de suppression soit dĂ©fini. La technique est exactement la mĂȘme. Voici un exemple:
public interface CustomizedEmployees<T> { void delete(T entity);
Maintenant, si vous appelez
delete dans employeesCrudRepository, l'objet sera uniquement marqué comme supprimé.
6. Référentiel de la base d'utilisateurs
Dans l'exemple précédent, j'ai montré comment redéfinir le référentiel de suppression d'une entité dans Crud, mais si vous devez le faire pour toutes les entités de projet, rendez votre propre interface pas si bonne pour chacune ... puis dans les données Spring, vous pouvez configurer votre référentiel de base. Pour ce faire:
Une interface est déclarée et en elle une méthode de substitution (ou commune à toutes les entités du projet). Ici, pour toutes mes entités, j'ai introduit mon interface
BaseEntity (ce n'est pas nécessaire), pour la commodité d'appeler des méthodes communes, ses méthodes coïncident avec les méthodes de l'entité.
public interface BaseEntity { Boolean getDeleted(); void setDeleted(Boolean deleted); }
Dans la configuration, vous devez spécifier ce référentiel de base, il sera commun à tous les référentiels de projet
<jpa:repositories base-package="com.example.demoSpringData.repositories" base-class="com.example.demoSpringData.BaseRepositoryImpl"/>
DĂ©sormais, le rĂ©fĂ©rentiel des employĂ©s (et d'autres) doit ĂȘtre dĂ©veloppĂ© Ă partir de BaseRepository et dĂ©jĂ l'utiliser dans le client.
public interface EmployeesBaseRepository extends BaseRepository <Employees, Long> {
Vérification des employésBaseRepository
public class DemoSpringDataApplicationTests { @Resource private EmployeesBaseRepository employeesBaseRepository; @Test @Transactional @Commit public void testBaseRepository() { Employees employees = new Employees(); employees.setLastName("Ivanov");
Maintenant, comme précédemment, l'objet sera marqué comme supprimé, et cela sera effectué pour toutes les entités qui étendent l'interface BaseRepository. Dans l'exemple, la méthode de recherche -
RequĂȘte par exemple (QBE) a Ă©tĂ© appliquĂ©e, je ne la dĂ©crirai pas ici, l'exemple montre ce qu'elle fait, simple et pratique.
Plus tĂŽt, j'ai Ă©crit que si vous avez besoin d'une mĂ©thode spĂ©cifique ou de son implĂ©mentation, qui ne peut pas ĂȘtre dĂ©crite Ă l'aide du nom de la mĂ©thode, cela peut ĂȘtre fait via une interface personnalisĂ©e (CustomizedEmployees) et effectuer une implĂ©mentation de calcul. Et vous pouvez aller dans l'autre sens, en indiquant la requĂȘte (HQL ou SQL), comment calculer cette fonction.
Pour mon exemple avec getEmployeesMaxSalary, cette option d'implémentation est encore plus simple. Je vais le compliquer avec le paramÚtre d'entrée de salaire. C'est-à -dire il suffit de déclarer la méthode de calcul et de demander dans l'interface.
@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees> { @Query("select e from Employees e where e.salary > :salary") List<Employees> findEmployeesWithMoreThanSalary(@Param("salary") Long salary, Sort sort);
Vérification
@Test @Transactional public void testFindEmployeesWithMoreThanSalary() { List<Employees> employees = employeesCrudRepository.findEmployeesWithMoreThanSalary(10000L, Sort.by("lastName"));
Je mentionnerai simplement qu'il peut y avoir des demandes de modification, pour cela une annotation
@Modifying supplémentaire
leur est ajoutée
@Modifying @Query("update Employees e set e.firstName = ?1 where e.employeeId = ?2") int setFirstnameFor(String firstName, String employeeId);
Une autre des grandes fonctionnalités des annotations de
requĂȘte est la substitution du type de domaine d'entitĂ© dans la requĂȘte Ă l'aide du modĂšle
# {# entityName} , via des expressions SpEL.
Ainsi, par exemple, dans mon exemple hypothétique, lorsque j'ai besoin d'avoir le signe «supprimé» pour toutes les entités, je ferai une interface de base avec une méthode pour obtenir une liste d'objets avec le signe «supprimé» ou «actif»
@NoRepositoryBean public interface ParentEntityRepository<T> extends Repository<T, Long> { @Query("select t from #{#entityName} t where t.deleted = ?1") List<T> findMarked(Boolean deleted); }
De plus, tous les rĂ©fĂ©rentiels d'entitĂ©s peuvent ĂȘtre Ă©tendus Ă partir de celui-ci. Les interfaces qui ne sont pas des rĂ©fĂ©rentiels, mais qui se trouvent dans le dossier de configuration "package de base", annotez @NoRepositoryBean.
Référentiel des employés
@Repository public interface EmployeesEntityRepository extends ParentEntityRepository <Employees> { }
Maintenant, lorsque la demande est exécutée, le nom d'entité
T sera substitué dans le corps de la demande pour un référentiel spécifique qui étendra le ParentEntityRepository, dans ce cas, les employés.
Vérifier
@SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private EmployeesEntityRepository employeesEntityRepository; @Test @Transactional public void testEntityName() { List<Employees> employeesMarked = employeesEntityRepository.findMarked(true);
Matériaux
Spring Data JPA - Documentation de référenceProjet sur github .