Доступ к данным через JPA
Этот урок освещает процесс создания приложения, которое использует Spring Data JPA для сохранения и получения данных из реляционной БД.
Что вы создадите
Вы создадите приложение, которое сохраняет Customer
POJO в БД в ОЗУ.
Что вам потребуется
- Примерно 15 минут свободного времени
- Любимый текстовый редактор или IDE
- JDK 6 и выше
- Gradle 1.11+ или Maven 3.0+
- Вы также можете импортировать код этого урока, а также просматривать web-страницы прямо из Spring Tool Suite (STS), собственно как и работать дальше из него.
Как проходить этот урок
Как и большинство уроков по Spring, вы можете начать с нуля и выполнять каждый шаг, либо пропустить базовые шаги, которые вам уже знакомы. В любом случае, вы в конечном итоге получите рабочий код.
Чтобы начать с нуля, перейдите в Настройка проекта.
Чтобы пропустить базовые шаги, выполните следующее:
- Загрузите и
распакуйте архив с кодом этого урока, либо кнонируйте из репозитория с помощью
Git:
git clone https://github.com/spring-guides/gs-accessing-data-jpa.git
- Перейдите в каталог
gs-accessing-data-jpa/initial
- Забегая вперед, опишите простую сущность
Когда вы закончите, можете сравнить получившийся результат с образцом в gs-accessing-data-jpa/complete
.
Настройка проекта
Для начала вам необходимо настроить базовый скрипт сборки. Вы можете использовать любую систему сборки, которая вам нравится для сборки проетов Spring, но в этом уроке рассмотрим код для работы с Gradle и Maven. Если вы не знакомы ни с одним из них, ознакомьтесь с соответсвующими уроками Сборка Java-проекта с использованием Gradle или Сборка Java-проекта с использованием Maven.
Создание структуры каталогов
В выбранном вами каталоге проекта создайте следующую структуру каталогов; к примеру,
командой mkdir -p src/main/java/hello
для *nix систем:
└── src └── main └── java └── hello
Создание файла сборки Gradle
Ниже представлен начальный файл сборки Gradle. Файл pom.xml находится здесь. Если вы используете Spring Tool Suite (STS), то можете импортировать урок прямо из него.
pom.xml
, вы найдете, что указана версия для maven-compiler-plugin.
В общем, это не рекомендуется делать. В данном случае он предназначен для решения проблем с нашей CI системы,
которая по умолчанию имеет старую(до Java 5) версию этого плагина.
build.gradle
buildscript {
repositories {
maven { url "http://repo.spring.io/libs-release" }
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.8.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
jar {
baseName = 'gs-accessing-data-jpa'
version = '0.1.0'
}
repositories {
mavenLocal()
mavenCentral()
maven { url "http://repo.spring.io/libs-release" }
maven { url "https://repository.jboss.org/nexus/content/repositories/releases" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("com.h2database:h2")
testCompile("junit:junit")
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
Spring Boot gradle plugin предоставляет множество удобных возможностей:
- Он собирает все jar'ы в classpath и собирает единое, исполняемое "über-jar", что делает более удобным выполнение и доставку вашего сервиса
- Он ищет
public static void main()
метод, как признак исполняемого класса - Он предоставляет встроенное разрешение зависимостей, с определенными номерами версий для соответсвующих Spring Boot зависимостей. Вы можете переопределить на любые версии, какие захотите, но он будет по умолчанию для Boot выбранным набором версий
Описание простой сущности
В этом примере, вы сохраняете Customer объекты, аннотированные как JPA сущность.
src/main/java/hello/Customer.java
package hello;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
protected Customer() {}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format(
"Customer[id=%d, firstName='%s', lastName='%s']",
id, firstName, lastName);
}
}
Здесь у вас есть класс Customer
с тремя атрибутами id
,
firstName
и lastName
. У вас также есть два конструктора.
Конструктор по умолчанию существует только из-за JPA. Вы не будете его использовать
напрямую, потому что он определен как protected
. Другой конструктор вы
будете использовать для создания экземпляра Customer
, чтобы сохранить
его в БД.
Класс Customer
аннотирован как @Entity
, означая, что он
является JPA сущностью. Из-за отсутствия аннотации @Table
, предполагается,
что сущность будет соответствовать таблице с названием Customer
.
Свойство id
класса Customer
аннотировано как @Id
,
так что JPA распознает его как ID объекта. Свойство id
также аннотировано
как @GeneratedValue
, означая, что ID должен генерироваться автоматически.
Другие два свойства, firstName
и lastName
остались не
аннотированными. Это значит, что они будут соответствовать колонкам с такими же
названиями и параметрами.
Метод tostring
будет печатать свойства объекта.
Создание простых запросов
Spring Data JPA ориентирована на использование JPA для сохранения данных в реляционную БД. Наиболее полезной её возможностью является автоматическое создание реализаций репозитория во время выполнения из интерфейса.
Чтобы увидеть, как это работает, создайте интерфейс репозитория, который работает с сущностями Customer
:
src/main/java/hello/CustomerRepository.java
package hello;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
CustomerRepository
расширяет CrudRepository
интерфейс. Тип сущности
и ID, Customer
и Long
, указаны в общих параметрах CrudRepository
.
Расширяя CrudRepository
, CustomerRepository
наследует несколько
методов для работы с Customer
, включая методы сохранения, удаления и поиска.
Spring Data JPA позволяет также определить и другие методы запросов, просто описав сигнатуры
метода. В данном случае, таковым является метод findByLastName()
.
В типичном Java приложении, вы бы написали класс, который реализовывал
CustomerRepository
. Но это то, что делает Spring Data JPA мощным
инструментом: вам не нужно писать реализацию интерфейса репозитория. Spring Data JPA
создает реализацию на лету, когда вы запускаете приложение.
Приступим к работе и посмотрим, что он найдет!
Создание класса Application
Создайте класс Application со всеми компонентами.
src/main/java/hello/Application.java
package hello;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class);
CustomerRepository repository = context.getBean(CustomerRepository.class);
// save a couple of customers
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));
// fetch all customers
Iterable<Customer> customers = repository.findAll();
System.out.println("Customers found with findAll():");
System.out.println("-------------------------------");
for (Customer customer : customers) {
System.out.println(customer);
}
System.out.println();
// fetch an individual customer by ID
Customer customer = repository.findOne(1L);
System.out.println("Customer found with findOne(1L):");
System.out.println("--------------------------------");
System.out.println(customer);
System.out.println();
// fetch customers by last name
List<Customer> bauers = repository.findByLastName("Bauer");
System.out.println("Customer found with findByLastName('Bauer'):");
System.out.println("--------------------------------------------");
for (Customer bauer : bauers) {
System.out.println(bauer);
}
context.close();
}
}
В конфигурацию вам необходимо добавить аннотацию @EnableAutoConfiguration
.
Эта аннотация говорит Spring Boot конфигурировать JPA репозитории и сущности из текущего
пакета. Поэтому для любых интерфейсов, которые расширяют
org.springframework.data.repository.Repository
, будут автоматически сгенерированы
реализации. Расширяя JpaRepository
, ваш интерфейс CustomerRepository
транзитивно расширяет Repository
. Следовательно, Spring Data JPA будет находить
его и создавать для вас реализацию.
Application
включает метод main()
, который использует CustomerRepository
в нескольких тестах. Для начала, он получает CustomerRepository
из контекста приложения
Spring. Затем он сохраняет несколько объектов Customer
через метод save()
.
Далее, вызывается findAll()
для получения всех объектов Customer
из БД.
Затем вызывается finfOne()
для получения единственного customer
по его ID.
В заключении, вызывается findByLastName()
для получения всех объектов с фамилией "Bauer".
Сборка исполняемого JAR
Вы можете собрать единый исполняемый JAR-файл, который содержит все необходимые зависимости, классы и ресурсы. Это делает его легким в загрузке, версионировании и развертывании сервиса как приложения на протяжении всего периода разработки, на различных средах и так далее.
./gradlew build
Затем вы можете запустить JAR-файл:
java -jar build/libs/gs-accessing-data-jpa-0.1.0.jar
Если вы используете Maven, вы можете запустить приложение, используя mvn spring-boot:run
,
либо вы можете собрать приложение с mvn clean package
и запустить JAR примерно так:
java -jar target/gs-accessing-data-jpa-0.1.0.jar
Если вы используете Gradle, вы можете запустить ваш сервис из командной строки:
./gradlew clean build && java -jar build/libs/gs-accessing-data-jpa-0.1.0.jar
mvn clean package && java -jar target/gs-accessing-data-jpa-0.1.0.jar
.
Как вариант, вы можете запустить ваш сервис напрямую из Gradle примерно так:
./gradlew bootRun
mvn spring-boot:run
.Вы должны увидеть следующее:
== Customers found with findAll(): Customer[id=1, firstName='Jack', lastName='Bauer'] Customer[id=2, firstName='Chloe', lastName='O'Brian'] Customer[id=3, firstName='Kim', lastName='Bauer'] Customer[id=4, firstName='David', lastName='Palmer'] Customer[id=5, firstName='Michelle', lastName='Dessler'] == Customer found with findOne(1L): Customer[id=1, firstName='Jack', lastName='Bauer'] == Customer found with findByLastName('Bauer'): Customer[id=1, firstName='Jack', lastName='Bauer'] Customer[id=3, firstName='Kim', lastName='Bauer']
Итог
Поздравляем! Вы только что написали простое приложение с использованием Spring Data JPA для сохранения объектов в БД и для их получения - и все это без написания реализации репозитория.
С оригинальным текстом урока вы можете ознакомиться на spring.io.
comments powered by Disqus