【问题标题】:Implement validation message for default size validation实现默认大小验证的验证消息
【发布时间】:2021-06-15 22:43:41
【问题描述】:

我有想要限制大小的 DTO:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
public class CreateUserDTO {

    @NotNull
    @NotEmpty
    @Size(min=1, max=20, message = "'Login' value '${validatedValue}' must be between {min} and {max} characters long.")
    private String login;

    @NotNull
    @NotEmpty
    @Size(min=1, max=45, message = "'Email' value '${validatedValue}' must be between {min} and {max} characters long.")
    private String email;

    @NotNull
    @NotEmpty
    @Size(min=1, max=20, message = "'First name' value '${validatedValue}' must be between {min} and {max} characters long.")
    private String firstName;

    @NotNull
    @NotEmpty
    @Size(min=1, max=20, message = "'Last name' value '${validatedValue}' must be between {min} and {max} characters long.")
    private String lastName;
}

休息控制器:

    @PostMapping("/create")
    public ResponseEntity<?> create(@Valid @RequestBody CreateUserDTO dto) {

        .....

        return ok().build();
    }

知道为什么我会收到这个巨大的错误消息:

{
    "errors": [
        {
            "status": 404,
            "code": "1001",
            "title": "Not found",
            "detail": "Validation failed for argument [0] in public org.springframework.http.ResponseEntity<?> org.engine.rest.UsersController.create(org.engine.dto.CreateUserDTO): [Field error in object 'createUserDTO' on field 'login': rejected value [56dtttttttttt444444444465st]; codes [Size.createUserDTO.login,Size.login,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [createUserDTO.login,login]; arguments []; default message [login],20,1]; default message ['Login' value '56dtttttttttt444444444465st' must be between 1 and 20 characters long.]] ",
            "extra": {
                "detail": "Validation failed for argument [0] in public org.springframework.http.ResponseEntity<?> org.engine.rest.UsersController.create(org.engine.dto.CreateUserDTO): [Field error in object 'createUserDTO' on field 'login': rejected value [56dtttttttttt444444444465st]; codes [Size.createUserDTO.login,Size.login,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [createUserDTO.login,login]; arguments []; default message [login],20,1]; default message ['Login' value '56dtttttttttt444444444465st' must be between 1 and 20 characters long.]] "
            }
        }
    ]
}

【问题讨论】:

  • "56dtttttttttt444444444465st".length(); $4 ==&gt; 27。如果值不是您发送的值,请尝试使用{value} 而不是${validatedValue}
  • 请显示您如何处理此异常
  • @PeterPenzov 由于传递的输入超过 20 个字符,因此会引发验证异常。然后它由在 EngineExceptionHandler.java 中定义的 serverExceptionHandler 处理,它服务于这个响应。
  • @PeterPenzov 你用的是什么版本的spring boot/spring framework?

标签: java spring spring-boot spring-validator


【解决方案1】:

查看评论中的链接存储库,您可以添加一个新的异常处理程序来自定义与约束相关的验证错误。

现在所有未定义的异常都被路由到定义的here

您可以在EngineExceptionhandler 类中为与约束相关的错误定义异常处理程序。

类似

@ExceptionHandler(ConstraintViolationException.class)
ResponseEntity<ErrorResponseDTO> constraintValidationException(final ConstraintViolationException e) {
    List<ErrorRerponse> errors = new ArrayList<>();
    for (ConstraintViolation violation : e.getConstraintViolations()) {
        ErrorResponse error = new ErrorResponse();
        error.setTitle(violation.getPropertyPath().toString());
        error.setDetail(violation.getMessage());
        errors.add(error);
    }
    ErrorResponseDTO errorResponse = new ErrorResponseDTO();
    errorResponse.setErrors(errors);
    return new ResponseEntity<ErrorResponseDTO>(errorResponse, HttpStatus.BAD_REQUEST);
}

您可以根据需要添加更多自定义。

【讨论】:

    【解决方案2】:

    我正在使用以下ResponseEntityExceptionHandler,它对我来说很好用。

    @Order(Ordered.HIGHEST_PRECEDENCE)
    @ControllerAdvice
    public class RestExceptionHandler extends ResponseEntityExceptionHandler {
    
    
      @Override
      protected ResponseEntity<Object> handleMethodArgumentNotValid(
          MethodArgumentNotValidException ex,
          HttpHeaders headers,
          HttpStatus status,
          WebRequest request) {
        Map<String, Map<String, List<Map<String, String>>>> errors = new HashMap<>();
        ex.getBindingResult()
            .getAllErrors()
            .forEach(
                error -> {
                  String fieldName = ((FieldError) error).getField();
                  String errorMessage = error.getDefaultMessage();
                  Map<String, String> errorFields = new HashMap<>();
                  errorFields.put("field", fieldName);
                  errorFields.put("message", errorMessage);
                  Map<String, List<Map<String, String>>> errorMap = new HashMap<>();
                  errorMap.put("errors", List.of(errorFields));
                  errors.put(fieldName, errorMap);
                });
    
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
      }
    }
    

    【讨论】:

      【解决方案3】:

      简单的错误信息说明问题出在哪里

      default message ['Login' value '56dtttttttttt444444444465st' must be between 1 and 20 characters long.]
      

      由于该值,您在CreateUserDTO dto 中传递给login,请求的字符数超过了您定义的最大值(20)。由于验证失败所以抛出这个错误。

      【讨论】:

        【解决方案4】:

        你需要处理MethodArgumentNotValidException

        一个快速的实现就像

        @ExceptionHandler({ MethodArgumentNotValidException.class })
        public ResponseEntity<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
            BindingResult bindingResult = ex.getBindingResult();
            for (FieldError fieldError : bindingResult.getFieldErrors()) {
                // Do something with fieldError.getDefaultMessage();
                // Which is equivalent to 'Login' value '${validatedValue}' must be between {min} and {max} characters long.
            }
        
            for (ObjectError objectError : bindingResult.getGlobalErrors()) {
                // Do something with objectError.getDefaultMessage();
            }
        
            return ResponseEntity.ok().build();
        }
        

        【讨论】:

          【解决方案5】:

          在显示给最终用户或发送给客户端之前,您需要处理根异常并美化它。正如上面提到的答案,您可以从ResponseEntityExceptionHandler 覆盖handleMethodArgumentNotValid 方法,如下所示:

          @RestControllerAdvice
          public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {
          
              @Override
              protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                            HttpHeaders headers, HttpStatus status, WebRequest request) {
          
                  StringBuilder sb = new StringBuilder();
                  ex.getBindingResult().getAllErrors().forEach((error) -> {
                      sb.append("[");
                      sb.append(((FieldError) error).getField());
                      sb.append(" ");
                      sb.append(error.getDefaultMessage());
                      sb.append("] ");
                  });
          
              log.error("Method arg is invalid. " + sb.toString(), ex);
          
              return new ResponseEntity<>(sb.toString(), HttpStatus.BAD_REQUEST);
              }
          }
          
          

          log.error() 打印以下消息:

          // here is the message I show to the end user
          10:27:02 [ERROR] [ServiceExceptionHandler] 141: Method arg is invalid. [shareList size must be between '1' and '10'] 
          // here is the stack trace you encountered
          org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public
          ...
          [Size.eyatTransferDTO.shareList,Size.shareList,Size.java.util.List,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [eyatTransferDTO.shareList,shareList]; arguments []; default message [shareList],10,1]; default message [size must be between '1' and '10']]
          ...
          
          

          【讨论】:

            猜你喜欢
            • 2012-10-30
            • 2020-01-17
            • 2014-04-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-24
            相关资源
            最近更新 更多