🚑 Global Exception Handling: Красиво падаем
Представьте: пользователь запрашивает ID, которого нет.
🔴 Плохой сценарий: Сервер выплевывает стэктрейс на 500 строк, раскрывая внутренности БД. Статус 500 Internal Server Error. Клиент в шоке.
🔴 Хороший сценарий: Клиент получает аккуратный JSON:
Раньше, чтобы добиться хорошего сценария, приходилось писать
В Spring Boot есть элегантное решение -
🛡 Что это такое?
Это перехватчик (Interceptor), который работает по принципу Аспектно-Ориентированного Программирования (AOP). Он "сидит" над всеми вашими контроллерами и ловит исключения, которые вылетели из них, прежде чем они дойдут до пользователя.
🛠 Как настроить? (3 шага)
1. Создаем DTO для ошибки
Нам нужен красивый формат ответа, чтобы фронтенд всегда знал, чего ожидать.
2. Создаем Глобальный Обработчик
Используем аннотацию
Внутри класса мы пишем методы-обработчики с аннотацией
3. Бросаем исключения в Сервисе
Теперь в коде сервиса можно не бояться и просто бросать ошибки. Обработчик их поймает.
⚡ Почему это круто?
1. Чистота кода: В контроллерах нет
2. Единообразие: Весь API возвращает ошибки в одинаковом формате.
3. Безопасность: Вы контролируете, какой текст ошибки увидит пользователь, и скрываете системные детали.
🔥 Итог
🔴 Не используйте
🔴 Создайте один класс с
🔴 Маппите Java-исключения (
#SpringBoot #Java #ExceptionHandling #BestPractices
📲 Мы в MAX
👉@BookJava
Представьте: пользователь запрашивает ID, которого нет.
{"status": 404, "message": "User not found"}.Раньше, чтобы добиться хорошего сценария, приходилось писать
try-catch в каждом методе контроллера. Это ужасно.В Spring Boot есть элегантное решение -
@ControllerAdvice.🛡 Что это такое?
Это перехватчик (Interceptor), который работает по принципу Аспектно-Ориентированного Программирования (AOP). Он "сидит" над всеми вашими контроллерами и ловит исключения, которые вылетели из них, прежде чем они дойдут до пользователя.
🛠 Как настроить? (3 шага)
1. Создаем DTO для ошибки
Нам нужен красивый формат ответа, чтобы фронтенд всегда знал, чего ожидать.
public record ErrorResponse(int statusCode, String message, LocalDateTime timestamp) {}
2. Создаем Глобальный Обработчик
Используем аннотацию
@RestControllerAdvice. Это тот же @ControllerAdvice, но он автоматически добавляет @ResponseBody ко всем ответам (мы же пишем REST API).Внутри класса мы пишем методы-обработчики с аннотацией
@ExceptionHandler.
@RestControllerAdvice
public class GlobalExceptionHandler {
// 1. Ловим конкретную ошибку (например, сущность не найдена)
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(EntityNotFoundException ex) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(404, ex.getMessage(), LocalDateTime.now()));
}
// 2. Ловим ошибки валидации (если передали кривой JSON)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
String errors = ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.collect(Collectors.joining(", "));
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(400, errors, LocalDateTime.now()));
}
// 3. Ловим всё остальное (Fallback)
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(500, "Произошла внутренняя ошибка", LocalDateTime.now()));
}
}
3. Бросаем исключения в Сервисе
Теперь в коде сервиса можно не бояться и просто бросать ошибки. Обработчик их поймает.
public User getUser(Long id) {
return repo.findById(id)
.orElseThrow(() -> new EntityNotFoundException("User with id " + id + " not found"));
}
⚡ Почему это круто?
1. Чистота кода: В контроллерах нет
try-catch блоков. Только "счастливый путь" (happy path).2. Единообразие: Весь API возвращает ошибки в одинаковом формате.
3. Безопасность: Вы контролируете, какой текст ошибки увидит пользователь, и скрываете системные детали.
🔥 Итог
try-catch в контроллерах.@RestControllerAdvice.EntityNotFoundException) на HTTP-статусы (404 Not Found).#SpringBoot #Java #ExceptionHandling #BestPractices
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1🔥1
🎛 Конфигурация Spring Boot: YAML, Профили и Секреты
Хардкодить настройки (порты, пароли, URL-ы) в Java-коде - это моветон. Если вам нужно поменять порт сервера, вы не должны перекомпилировать приложение.
Spring Boot следует принципу: "Код отдельно, настройки отдельно".
1️⃣ Properties vs YAML
По умолчанию Spring создает
Весь мир переходит на YAML (
Было (
Стало (
Меньше дублирования, глазам приятнее.
2️⃣ Как достать настройки в коде?
Способ А: Простой (
Подходит для точечных настроек.
Способ Б: Профессиональный (
Если настроек много (например, настройки почты или API), лучше собрать их в отдельный класс. Это дает типизацию и проверку данных!
Теперь вы просто внедряете
3️⃣ Профили (Profiles) - Киллер-фича
На локальной машине у вас H2 база данных, а на продакшене - PostgreSQL. Как не менять конфиги вручную?
Используйте Профили.
Вы создаете несколько файлов рядом с основным
🔴
🔴
В основном файле вы указываете, какой профиль активен по умолчанию:
А при запуске на сервере вы просто передаете флаг, и Spring подхватит нужный файл, перетерев дефолтные настройки:
4️⃣ Секреты (Никаких паролей в Git!)
Самая страшная ошибка - закоммитить
Правило: В файлах храним только дефолтные/безопасные значения. Реальные пароли передаем через Переменные Окружения (Environment Variables).
Spring Boot имеет строгий приоритет загрузки. Переменные окружения OS имеют более высокий приоритет, чем файлы.
🔴 В файле:
🔴 В переменной ОС:
Spring увидит переменную в системе и проигнорирует то, что написано в файле. Ваш секрет в безопасности.
🔥 Итог
1. Используйте YAML вместо properties.
2. Группируйте настройки через
3. Разделяйте среды через Профили (
4. Никогда не храните боевые пароли в файлах. Используйте ENV vars.
#SpringBoot #Configuration #YAML #DevOps #BestPractices
📲 Мы в MAX
👉@BookJava
Хардкодить настройки (порты, пароли, URL-ы) в Java-коде - это моветон. Если вам нужно поменять порт сервера, вы не должны перекомпилировать приложение.
Spring Boot следует принципу: "Код отдельно, настройки отдельно".
1️⃣ Properties vs YAML
По умолчанию Spring создает
application.properties. Это старый формат (ключ=значение).Весь мир переходит на YAML (
.yaml или .yml). Он читабельнее и поддерживает иерархию.Было (
.properties):
spring.datasource.url=jdbc:postgresql://localhost/db
spring.datasource.username=admin
server.port=8080
Стало (
.yaml):
server:
port: 8080
spring:
datasource:
url: jdbc:postgresql://localhost/db
username: admin
Меньше дублирования, глазам приятнее.
2️⃣ Как достать настройки в коде?
Способ А: Простой (
@Value)Подходит для точечных настроек.
@Value("${server.port}")
private int port;
Способ Б: Профессиональный (
@ConfigurationProperties)Если настроек много (например, настройки почты или API), лучше собрать их в отдельный класс. Это дает типизацию и проверку данных!
@ConfigurationProperties(prefix = "mail")
public record MailConfig(String host, int port, String username) {}
Теперь вы просто внедряете
MailConfig в свои сервисы, как обычный бин.3️⃣ Профили (Profiles) - Киллер-фича
На локальной машине у вас H2 база данных, а на продакшене - PostgreSQL. Как не менять конфиги вручную?
Используйте Профили.
Вы создаете несколько файлов рядом с основным
application.yaml:application-dev.yaml (для разработки)application-prod.yaml (для боевого сервера)В основном файле вы указываете, какой профиль активен по умолчанию:
spring:
profiles:
active: dev # По умолчанию грузим dev-настройки
А при запуске на сервере вы просто передаете флаг, и Spring подхватит нужный файл, перетерев дефолтные настройки:
java -jar app.jar -Dspring.profiles.active=prod4️⃣ Секреты (Никаких паролей в Git!)
Самая страшная ошибка - закоммитить
application-prod.yaml с паролем от боевой БД в репозиторий. ☠️Правило: В файлах храним только дефолтные/безопасные значения. Реальные пароли передаем через Переменные Окружения (Environment Variables).
Spring Boot имеет строгий приоритет загрузки. Переменные окружения OS имеют более высокий приоритет, чем файлы.
spring.datasource.password=secretSPRING_DATASOURCE_PASSWORD=SuperSecurePass123Spring увидит переменную в системе и проигнорирует то, что написано в файле. Ваш секрет в безопасности.
🔥 Итог
1. Используйте YAML вместо properties.
2. Группируйте настройки через
@ConfigurationProperties.3. Разделяйте среды через Профили (
dev, test, prod).4. Никогда не храните боевые пароли в файлах. Используйте ENV vars.
#SpringBoot #Configuration #YAML #DevOps #BestPractices
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍1🤔1