Сегодня мы реализуем малую, но важную часть нашего приложения: создадим сущности и репозитории. Мы расширим функциональность нашего проекта, добавив работу с базой данных. В процессе работы мы будем шаг за шагом разбирать:
- Создание сущности — основа работы с JPA. Используем аннотации, такие как
@Entity,@Id,@GeneratedValueи другие. - Настройка репозиториев. Подключим
JpaRepositoryи используем его стандартные методы. - Практическая работа с CRUD-операциями. Сохраним, обновим, удалим и прочитаем данные из базы.
1. Постановка задачи
Представьте, что вы работаете над системой управления библиотечным каталогом. В рамках учебного примера мы создадим сущность Book, которая будет представлять книгу, и обеспечим базовые операции для взаимодействия с ней через базу данных. Наши задачи:
- Создать сущность
Bookс полямиid,title,authorиpublishedYear. - Реализовать для неё репозиторий.
- Написать методы для сохранения и получения данных.
2. Создание сущности
Начнём с создания класса-сущности Book. Вспоминаем главное правило: сущности сопоставляют таблицы в базе данных. Каждое поле нашего класса становится колонкой в таблице. Для этого воспользуемся аннотациями @Entity, @Id, @GeneratedValue, @Column.
Откроем наш проект и добавим новый класс Book в пакет entity.
package com.example.library.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Column;
@Entity
public class Book {
@Id // Указываем первичный ключ
@GeneratedValue(strategy = GenerationType.IDENTITY) // Автоматическая генерация ID
private Long id;
@Column(nullable = false) // Поле обязательное
private String title;
@Column(nullable = false)
private String author;
@Column(name = "published_year") // Указываем название колонки в базе
private Integer publishedYear;
// Конструкторы, геттеры, сеттеры
public Book() {
}
public Book(String title, String author, Integer publishedYear) {
this.title = title;
this.author = author;
this.publishedYear = publishedYear;
}
// Геттеры и сеттеры
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 getPublishedYear() {
return publishedYear;
}
public void setPublishedYear(Integer publishedYear) {
this.publishedYear = publishedYear;
}
}
В коде:
@Entity— обозначает, что класс является сущностью и будет сопоставлен с таблицей в базе.@Id— поле, которое будет использоваться в качестве первичного ключа таблицы.@GeneratedValue(strategy = GenerationType.IDENTITY)— автоматическая генерация ID для новых записей.@Column— настройка столбцов таблицы; добавилиnullable = false, чтобы сделать поле обязательным.
Теперь, когда наша сущность готова, переходим к следующему шагу!
3. Создание репозитория
Репозиторий отвечает за операции с базой данных. В Spring Data JPA для этого используются интерфейсы, такие, как JpaRepository. Мы создадим интерфейс BookRepository и подключим стандартные методы.
Добавим новый интерфейс в пакет repository.
package com.example.library.repository;
import com.example.library.entity.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
// Здесь можно добавлять кастомные методы, если потребуется
}
JpaRepository<Book, Long>— типBookуказывает на нашу сущность, аLong— на тип её идентификатора.- Аннотация
@Repositoryдаёт понять Spring, что это компонент для работы с базой данных.
Встроенные методы JpaRepository
Получив наследование от JpaRepository, мы уже можем использовать методы, такие как:
save()— для сохранения объекта.findById()— для поиска объекта по ID.findAll()— для получения списка всех объектов.deleteById()— для удаления объекта по ID.
4. Практическая работа: CRUD-операции
Теперь мы протестируем работу созданных сущностей и репозиториев. Для этого создадим базовый сервис и добавим тестовые данные.
Добавим новый сервис в пакет service.
package com.example.library.service;
import com.example.library.entity.Book;
import com.example.library.repository.BookRepository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class BookService {
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
// Добавление книги
public Book addBook(Book book) {
return bookRepository.save(book);
}
// Получение всех книг
public List<Book> getAllBooks() {
return bookRepository.findAll();
}
// Поиск книги по ID
public Optional<Book> getBookById(Long id) {
return bookRepository.findById(id);
}
// Удаление книги по ID
public void deleteBook(Long id) {
bookRepository.deleteById(id);
}
}
Теперь добавим контроллер, чтобы протестировать функциональность через HTTP-запросы.
package com.example.library.controller;
import com.example.library.entity.Book;
import com.example.library.service.BookService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/books")
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@PostMapping
public Book addBook(@RequestBody Book book) {
return bookService.addBook(book);
}
@GetMapping
public List<Book> getAllBooks() {
return bookService.getAllBooks();
}
@GetMapping("/{id}")
public Book getBookById(@PathVariable Long id) {
return bookService.getBookById(id).orElseThrow(() -> new RuntimeException("Book not found"));
}
@DeleteMapping("/{id}")
public void deleteBook(@PathVariable Long id) {
bookService.deleteBook(id);
}
}
Для проверки работы можно отправлять запросы через Postman или аналогичный инструмент.
5. Запуск и проверка
- Запустите приложение на вашем локальном сервере.
- Проверьте базу данных, чтобы убедиться, что таблица
bookбыла создана. - Используйте такие запросы:
POST /booksс телом:{ "title": "Spring in Action", "author": "Craig Walls", "publishedYear": 2021 }GET /books— для получения всех книг.GET /books/{id}— для получения книги по ID.DELETE /books/{id}— для удаления книги.
Поздравляем! Вы создали свою первую сущность и подключили её к базе с минимальными усилиями! Теперь ваш код стал ближе к реальному производству!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ