Сегодня мы создадим полноценное приложение с использованием Spring Boot и JPA. Мы разберёмся, как создавать таблицы в базе данных через JPA-сущности, а также научимся работать с запросами к этим таблицам. Для практики мы разработаем мини-приложение для управления каталогом книг.
Шаг 1: Создание нового Spring Boot проекта
Если вы ещё не создали проект, воспользуемся удобным инструментом Spring Initializr. Желаемое название проекта: library-management. Включите следующие зависимости:
- Spring Web
- Spring Data JPA
- H2 Database (или выберите другую базу данных, с которой вы хотите работать)
Структура проекта
После создания проекта структура будет выглядеть примерно так:
src/main/java/com/example/librarymanagement
├── LibraryManagementApplication.java
├── entity
│ └── Book.java
├── repository
│ └── BookRepository.java
├── controller
│ └── BookController.java
├── service
└── BookService.java
Шаг 2: Настройка файла application.properties
Для конфигурации базы данных укажите параметры подключения в файле application.properties (или application.yml):
# Настройка встраиваемой базы данных H2
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=password
spring.datasource.driver-class-name=org.h2.Driver
# Генерация таблиц на основе JPA
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
Обратите внимание:
spring.jpa.hibernate.ddl-auto=updateуказывает Hibernate автоматически обновлять структуру базы данных в соответствии с вашими сущностями. Для продакшна рекомендуется использоватьvalidateили управлять схемой вручную.spring.jpa.show-sql=trueпозволяет видеть SQL-запросы, которые выполняются, в консоли.
Шаг 3: Создание сущности Book
Теперь создадим сущность, которая будет представлять таблицу books в нашей базе данных. Поместите её в пакет entity.
package com.example.librarymanagement.entity;
import jakarta.persistence.*;
@Entity // Указывает, что это сущность JPA
@Table(name = "books") // Имя таблицы
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // Генерация ID
private Long id;
@Column(name = "title", nullable = false) // Поле с именем "title", обязательное для заполнения
private String title;
@Column(name = "author", nullable = false)
private String author;
@Column(name = "year_published") // Поле с названием "year_published"
private Integer yearPublished;
// Конструкторы, геттеры и сеттеры
public Book() {}
public Book(String title, String author, Integer yearPublished) {
this.title = title;
this.author = author;
this.yearPublished = yearPublished;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Integer getYearPublished() {
return yearPublished;
}
public void setYearPublished(Integer yearPublished) {
this.yearPublished = yearPublished;
}
}
- Аннотация
@Entityделает класс сущностью JPA. - Аннотация
@Tableзадаёт название таблицы. Если её не указать, JPA автоматически установит имя таблицы по названию класса. @Idи@GeneratedValueуказывают, что полеid— это первичный ключ, который генерируется автоматически.- Для каждого поля мы задали аннотацию
@Column, чтобы настроить соответствие между полями класса и столбцами таблицы.
Шаг 4: Создание репозитория BookRepository
Механика Spring Data JPA позволяет нам создавать репозитории без необходимости писать код для базовых операций. Все основные CRUD-методы уже реализованы в интерфейсе JpaRepository.
package com.example.librarymanagement.repository;
import com.example.librarymanagement.entity.Book;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BookRepository extends JpaRepository<Book, Long> {
// Здесь можно добавлять кастомные методы при необходимости
Book findByTitle(String title);
}
Краткое пояснение
- Расширяя интерфейс
JpaRepository, мы автоматически получаем все стандартные методы, такие какsave(),findById(),deleteById()и другие. - В репозитории мы также добавили кастомный метод
findByTitle(), который выполняет поиск книг по названию.
Шаг 5: Создание сервиса BookService
Сервисный слой отвечает за бизнес-логику. Здесь мы будем использовать наш репозиторий для управления данными.
package com.example.librarymanagement.service;
import com.example.librarymanagement.entity.Book;
import com.example.librarymanagement.repository.BookRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
public List<Book> getAllBooks() {
return bookRepository.findAll();
}
public Book getBookById(Long id) {
return bookRepository.findById(id).orElseThrow(() -> new RuntimeException("Книга не найдена"));
}
public Book createBook(Book book) {
return bookRepository.save(book);
}
public void deleteBook(Long id) {
bookRepository.deleteById(id);
}
}
Шаг 6: Создание контроллера BookController
Контроллер будет обрабатывать HTTP-запросы и возвращать данные клиенту.
package com.example.librarymanagement.controller;
import com.example.librarymanagement.entity.Book;
import com.example.librarymanagement.service.BookService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/books")
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@GetMapping
public List<Book> getAllBooks() {
return bookService.getAllBooks();
}
@GetMapping("/{id}")
public Book getBookById(@PathVariable Long id) {
return bookService.getBookById(id);
}
@PostMapping
public Book createBook(@RequestBody Book book) {
return bookService.createBook(book);
}
@DeleteMapping("/{id}")
public void deleteBook(@PathVariable Long id) {
bookService.deleteBook(id);
}
}
- Аннотация
@RestControllerуказывает, что это контроллер для REST API. - Методы, такие как
getAllBooks()иcreateBook(), обрабатывают соответствующие HTTP-запросы (GET,POSTи т.д.). - Аннотация
@RequestBodyпозволяет принимать объектBookиз тела HTTP-запроса.
Шаг 7: Проверка работы
Через Postman, Curl или браузер выполните следующие действия:
1. Отправьте POST запрос на http://localhost:8080/api/books с телом:
{
"title": "Effective Java",
"author": "Joshua Bloch",
"yearPublished": 2018
}
2. Получите все добавленные книги через GET:
curl -X GET http://localhost:8080/api/books
Итог
Мы успешно создали таблицу с помощью JPA-сущности, реализовали репозиторий, добавили бизнес-логику в виде сервиса и создали контроллер для обработки запросов. Теперь наше приложение готово для работы с базой данных: мы можем добавлять, читать и удалять книги. В следующих лекциях мы рассмотрим более сложные аспекты работы с данными, такие как JPQL и ленивую/жадную загрузку данных.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ