Skip to content
Open

Dev #11

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 76 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/> <!-- lookup parent from repository -->
<relativePath/>
</parent>
<groupId>com.emobile</groupId>
<artifactId>SpringToDo</artifactId>
Expand All @@ -19,18 +19,92 @@
</properties>

<dependencies>

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


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


<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.4</version>
</dependency>


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

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


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


<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>


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

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>


<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>


<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>11.3.2</version>
</dependency>

<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
<version>11.3.2</version>
</dependency>


</dependencies>


<build>
<plugins>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* Главный класс приложения Spring Boot для ToDo.
* Запускает приложение.
*
* @author PavelOkhrimchuk
*/
@SpringBootApplication
public class SpringToDoApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.emobile.springtodo.configuration;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* Конфигурация OpenAPI для документации API.
* Настроена информация о версии и описании API.
*
* @author PavelOkhrimchuk
*/
@Configuration
public class OpenApiConfig {

/**
* Создает объект OpenAPI с информацией о приложении.
*
* @return OpenAPI объект с настроенной информацией.
*/
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Spring ToDo API")
.version("1.0")
.description("API для управления задачами ToDo"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.emobile.springtodo.configuration;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;

/**
* Конфигурация Redis кеширования.
* Включает создание и настройку CacheManager для работы с Redis в приложении.
*
* @author PavelOkhrimchuk
*/
@Configuration
@EnableCaching
public class RedisConfig {

/**
* Создает и настраивает CacheManager для работы с Redis.
*
* @param connectionFactory Фабрика подключения к Redis.
* @return CacheManager, использующий Redis для кеширования.
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig();
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(cacheConfig)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.emobile.springtodo.controller;

import com.emobile.springtodo.dto.ErrorResponse;
import com.emobile.springtodo.exception.InvalidToDoException;
import com.emobile.springtodo.exception.ToDoNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
* Глобальный обработчик исключений для всего приложения.
* Обрабатывает различные исключения, такие как ToDoNotFoundException и InvalidToDoException,
* а также ошибки валидации.
*
* @author PavelOkhrimchuk
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

/**
* Строит ответ на основе переданного исключения, статуса HTTP и ошибки валидации.
*
* @param ex Исключение, которое было выброшено.
* @param status Статус HTTP-ответа.
* @param request HTTP-запрос, содержащий путь.
* @param validationErrors Ошибки валидации (если имеются).
* @return Ответ с ошибкой.
*/
private ResponseEntity<ErrorResponse> buildResponse(Exception ex, HttpStatus status, HttpServletRequest request, Map<String, String> validationErrors) {
log.error("Exception: {} - {}", ex.getClass().getSimpleName(), ex.getMessage(), ex);

ErrorResponse response = ErrorResponse.builder()
.timestamp(LocalDateTime.now())
.status(status.value())
.error(status.getReasonPhrase())
.message(ex.getMessage())
.path(request.getRequestURI())
.build();

if (validationErrors != null && !validationErrors.isEmpty()) {
response.setDetails(validationErrors);
}

return ResponseEntity.status(status).body(response);
}

/**
* Обработчик исключения ToDoNotFoundException.
* @param ex Исключение, выброшенное при отсутствии задачи.
* @param request HTTP-запрос.
* @return Ответ с ошибкой 404.
*/
@ExceptionHandler(ToDoNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ToDoNotFoundException ex, HttpServletRequest request) {
return buildResponse(ex, HttpStatus.NOT_FOUND, request, null);
}

/**
* Обработчик исключения InvalidToDoException.
* @param ex Исключение, выброшенное при недействительной задаче.
* @param request HTTP-запрос.
* @return Ответ с ошибкой 400.
*/
@ExceptionHandler(InvalidToDoException.class)
public ResponseEntity<ErrorResponse> handleInvalidToDo(InvalidToDoException ex, HttpServletRequest request) {
return buildResponse(ex, HttpStatus.BAD_REQUEST, request, null);
}

/**
* Обработчик исключений валидации.
* @param ex Исключение с ошибками валидации.
* @param request HTTP-запрос.
* @return Ответ с ошибками валидации.
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationExceptions(MethodArgumentNotValidException ex, HttpServletRequest request) {
Map<String, String> validationErrors = new HashMap<>();
for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
validationErrors.put(fieldError.getField(), fieldError.getDefaultMessage());
}

log.error("Validation failed: {}", validationErrors);

return buildResponse(ex, HttpStatus.BAD_REQUEST, request, validationErrors);
}

/**
* Обработчик общих исключений.
* @param ex Общее исключение.
* @param request HTTP-запрос.
* @return Ответ с ошибкой 500.
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneral(Exception ex, HttpServletRequest request) {
return buildResponse(ex, HttpStatus.INTERNAL_SERVER_ERROR, request, null);
}
}
Loading