#java #spring #hibernate #rest #validation
#java #весна #впасть в спящий режим #отдых #проверка
Вопрос:
У меня есть API, который проверяет и создает пользователя. Когда я не ввожу адрес электронной почты в теле запроса, я получаю
{
"timestamp": "2020-11-26T13:55:40.116 00:00",
"status": 400,
"error": "Bad Request",
"message": "Validation failed for object='user'. Error count: 1",
"path": "/api/users"
}
Я хочу изменить сообщение на более понятную ошибку типа «адрес электронной почты должен быть не нулевым».
Вот как выглядит свойство моей модели:
@NotNull
private String email;
А вот и метод моего контроллера:
@PostMapping("/users")
public ResponseEntity<User> addUser(@RequestBody @Valid User user) {
User savedUser = manager.save(user);
URI uri = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
return ResponseEntity.ok(savedUser);
}
Я пытался установить пользовательское сообщение в @NotNull
аннотации, но сообщение не меняется. Также, когда выдается ошибка, консоль показывает это сообщение:
2020-11-26 15:09:11.460 WARN 7137 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public org.springframework.http.ResponseEntity<pl.vemu.socialApp.entities.User> pl.vemu.socialApp.controllers.UserController.addUser(pl.vemu.socialApp.entities.User) throws pl.vemu.socialApp.exceptions.user.UserWithEmailAlreadyExistException: [Field error in object 'user' on field 'email': rejected value [xsars.pl]; codes [Email.user.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.email,email]; arguments []; default message [email],[Ljavax.validation.constraints.Pattern$Flag;@2a50b33,.*]; default message [must be a well-formed email address]] ]
Как установить сообщение в ответ в формате json?
Как избавиться от этого сообщения в консоли? Другие ошибки не отображают сообщение в консоли.
Ответ №1:
Проблема в том, что Spring по умолчанию не отправляет ошибки при привязке. Чтобы включить его, вы должны добавить server.error.include-binding-errors=always
в свой application.properties.
Ответ №2:
Вместо того чтобы полагаться на "message"
свойство, вы можете использовать "defaultMessage"
свойство.
Вы можете установить пользовательское сообщение об ошибке @NotNull
в аннотации.
@NotNull(message = "Name cannot be null")
private String name;
@NotNull(message = "email cannot be null")
@NotEmpty(message = "email cannot be empty")
private String email;
Если проверка не удалась для поля, spring
эти пользовательские сообщения будут установлены в "defaultMessage"
свойстве
Как вы сказали в комментариях, что не смогли найти DefaultMessage, другим подходом (возможно, грязным подходом) было бы вручную создать тело ответа, вы можете сослаться на следующий пример кода для его создания:
@PostMapping("saveEmployee")
public ResponseEntity<?> eat(@RequestBody @Valid Employee employee, Errors errors) {
if (errors.hasFieldErrors()) {
FieldError fieldError = errors.getFieldError();
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(fieldError.getDefaultMessage());
}
return ResponseEntity.ok(employee);
}
FieldError#getDefaultMessage()
отобразит значение message
атрибута в @NotNull(message = "email can't be null")
Комментарии:
1. Как вернуть DefaultMessage в json по запросу?
2. spring по умолчанию включит его, если проверка завершится неудачей.
3. Хм, в моем случае это не так
4. @Vemu тогда, возможно, вам следует создать ответ вручную. проверьте обновленный ответ
5. это работает, но также связывает логику проверки с реализацией контроллера.
Ответ №3:
ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body("email must be not null");
и HttpStatus.UNPROCESSABLE_ENTITY
замените подходящим кодом ошибки.
Комментарии:
1. Я хочу, чтобы валидатор spring обработал проверку модели
Ответ №4:
используйте также @Validated на уровне класса плюс используйте пользовательский обработчик ошибок, подобный этому
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException e) {
String violations = e.getConstraintViolations().stream().map(cv -> cv.getConstraintDescriptor().getMessageTemplate()).toList().toString();
return new ResponseEntity<>
("not valid due to validation errors: " violations, HttpStatus.BAD_REQUEST);
}
}
Ответ №5:
Вы можете переопределить сообщения об ошибках по умолчанию в BindException.
@ControllerAdvice
public class BindExceptionHandler {
@ExceptionHandler(BindException.class)
@ResponseBody
public String handleBindExceptionHandler(BindException exception) {
return "Your message like 'email must be not null'";
}
}