Создание Spring Boot Data Rest CRUD-приложения
Last updated: 12 мая 2025 г.Создадим crud
приложение, только теперь с использованием Spring Data Rest.
Создадим новое Spring Boot приложение с такими папками и файлами.

Как видите, в этом проекте, по сравнению с предыдущими crud приложениями которые мы разрабатывали, стало крайне мало файлов.
Нет дао класса, сервис класса и даже контроллера. А если вы пролистаете данный урок далее, то увидите, что в файлах вообще практически нет кода.
Но при всем этом, это полностью рабочее crud приложение. Что? Как такое возможно?
Давайте же разберемся.
Для начала, давайте добавим зависимость для поддержки Spring Data Rest.
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
5 https://maven.apache.org/xsd/maven-4.0.0.xsd">
6 <modelVersion>4.0.0</modelVersion>
7 <parent>
8 <groupId>org.springframework.boot</groupId>
9 <artifactId>spring-boot-starter-parent</artifactId>
10 <version>3.1.5</version>
11 <relativePath/> <!-- lookup parent from repository -->
12 </parent>
13 <groupId>com.SpringBootApps</groupId>
14 <artifactId>firstSpringBootDataRestCRUDApp</artifactId>
15 <version>0.0.1-SNAPSHOT</version>
16 <name>firstSpringBootDataRestCRUDApp</name>
17 <description>Demo project for Spring Boot</description>
18 <properties>
19 <java.version>17</java.version>
20 </properties>
21 <dependencies>
22 <dependency>
23 <groupId>org.springframework.boot</groupId>
24 <artifactId>
25 spring-boot-starter-data-jpa
26 </artifactId>
27 </dependency>
28 <dependency>
29 <groupId>org.springframework.boot</groupId>
30 <artifactId>spring-boot-starter-web</artifactId>
31 </dependency>
32 <dependency>
33 <groupId>com.mysql</groupId>
34 <artifactId>mysql-connector-j</artifactId>
35 <scope>runtime</scope>
36 </dependency>
37 <dependency>
38 <groupId>org.springframework.boot</groupId>
39 <artifactId>spring-boot-starter-test</artifactId>
40 <scope>test</scope>
41 </dependency>
42 <dependency>
43 <groupId>org.springframework.boot</groupId>
44 <artifactId>spring-boot-devtools</artifactId>
45 <scope>test</scope>
46 </dependency>
47 <!--Добавим зависимость для поддержки Spring Data Rest-->
48 <dependency>
49 <groupId>org.springframework.boot</groupId>
50 <artifactId>spring-boot-starter-data-rest</artifactId>
51 </dependency>
52 </dependencies>
53
54 <build>
55 <plugins>
56 <plugin>
57 <groupId>org.springframework.boot</groupId>
58 <artifactId>
59 spring-boot-maven-plugin
60 </artifactId>
61 </plugin>
62 </plugins>
63 </build>
64
65</project>
В прошлом уроке мы задавали вопрос о DAO имплементациях. Нужно ли их так много?
Но тот же вопрос можно применить и к контроллерам! Нужно ли для каждой сущности писать маппинги(ну там GetMapping, PostMapping и т.д.) для CRUD операций?
Действительно, зачем? Ведь код методов в контроллере для совершения простых CRUD операций тоже чаще всего будет почти одинаковым для разных сущностей.
Spring может сам создать эти методы за кулисами!
Всё что нам нужно, это создать интерфейсы расширяющие JpaRepository
для сущностей, а спринг сам предоставит нам адреса, которые мы писали в GetMapping, PostMapping и т.д. по которым мы можем совершать CRUD операции. Адреса эти формируются автоматически по имени класса, который мы передали в JpaRepository<[По имени этого класса],Integer>
.
Например, для JpaRepository<Actor, Integer>
Spring Data Rest сгенерирует адреса /actors, /actors/{actorId} и т.д. для разных HTTP методов.
Также важно упомянуть что в JSON ответах от таких сгенерированных REST методов можно увидеть некоторые метаданные. Например, по какой ссылке был сделан запрос или количество переданных объектов и т.д.
1package com.SpringBootApps.firstSpringBootDataRestCRUDApp.dao;
2
3import org.springframework.data.jpa.repository.JpaRepository;
4
5
6//Как уже было сказано адреса формируются автоматически по имени класса,
7//который мы передали в JpaRepository<[По имени этого класса],Integer>.
8public interface ActorRepository extends JpaRepository<Actor, Integer> {
9}
Давайте же протестируем созданные обработчики.
В таблице actor
сейчас три актера:

Давайте выберем из БД всех актеров GET запросом с помощью автоматически сгенерированного с помощью Spring Data Rest адреса /actors
.

Как видим, все актеры успешно были получены.
При этом, как уже упоминалось, были присланы также некоторые метаданные. Например, можно увидеть, что JSON каждого актера содержит ссылку по которой можно получить доступ к нему.
Также на скриншоте снизу можно увидеть метаданные о страницах – количество актеров на странице (три), номер страницы (нулевая страница), размер страницы (на странице может быть всего 20 актеров). То есть актеры разбиваются на страницы. Пока сильно не будем углубляться, что такое страницы и как с ними взаимодействовать.
Давайте теперь выберем из БД одного конкретного актера GET запросом с помощью автоматически сгенерированного с помощью Spring Data Rest адреса /actors/{actorId}
.

Как видим, актер с id два был успешно выбран из БД и прислан в ответ на GET запрос. Также с метаданными.
Давайте теперь добавим в БД нового актера POST запросом с помощью автоматически сгенерированного с помощью Spring Data Rest адреса /actors
. Для этого пишем в body данные в формате JSON, которые мы хотим добавить в БД.

Выше видим, что в результате выполнения POST запроса был получен код успешного выполнения операции – 201
. Ниже можно увидеть, что актер успешно добавился в БД.

Давайте теперь обновим в БД актера PUT запросом с помощью автоматически сгенерированного с помощью Spring Data Rest адреса /actors/{actorId}
. Для этого пишем в body данные в формате JSON, которыми мы хотим обновить актера с id, который указывается в конце адреса.

Выше видим, что в результате выполнения PUT запроса был получен код успешного выполнения операции – 201
. Ниже можно увидеть, что актер с id четыре успешно обновился в БД.

Давайте теперь удалим из БД актера DELETE запросом с помощью автоматически сгенерированного с помощью Spring Data Rest адреса /actors/{actorId}
. Для этого пишем в конце адреса id актера, которого мы хотим удалить.

Выше видим, что в результате выполнения DELETE запроса был получен код успешного выполнения операции – 201
. Ниже можно увидеть, что актер с id четыре успешно удалился из БД.

Еще раз заметим. Все эти ссылки были фактически ПОДАРЕНЫ нам средствами Spring Data Rest. Это может серьезно сэкономить время если нам нужны простейшие crud операции.
Доп. конфигурация Spring Boot Data Rest приложения
А что если нам нужно чтобы Spring Data Rest не генерировал автоматически некоторые адреса для CRUD?
Что если мы хотим написать их код вручную в контроллере (например, для POST и DELETE)? То есть нам не нужны простейшие POST и DELETE операции по адресу /actors
, мы хотим написать чуть более сложные обработчики для этого адреса вручную в контроллере.
Для этого можно просто отключить генерацию адресов для POST и DELETE в классе, который реализует RepositoryRestConfigurer
переопределяя метод configureRepositoryRestConfiguration
.
1package com.SpringBootApps.firstSpringBootDataCRUDApp.config;
2
3import org.springframework.context.annotation.Configuration;
4import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
5import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
6import org.springframework.http.HttpMethod;
7
8@Configuration
9public class MyDataRestConfig implements RepositoryRestConfigurer {
10
11 @Override
12 public void configureRepositoryRestConfiguration(
13 RepositoryRestConfiguration config, CorsRegistry cors) {
14
15 //здесь в массив передаем не нужные для генерации HTTP методы
16 HttpMethod[] theUnsupportedActions={HttpMethod.POST, HttpMethod.DELETE};
17
18 config.getExposureConfiguration()
19 //Ниже пишем класс, который мы передавали
20 //в JpaRepository<Actor, Integer> на основе
21 //которого генерировались методы для CRUD.
22 .forDomainType(Actor.class)
23 //Передаем в методы ниже созданный массив.
24 .withItemExposure((metadata, httpMethods) ->
25 httpMethods.disable(theUnsupportedActions))
26 .withCollectionExposure((metadata, httpMethods) ->
27 httpMethods.disable(theUnsupportedActions));
28
29 //Все. Автоматическая генерация адресов для совершения
30 //Post и Delete запросов над сущностью actor отключена.
31
32 }
33}
Дополнительные материалы
Следующие уроки
Что такое Docker и зачем он нужен?
13
мин.
Docker Hub: назначение и использование
17
мин.
Сборка Java приложения в Docker
20
мин.