Библиотека Java разработчика
10.5K subscribers
1.17K photos
594 videos
58 files
1.51K links
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate.


По всем вопросам @evgenycarter

РКН clck.ru/3KoGeP
Download Telegram
🚑 Global Exception Handling: Красиво падаем

Представьте: пользователь запрашивает ID, которого нет.

🔴Плохой сценарий: Сервер выплевывает стэктрейс на 500 строк, раскрывая внутренности БД. Статус 500 Internal Server Error. Клиент в шоке.
🔴Хороший сценарий: Клиент получает аккуратный JSON: {"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.
🔴Маппите Java-исключения (EntityNotFoundException) на HTTP-статусы (404 Not Found).

#SpringBoot #Java #ExceptionHandling #BestPractices

📲 Мы в MAX

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍61🔥1
🎛 Конфигурация Spring Boot: YAML, Профили и Секреты

Хардкодить настройки (порты, пароли, 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=prod

4️⃣ Секреты (Никаких паролей в Git!)

Самая страшная ошибка - закоммитить application-prod.yaml с паролем от боевой БД в репозиторий. ☠️

Правило: В файлах храним только дефолтные/безопасные значения. Реальные пароли передаем через Переменные Окружения (Environment Variables).

Spring Boot имеет строгий приоритет загрузки. Переменные окружения OS имеют более высокий приоритет, чем файлы.

🔴В файле: spring.datasource.password=secret
🔴В переменной ОС: SPRING_DATASOURCE_PASSWORD=SuperSecurePass123

Spring увидит переменную в системе и проигнорирует то, что написано в файле. Ваш секрет в безопасности.

🔥 Итог

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