Что Мы Хотим Сделать? 🤔
Примените проверку к объектам, которые мы получаем на контроллерах конечных точек от клиентов.
Какое Первое Решение Приходит На Ум? 🧠
это просто, верно? напишите функции, которые проверяют эти объекты.
Допустим, у нас есть конечная точка для добавления новых отправлений. 🚚
Давайте начнем с классов DTO (Объект передачи данных)
@RequiredArgsConstructor @Getter public class ShipmentComponentDTO { private final String productCode; }
@RequiredArgsConstructor @Getter public class ShipmentDTO { private final String productCode; private final int count; private final ListshipmentComponentDTOs; }
Сейчас, контроллер
@RestController public class ShipmentController { @PostMapping("/shipment/add") public ResponseEntityaddShipment(@RequestBody ShipmentDTO shipmentDTO){ if (shipmentDTO.getProductCode() == null) return ResponseEntity.badRequest().body("Product code can't be null"); if (shipmentDTO.getCount() <= 0) return ResponseEntity.badRequest().body("Count can't be negative or zero"); if (!allComponentsAreValid(shipmentDTO)) return ResponseEntity.badRequest().body("Component product code can't be null"); return ResponseEntity.ok(":)"); } private boolean allComponentsAreValid(ShipmentDTO shipmentDTO) { List shipmentComponentDTOs = shipmentDTO.getShipmentComponentDTOs(); return shipmentComponentDTOs != null && shipmentComponentDTOs.size() > 0 && shipmentComponentDTOs. stream(). allMatch(shipmentComponentDTO -> shipmentComponentDTO.getProductCode() != null); } }
Обратите внимание на всю ту утомительную ручную работу, которую нам приходилось выполнять. 🤕
Неужели никто не может помочь нам сделать эту задачу более увлекательной? 😏
Пожалуйста, познакомьтесь с валидатором Javax. 🥳
- Он предоставляет набор аннотаций, которые используются с полями класса.
- Они действуют как ограничения.
- это поле не должно быть пустым
- этот список должен иметь минимальный размер 5
- и многое другое…
Как это сделать? 👀
Для объекта, который мы хотим проверить
- Мы аннотируем поля, которые хотим проверить, аннотациями из
javax.validation.constraints
Затем мы аннотируем параметр контроллера, который мы хотим проверить.
Затем мы должны перехватить ошибку, выданную валидатором, и вернуть правильный ответ пользователю.
Давайте закодируем это 🦾
Вот объекты DTO
@RequiredArgsConstructor @Getter public class ShipmentComponentDTO { @NotBlank(message = "Component product code can't be null") private final String productCode; // required by the javax validation code public ShipmentComponentDTO() { this.productCode = ""; } }
@RequiredArgsConstructor @Getter public class ShipmentDTO { @NotBlank(message = "Product code can't be null") private final String productCode; @Min(1) private final int count; @Size(min = 1, message = "Component product code can't be empty") @NotNull(message = "Component product code can't be null") @Valid private final ListshipmentComponentDTOs; }
Хорошо, что это были за аннотации? 👇
- Не чистый
- Это поле не может быть нулевым или пустым строка
- Минута
- это целое число должно иметь минимальное значение мы уточняем
- Размер
- размер этого массива должен быть в пределах границ мы уточняем
- не полный
- Это поле не должно быть пустым
- Действительный
- Проверьте поля в этом объекте
Итак, вот контроллер 👇
@RestController public class ShipmentController_Validation { @PostMapping("validation/shipment/add") public ResponseEntityaddShipment(@RequestBody @Validated ShipmentDTO shipmentDTO){ return ResponseEntity.ok(":)"); } }
Что это была за аннотация @Validated? 🤨
- он сообщает Spring запустить механизм проверки для этого объекта в соответствии с его аннотациями проверки (Не пустыми и т.д.)
Наконец, давайте перехватим исключение, выданное валидатором, и сгенерируем правильный ответ
@Order(Ordered.HIGHEST_PRECEDENCE) @ControllerAdvice public class ValidationAdvice{ @ResponseStatus(BAD_REQUEST) @ResponseBody @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity> methodArgumentNotValidException(MethodArgumentNotValidException ex) { BindingResult result = ex.getBindingResult(); ListfieldErrors = result.getFieldErrors(); String errorMessage = fieldErrors.get(0).getDefaultMessage(); return ResponseEntity.badRequest().body(errorMessage); } }
В заключение ✍️
- Представьте, что у вас есть API со множеством конечных точек, которые нам нужно проверить. Какой метод был бы лучше?
- Валидатор.
Код на GitHub
Оригинал: “https://dev.to/jarjanazy/validate-your-endpoints-using-spring-4l3e”