Spring Data JPA

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

Spring Data JPA

Некоторые из интересных возможностей, предоставляемых Spring Data JPA, включают:

  1. Создание и поддержка репозиториев, созданных с помощью Spring и JPA
  2. Поддержка QueryDSL и запросов JPA
  3. Аудит классов домена
  4. Поддержка пакетной загрузки, сортировки, динамических запросов
  5. Поддержка XML-отображения для сущностей
  6. Сокращение объема кода для общих операций 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.

  1. postgresql: драйвер Postgresql для Java.
  2. spring-core, spring-context: Зависимости основного модуля Spring Framework.
  3. spring-webmvc, jackson-databind: Для приложений Spring REST.
  4. 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