JavaRush /Курсы /Модуль 5. Spring /Краткое содержание предыдущих лекций

Краткое содержание предыдущих лекций

Модуль 5. Spring
16 уровень , 1 лекция
Открыта

Перед тем, как начать писать код, важно определить архитектурный стиль приложения, основные его компоненты и их взаимодействие. Любой опытный программист подвтердит, что плохо спроектированная архитектура подобна дома без фундамента: может и стоять, но недолго.


1. Архитектурный обзор

Выбор архитектурного стиля

Мы разрабатываем приложение в стиле монолитной архитектуры. Да-да, никакого хайпа микросервисов на данном этапе. Почему? Потому что наше приложение будет сравнительно небольшим, и переключаться на микросервисы нет смысла. Всё будет собрано в одном проекте, но мы разделим его на логические модули.

Компоненты приложения

Составляющие нашего приложения можно разделить на несколько ключевых блоков:

  1. REST API: будем предоставлять интерфейс взаимодействия через HTTP-запросы для внешних пользователей (например, фронтенда).
  2. Сервисный слой (бизнес-логика): здесь мы сосредоточим основной функционал приложения, такой как обработка данных, валидация и управление транзакциями.
  3. База данных: для хранения информации.
  4. Безопасность: защитим доступ к нашим данным и функционалу.

Вот пример схемы компонента:


+-------------------+
|   REST API        |
|-------------------|
|  Контроллеры      |
+-------------------+
        |
        v
+-------------------+
| Сервисный слой    |
|-------------------|
|  Бизнес-логика    |
+-------------------+
        |
        v
+-------------------+
|   Доступ к данным |
|-------------------|
|  JPA Репозитории  |
+-------------------+
        |
        v
+-------------------+
|  База данных      |
|-------------------|

2. Дизайн REST API

Для начала вспомним, что REST API — это интерфейс, позволяющий взаимодействовать с приложением через HTTP-запросы. Основные принципы REST:

  1. Ресурсоориентированность: всё в нашем приложении рассматривается как ресурс. Например, пользователь — это ресурс /users.
  2. Методы HTTP: для разных операций используются разные методы:
    • GET для получения данных.
    • POST для создания новых данных.
    • PUT для обновления данных.
    • DELETE для удаления данных.
  3. Статусные коды HTTP: Сервер возвращает статус выполнения операции. Например:
    • 200 OK для успешного ответа.
    • 201 Created для успешного создания ресурса.
    • 404 Not Found для отсутствующего ресурса.

Проектирование эндпоинтов

Мы планируем создать базовый CRUD для пользователей. Вот предполагаемые эндпоинты:

Метод URL Описание
GET /users Получить список пользователей
GET /users/{id} Получить пользователя по ID
POST /users Создать нового пользователя
PUT /users/{id} Обновить данные пользователя
DELETE /users/{id} Удалить пользователя

Вот как это выглядит в контроллере:


@RestController
@RequestMapping("/users")
public class UserController {

    @GetMapping
    public List<User> getAllUsers() {
        // Возвращает список всех пользователей
    }

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        // Получает пользователя по id
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        // Создает нового пользователя
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        // Обновляет данные пользователя
    }

    @DeleteMapping("/{id}")
    public ResponseEntity
    deleteUser(@PathVariable Long id) {
        // Удаляет пользователя
    }
}

3. Безопасность приложения

Реализация аутентификации с использованием Spring Security

Вы уже знаете, что Spring Security позволяет нам добавлять правила аутентификации и авторизации.

1. Подключение зависимости: В pom.xml добавляем:


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. Создание конфигурации безопасности:


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/users/**").authenticated()
            .anyRequest().permitAll()
            .and()
            .httpBasic(); // Используем базовую аутентификацию
    }
}

Здесь мы защищаем эндпоинты /users/**, а остальные оставляем доступными для всех.


4. Работа с базой данных

Проектирование базы данных

Для нашего приложения нам потребуется таблица users. Пример структуры (ER-диаграмма):

Поле Тип данных Описание
id BIGINT Идентификатор
name VARCHAR Имя пользователя
email VARCHAR Электронная почта
password VARCHAR Пароль

Имплементация сущностей

Создаём сущность User с использованием JPA-аннотаций:


@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

    // Геттеры и сеттеры
}

Репозиторий для работы с базой

Используем Spring Data JPA для работы с данными:


@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
}

Теперь мы можем выполнять CRUD-операции с пользовательскими данными через этот интерфейс.

Конфигурация подключения

В application.properties настраиваем подключение к базе:


spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update

Взаимодействие компонентов

Итак, как всё это соединяется?

  1. REST-запрос приходит в контроллер.
  2. Контроллер вызывает соответствующий метод из сервисного слоя.
  3. Сервисный слой взаимодействует с репозиториями и возвращает результат.
  4. Контроллер возвращает ответ клиенту.

Вот пример цепочки:


@RestController
public class UserController {

    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}

@Service
public class UserService {

    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUserById(Long id) {
        return userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
    }
}

На этом этапе архитектура приложения готова. Далее мы погрузимся в декомпозицию задач проекта, чтобы понять, как лучше организовать работу над оставшимися модулями.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ