Spring Data JPA является частью семьи Spring Data. Spring Data упрощает создание приложений, основанных на Spring, которые используют новые способы доступа к данным, такие как нереляционные базы данных, фреймворки сокращения объема данных, облачные сервисы, а также продвинутую поддержку реляционных баз данных. В этой статье будет рассмотрено Spring Data JPA. Мы также рассмотрим пример приложения с использованием Spring Data JPA.
Spring Data JPA
Некоторые из интересных возможностей, предоставляемых Spring Data JPA, включают:
- Создание и поддержка репозиториев, созданных с помощью Spring и JPA
- Поддержка QueryDSL и запросов JPA
- Аудит классов домена
- Поддержка пакетной загрузки, сортировки, динамических запросов
- Поддержка XML-отображения для сущностей
- Сокращение объема кода для общих операций CRUD с использованием CrudRepository
Когда использовать Spring Data JPA?
I would say that if you need to quickly create a JPA-based repository layer that is mainly for CRUD operations, and you do not want to create abstract DAO, implementing interfaces, Spring Data JPA is a good choice.
Пример Spring Data JPA
Для нашего примера Spring Data JPA мы создадим RESTful веб-сервис, который будет подключаться к базе данных Postgresql. Мы реализуем основные операции CRUD и будем работать с образцовыми данными, которые мы уже создали.
Пример данных Spring JPA
Используйте следующий запрос для создания таблицы в базе данных Postgresql и добавления некоторых тестовых данных.
create table people (
id serial not null primary key,
first_name varchar(20) not null,
last_name varchar(20) not null,
age integer not null
);
insert into people (id, first_name, last_name, age) values
(1, 'Vlad', 'Boyarskiy', 21),
(2,'Oksi', ' Bahatskaya', 30),
(3,'Vadim', ' Vadimich', 32);
Структура проекта Spring Data JPA Maven
На изображении ниже показана окончательная структура проекта Spring JPA. Позже мы рассмотрим каждый из компонентов более подробно.
Зависимости Maven для Spring Data JPA
Мы должны добавить следующие зависимости для нашего примера проекта Spring Data JPA.
postgresql
: драйвер Postgresql для Java.spring-core
,spring-context
: Зависимости основного модуля Spring Framework.spring-webmvc
,jackson-databind
: Для приложений Spring REST.spring-data-jpa
,hibernate-entitymanager
: Для поддержки Spring Data JPA и Hibernate.
Ниже приведено содержимое файла pom.xml.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>springData</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>Spring Data JPA Maven Webapp</name>
<url>https://maven.apache.org</url>
<properties>
<spring.framework>4.3.0.RELEASE</spring.framework>
<postgres.version>42.1.4</postgres.version>
<serializer.version>2.8.1</serializer.version>
<spring.data>1.3.4.RELEASE</spring.data>
<hibernate.manager>4.2.5.Final</hibernate.manager>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgres.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring.data}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.manager}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${serializer.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
Конфигурационные классы Spring
package com.journaldev.spring.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.ejb.HibernatePersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("com.journaldev.spring.repository")
@PropertySource("classpath:database.properties")
public class DataConfig {
private final String PROPERTY_DRIVER = "driver";
private final String PROPERTY_URL = "url";
private final String PROPERTY_USERNAME = "user";
private final String PROPERTY_PASSWORD = "password";
private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
private final String PROPERTY_DIALECT = "hibernate.dialect";
@Autowired
Environment environment;
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
lfb.setDataSource(dataSource());
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setPackagesToScan("com.journaldev.spring.model");
lfb.setJpaProperties(hibernateProps());
return lfb;
}
@Bean
DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl(environment.getProperty(PROPERTY_URL));
ds.setUsername(environment.getProperty(PROPERTY_USERNAME));
ds.setPassword(environment.getProperty(PROPERTY_PASSWORD));
ds.setDriverClassName(environment.getProperty(PROPERTY_DRIVER));
return ds;
}
Properties hibernateProps() {
Properties properties = new Properties();
properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
return properties;
}
@Bean
JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
-
@Configuration
: Эта аннотация Spring указывает, что это класс конфигурации. -
@EnableTransactionManagement
: Эта аннотация позволяет использовать управление транзакциями в приложении. -
@EnableJpaRepositories("com.journaldev.spring.repository")
: Указывает, где находятся классы репозиториев. -
@PropertySource("classpath:database.properties")
: указывает, что у нас есть файл свойств в нашем classpath. Значения из этого файла будут внедрены в переменную среды. Содержимое файла database.properties показано ниже.driver=org.postgresql.Driver url=jdbc:postgresql://127.0.0.1:5432/postgres user=postgres password=postgres hibernate.dialect=org.hibernate.dialect.PostgreSQL82Dialect hibernate.show_sql=true
-
Для использования Spring Data сначала мы должны настроить бин
DataSource
. Затем нам нужно настроить бинLocalContainerEntityManagerFactoryBean
. Нам нужен этот бин для управления сущностями. В этом бине вы должны указать поставщик сохранения, то естьHibernatePersistence
в нашем случае. -
Следующий шаг – настройка бина для управления транзакциями. В нашем примере это
JpaTransactionManager
. Обратите внимание, что без настройки менеджера транзакций мы не можем использовать аннотацию@Transactional
.
Класс AppInitializer
и Класс WebConfig
предназначены для настройки нашего приложения в качестве веб-приложения без использования файла web.xml.
Класс модели
package com.journaldev.spring.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "people")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "age")
private Integer age;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
public Person() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "Person{" + "id=" + id + ", age=" + age + ", firstName='" + firstName + '\'' + ", lastName='" + lastName
+ '\'' + '}';
}
}
Здесь у нас есть несколько новых аннотаций. Давайте поговорим о них подробнее.
- @Entity: Эта аннотация позволяет менеджеру сущностей использовать этот класс и помещает его в контекст.
- @Table(name = “people”): связывает класс с таблицей в базе данных.
@Id
: указывает, что это поле является первичным ключом.@GeneratedValue(strategy = GenerationType.IDENTITY)
: Определяет стратегию генерации первичного ключа.@Column(name = "age")
: обозначает столбец в базе данных, с которым будет связано это поле.
Репозиторий Spring Data JPA
Следующий шаг – создание репозитория JPA.
package com.journaldev.spring.repository;
import org.springframework.data.repository.CrudRepository;
import com.journaldev.spring.model.Person;
import java.util.List;
public interface PersonRepository<P> extends CrudRepository<Person, Long> {
List<Person> findByFirstName(String firstName);
}
Наследуясь от CrudRepository
, мы можем вызывать множество методов, необходимость в их реализации отпадает. Некоторые из этих методов:
- save
- findOne
- exists
- findAll
- count
- delete
- deleteAll
Мы также можем определить свои собственные методы. Имена этих методов должны использовать специальные ключевые слова, такие как “find”, “order” с именем переменных. Разработчики Spring Data JPA попытались учесть большинство возможных вариантов, которые вам могут понадобиться. В нашем примере метод findByFirstName(String firstName)
возвращает все записи из таблицы, где поле first_name
равно firstName
. Это одна из самых важных особенностей Spring Data JPA, потому что она устраняет много шаблонного кода. Кроме того, вероятность ошибок меньше, потому что эти методы Spring хорошо протестированы множеством проектов, которые уже их используют.
Класс Spring Service
Теперь, когда наш код Spring Data JPA готов, следующим шагом является создание класса сервиса и определение методов, с которыми мы будем работать с таблицей базы данных.
package com.journaldev.spring.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.repository.PersonRepository;
@Service
public class PersonService {
@Autowired
PersonRepository<Person> personRepository;
@Transactional
public List<Person> getAllPersons() {
return (List<Person>) personRepository.findAll();
}
@Transactional
public List<Person> findByName(String name) {
return personRepository.findByFirstName(name);
}
@Transactional
public Person getById(Long id) {
return personRepository.findOne(id);
}
@Transactional
public void deletePerson(Long personId) {
personRepository.delete(personId);
}
@Transactional
public boolean addPerson(Person person) {
return personRepository.save(person) != null;
}
@Transactional
public boolean updatePerson(Person person) {
return personRepository.save(person) != null;
}
}
Аннотация @Transactional
указывает, что метод будет выполнен в транзакции. Spring позаботится о управлении транзакциями.
Класс Spring Controller
Последний шаг – создать класс контроллера, чтобы предоставить наши API внешнему миру.
package com.journaldev.spring.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.services.PersonService;
@RestController
public class PersonController {
@Autowired
PersonService personService;
@RequestMapping(value = "/person/{id}", method = RequestMethod.GET)
public @ResponseBody Person getAllUsers(@PathVariable Long id) {
return personService.getById(id);
}
@RequestMapping(value = "/personByName/{name}", method = RequestMethod.GET)
public List<Person> getPersoneByName(@PathVariable String name) {
return personService.findByName(name);
}
@RequestMapping(value = "/person", method = RequestMethod.GET)
public List<Person> getAll() {
return personService.getAllPersons();
}
@RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE)
public HttpStatus deletePersnone(@PathVariable Long id) {
personService.deletePerson(id);
return HttpStatus.NO_CONTENT;
}
@RequestMapping(value = "/person", method = RequestMethod.POST)
public HttpStatus insertPersone(@RequestBody Person person) {
return personService.addPerson(person) ? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
}
@RequestMapping(value = "/person", method = RequestMethod.PUT)
public HttpStatus updatePerson(@RequestBody Person person) {
return personService.updatePerson(person) ? HttpStatus.ACCEPTED : HttpStatus.BAD_REQUEST;
}
}
Тестирование Spring Data JPA
Просто соберите и разверните проект в вашем любимом контейнере сервлетов, таком как Tomcat. Ниже показаны ответы на некоторые из вызовов API.
Spring Data JPA Чтение всего
Spring Data JPA Получение по имени
Spring Data JPA Создание
Spring Data JPA Обновление
Spring Data JPA Удаление
Это все, что касается примера учебного руководства по Spring Data JPA. Вы можете скачать окончательный проект по ссылке ниже.
Скачать проект примера Spring Data JPA
Ссылка: Официальный веб-сайт
Source:
https://www.digitalocean.com/community/tutorials/spring-data-jpa