Java spring аннотация repository

Spring Data JPA

Spring Data — дополнительный удобный механизм для взаимодействия с сущностями базы данных, организации их в репозитории, извлечение данных, изменение, в каких то случаях для этого будет достаточно объявить интерфейс и метод в нем, без имплементации.

  1. Spring Repository
  2. Методы запросов из имени метода
  3. Конфигурация и настройка
  4. Специальная обработка параметров
  5. Пользовательские реализации для репозитория
  6. Пользовательский Базовый Репозиторий
  7. Методы запросов — Query

1. Spring Repository

Основное понятие в Spring Data — это репозиторий. Это несколько интерфейсов которые используют JPA Entity для взаимодействия с ней. Так например интерфейс
public interface CrudRepository extends Repository
обеспечивает основные операции по поиску, сохранения, удалению данных (CRUD операции)

T save(T entity); Optional findById(ID primaryKey); void delete(T entity); 

Есть и другие абстракции, например PagingAndSortingRepository.

Т.е. если того перечня что предоставляет интерфейс достаточно для взаимодействия с сущностью, то можно прямо расширить базовый интерфейс для своей сущности, дополнить его своими методами запросов и выполнять операции. Сейчас я покажу коротко те шаги что нужны для самого простого случая (не отвлекаясь пока на конфигурации, ORM, базу данных).

@Entity @Table(name = "EMPLOYEES") public class Employees < private Long employeeId; private String firstName; private String lastName; private String email; // . . . 

2. Наследоваться от одного из интерфейсов Spring Data, например от CrudRepository

@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository

3. Использовать в клиенте (сервисе) новый интерфейс для операций с данными

@Service public class EmployeesDataService < @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Transactional public void testEmployeesCrudRepository() < OptionalemployeesOptional = employeesCrudRepository.findById(127L); //. > 

Здесь я воспользовался готовым методом findById. Т.е. вот так легко и быстро, без имплементации, получим готовый перечень операций из CrudRepository:

 S save(S var1); Iterable saveAll(Iterable var1); Optional findById(ID var1); boolean existsById(ID var1); Iterable findAll(); Iterable findAllById(Iterable var1); long count(); void deleteById(ID var1); void delete(T var1); void deleteAll(Iterable var1); void deleteAll(); 

Понятно что этого перечня, скорее всего не хватит для взаимодействия с сущностью, и тут можно расширить свой интерфейс дополнительными методами запросов.

Читайте также:  Python pandas column count

2. Методы запросов из имени метода

Запросы к сущности можно строить прямо из имени метода. Для этого используется механизм префиксов find…By, read…By, query…By, count…By, и get…By, далее от префикса метода начинает разбор остальной части. Вводное предложение может содержать дополнительные выражения, например, Distinct. Далее первый By действует как разделитель, чтобы указать начало фактических критериев. Можно определить условия для свойств сущностей и объединить их с помощью And и Or. Примеры

@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository  < // искать по полям firstName And LastName OptionalfindByFirstNameAndLastName(String firstName, String lastName); // найти первые 5 по FirstName начинающихся с символов и сортировать по FirstName List findFirst5ByFirstNameStartsWithOrderByFirstName(String firstNameStartsWith); 

В документации определен весь перечень, и правила написания метода. В качестве результата могут быть сущность T, Optional, List, Stream. В среде разработки, например в Idea, есть подсказка для написания методов запросов.

Достаточно только определить подобным образом метод, без имплементации и Spring подготовит запрос к сущности.

 @SpringBootTest public class DemoSpringDataApplicationTests < @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testFindByFirstNameAndLastName() < OptionalemployeesOptional = employeesCrudRepository.findByFirstNameAndLastName("Alex", "Ivanov"); 

3. Конфигурация и настройка

Весь проект доступен на github
github DemoSpringData

Здесь лишь коснусь некоторых особенностей.

В context.xml определенны бины transactionManager, dataSource и entityManagerFactory. Важно указать в нем также

путь где определены репозитории.

EntityManagerFactory настроен на работу с Hibernate ORM, а он в свою очередь с БД Oracle XE, тут возможны и другие варианты, в context.xml все это видно. В pom файле есть все зависимости.

4. Специальная обработка параметров

В методах запросов, в их параметрах можно использовать специальные параметры Pageable, Sort, а также ограничения Top и First.

Например вот так можно взять вторую страницу (индекс с -0), размером в три элемента и сортировкой по firstName, предварительно указав в методе репозитория параметр Pageable, также будут использованы критерии из имени метода — «Искать по FirstName начиная с % „

@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository  < ListfindByFirstNameStartsWith(String firstNameStartsWith, Pageable page); //. > // пример вызова @Test @Transactional public void testFindByFirstNameStartsWithOrderByFirstNamePage() < Listlist = employeesCrudRepository .findByFirstNameStartsWith("A", PageRequest.of(1,3, Sort.by("firstName"))); list.forEach(e -> System.out.println(e.getFirstName() + " " +e.getLastName())); > 

5. Пользовательские реализации для репозитория

Предположим что в репозиторие нужен метод, который не получается описать именем метода, тогда можно реализовать с помощью своего интерфейса и класса его имплементирующего. В примере ниже добавлю в репозиторий метод получения сотрудников с максимальной оплатой труда.

public interface CustomizedEmployees  < ListgetEmployeesMaxSalary(); > 

Имплементирую интерфейс. С помощью HQL (SQL) получаю сотрудников с максимальной оплатой, возможны и другие реализации.

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(); >> 

А также расширяю Crud Repository Employees еще и CustomizedEmployees.

@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository, CustomizedEmployees

Здесь есть одна важная особенность. Класс имплементирующий интерфейс, должен заканчиваться (postfix) на Impl, или в конфигурации надо поставить свой postfix

Проверяем работу этого метода через репозиторий

public class DemoSpringDataApplicationTests < @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testMaxSalaryEmployees() < Listemployees = employeesCrudRepository.getEmployeesMaxSalary(); employees.stream() .forEach(e -> System.out.println(e.getFirstName() + " " + e.getLastName() + " " + e.getSalary())); > 

Другой случай, когда надо изменить поведение уже существующего метода в интерфейсе Spring, например delete в CrudRepository, мне надо что бы вместо удаления из БД, выставлялся признак удаления. Техника точно такая же. Ниже пример:

public interface CustomizedEmployees  < void delete(T entity); // . >// Имплементация CustomizedEmployees public class CustomizedEmployeesImpl implements CustomizedEmployees

Теперь если в employeesCrudRepository вызвать delete, то объект будет только помечен как удаленный.

6. Пользовательский Базовый Репозиторий

В предыдущем примере я показал как переопределить delete в Crud репозитории сущности, но если это надо делать для всех сущностей проекта, делать для каждой свой интерфейс как то не очень. тогда в Spring data можно настроить свой базовый репозиторий. Для этого:
Объявляется интерфейс и в нем метод для переопределения (или общий для всех сущностей проекта). Тут я еще для всех своих сущностей ввел свой интерфейс BaseEntity (это не обязательно), для удобства вызова общих методов, его методы совпадают с методами сущности.

public interface BaseEntity < Boolean getDeleted(); void setDeleted(Boolean deleted); >// Сущность Employees @Entity @Table(name = "EMPLOYEES") public class Employees implements BaseEntity < private Boolean deleted; @Override public Boolean getDeleted() < return deleted; >@Override public void setDeleted(Boolean deleted) < this.deleted = deleted; >// Базовый пользовательский интерфейс @NoRepositoryBean public interface BaseRepository extends JpaRepository  < void delete(T entity); >//Базовый пользовательский класс имплементирующий BaseRepository public class BaseRepositoryImpl extends SimpleJpaRepository implements BaseRepository  < private final EntityManager entityManager; public BaseRepositoryImpl(JpaEntityInformationentityInformation, EntityManager entityManager) < super(entityInformation, entityManager); this.entityManager = entityManager; >@Transactional @Override public void delete(BaseEntity entity) < entity.setDeleted(true); entityManager.persist(entity); >> 

В конфигурации надо указать этот базовый репозиторий, он будет общий для всех репозиториев проекта

Теперь Employees Repository (и др.) надо расширять от BaseRepository и уже его использовать в клиенте.

public interface EmployeesBaseRepository extends BaseRepository  < // . >

Проверяю работу EmployeesBaseRepository

public class DemoSpringDataApplicationTests < @Resource private EmployeesBaseRepository employeesBaseRepository; @Test @Transactional @Commit public void testBaseRepository() < Employees employees = new Employees(); employees.setLastName("Ivanov"); // Query by Example (QBE) Exampleexample = Example.of(employees); Optional employeesOptional = employeesBaseRepository.findOne(example); employeesOptional.ifPresent(employeesBaseRepository::delete); > 

Теперь также как и ранее, объект будет помечен как удаленный, и это будет выполняться для всех сущностей, которые расширяют интерфейс BaseRepository. В примере был применен метод поиска — Query by Example (QBE), я не буду здесь его описывать, из примера видно что он делает, просто и удобно.

7. Методы запросов — Query

Ранее я писал, что если нужен специфичный метод или его реализация, которую нельзя описать через имя метода, то это можно сделать через некоторый Customized интерфейс ( CustomizedEmployees) и сделать реализацию вычисления. А можно пойти другим путем, через указание запроса (HQL или SQL), как вычислить данную функцию.
Для моего примера c getEmployeesMaxSalary, этот вариант реализации даже проще. Я еще усложню его входным параметром salary. Т.е. достаточно объявить в интерфейсе метод и запрос вычисления.

@Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository, CustomizedEmployees  < @Query("select e from Employees e where e.salary >:salary") List findEmployeesWithMoreThanSalary(@Param("salary") Long salary, Sort sort); // . > 
@Test @Transactional public void testFindEmployeesWithMoreThanSalary() < Listemployees = employeesCrudRepository.findEmployeesWithMoreThanSalary(10000L, Sort.by("lastName")); 

Упомяну лишь еще, что запросы могут быть и модифицирующие, для этого к ним добавляется еще аннотация @Modifying

@Modifying @Query("update Employees e set e.firstName = ?1 where e.employeeId = ?2") int setFirstnameFor(String firstName, String employeeId); 

Еще одной из замечательных возможностей Query аннотации — это подстановка типа домена сущности в запрос по шаблону # , через SpEL выражения.

Так например в моем гипотетическом примере, когда мне надо для всех сущностей иметь признак “удален», я сделаю базовый интерфейс с методом получения списка объектов с признаком «удален» или «активный»

@NoRepositoryBean public interface ParentEntityRepository extends Repository  < @Query("select t from #t where t.deleted = ?1") List findMarked(Boolean deleted); > 

Далее все репозитории для сущностей можно расширять от него. Интерфейсы которые не являются репозиториями, но находятся в «base-package» папке конфигурации, надо аннотировать @NoRepositoryBean.

@Repository public interface EmployeesEntityRepository extends ParentEntityRepository

Теперь когда будет выполняться запрос, в тело запроса будет подставлено имя сущности T для конкретного репозитория который будет расширять ParentEntityRepository, в данном случае Employees.

@SpringBootTest public class DemoSpringDataApplicationTests < @Autowired private EmployeesEntityRepository employeesEntityRepository; @Test @Transactional public void testEntityName() < ListemployeesMarked = employeesEntityRepository.findMarked(true); // . 

Источник

Spring @Repository Annotation

Spring @Repository Annotation

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Spring @Repository annotation is used to indicate that the class provides the mechanism for storage, retrieval, search, update and delete operation on objects.

Spring @Repository Annotation

Spring Repository annotation is a specialization of @Component annotation, so Spring Repository classes are autodetected by spring framework through classpath scanning. Spring Repository is very close to DAO pattern where DAO classes are responsible for providing CRUD operations on database tables. However, if you are using Spring Data for managing database operations, then you should use Spring Data Repository interface.

Spring Repository Example

Let’s look at a simple example where we will create a Spring Repository class. We will not use database operations, rather we will provide a repository for an Object. Create a maven project in Eclipse or any other IDE you use, then add spring core dependency.

 org.springframework spring-context 5.0.6.RELEASE  

Spring Repository Example

Below image shows our final project structure in Eclipse. Let’s create the model class for which we will implement a spring repository.

package com.journaldev.spring.model; public class Employee < private int id; private String name; private String jobTitle; public Employee() < >public Employee(int i, String n, String jt) < this.id = i; this.name = n; this.jobTitle = jt; >public int getId() < return id; >public void setId(int id) < this.id = id; >public String getName() < return name; >public void setName(String name) < this.name = name; >public String getJobTitle() < return jobTitle; >public void setJobTitle(String jobTitle) < this.jobTitle = jobTitle; >@Override public String toString() < return id + "," + name + "," + jobTitle; >> 

Before we implement Repository class, I have created a generic ObjectRepository interface to provide the contract for our repository class to implement.

package com.journaldev.spring.repository; public interface ObjectRepository

I am using Generics here, it’s a powerful technology to provide loosely coupled contract for the applications to implement. Now let’s look at our Repository class implementation.

package com.journaldev.spring.repository; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Repository; import com.journaldev.spring.model.Employee; @Repository public class EmployeeRepository implements ObjectRepository  < private Maprepository; public EmployeeRepository() < this.repository = new HashMap<>(); > @Override public void store(Employee emp) < repository.put(emp.getId(), emp); >@Override public Employee retrieve(int id) < return repository.get(id); >@Override public Employee search(String name) < Collectionemps = repository.values(); for (Employee emp : emps) < if (emp.getName().equalsIgnoreCase(name)) return emp; >return null; > @Override public Employee delete(int id) < Employee e = repository.get(id); this.repository.remove(id); return e; >> 

Note that I am using an in-memory Map to store the object data, you can use any other mechanisms too.

Spring Repository Test

package com.journaldev.spring; import java.sql.SQLException; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.journaldev.spring.model.Employee; import com.journaldev.spring.repository.EmployeeRepository; public class SpringMainClass < public static void main(String[] args) throws SQLException < AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.scan("com.journaldev.spring"); context.refresh(); EmployeeRepository repository = context.getBean(EmployeeRepository.class); // store repository.store(new Employee(1, "Pankaj", "CEO")); repository.store(new Employee(2, "Anupam", "Editor")); repository.store(new Employee(3, "Meghna", "CFO")); // retrieve Employee emp = repository.retrieve(1); System.out.println(emp); // search Employee cfo = repository.search("Meghna"); System.out.println(cfo); // delete Employee editor = repository.delete(2); System.out.println(editor); // close the spring context context.close(); >> 
1,Pankaj,CEO 3,Meghna,CFO 2,Anupam,Editor 

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases. Learn more about us

Источник

Оцените статью