【问题标题】:Springboot show error message for invalid date (YearMonth) formats: eg 2020-15Spring Boot 显示无效日期(年月)格式的错误消息:例如 2020-15
【发布时间】:2020-04-03 09:57:05
【问题描述】:

我有一个带有 Spring Boot 的项目,如果给定的日期格式不正确,我想显示错误响应。 正确的格式是 yyyy-MM (java.time.YearMonth),但如果有人发送 2020-13、2020-111 或 2020-1,我想显示一条消息。

当我添加了一个自定义验证器时,调试器会带着一个有效的请求而不是一个不正确的请求进入那里。我还尝试将 message.properties 与typeMismatch.project.startdate=Please enter a valid date. 一起使用,但我也没有在我的响应正文中看到该消息。 似乎应用程序不理解我的错误请求,然后总是抛出一个空正文的 BAD REQUEST,这并不奇怪,因为它不是有效日期。

谁能解释我如何在这些错误值的响应中显示错误消息? 还是没有其他方法可以使用 String 并将其转换为 YearMonth 对象,以便我可以显示 catch 并显示错误消息?

请求对象:

@Getter
@Setter    
public class Project {
    @NotNull(message = "mandatory")
    @DateTimeFormat(pattern = "yyyy-MM")
    private YearMonth startdate;
}

控制器:

@RestController
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public class ProjectController {

    @PostMapping(value = "/project", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Project newProject(@Valid @RequestBody Project newProject) {
        return projectService.newProject(newProject);
    }
}

异常处理程序:

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @SneakyThrows
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        headers.add("Content-Type", "application/json");

        ObjectMapper mapper = new ObjectMapper();

        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach(error -> {
            String name;
            if (error instanceof FieldError)
                name = ((FieldError) error).getField();
            else
                name = error.getObjectName();
            String errorMessage = error.getDefaultMessage();
            errors.put(name, errorMessage);
        });

        return new ResponseEntity<>(mapper.writeValueAsString(errors), headers, status);
    }
}

【问题讨论】:

    标签: spring-boot validation date-format


    【解决方案1】:

    好的,我提出了一个对我来说可行的解决方案。 我已为以后发现此线程并遇到与我相同的问题的人添加了以下解决方案。

    使用简单的正则表达式模式创建自定义验证器:

    @Target({ FIELD })
    @Retention(RUNTIME)
    @Constraint(validatedBy = YearMonthValidator.class)
    @Documented
    public @interface YearMonthPattern {
    
        String message() default "{YearMonth.invalid}";
    
        Class<?>[] groups() default { };
    
        Class<? extends Payload>[] payload() default { };
    
    }
    
    public class YearMonthValidator implements ConstraintValidator<YearMonthPattern, String> {
    
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            Pattern pattern = Pattern.compile("^([0-9]{4})-([0-9]{2})$");
            Matcher matcher = pattern.matcher(value);
            try {
                return matcher.matches();
            } catch (Exception e) {
                return false;
            }
        }
    }
    

    更新请求对象:

    @Getter
    @Setter
    public class Project {
        @NotNull(message = "mandatory")
        @YearMonthPattern
        private String startdate;
        
        public YearMonth toYearMonth(){
            return YearMonth.parse(startdate);
        }
    }
    

    DateTimeFormat 注释被我们新的自定义验证器替换,而不是 YearMonth,而是一个字符串。现在可以执行验证器注释,因为到 YearMonth 的映射不会再失败了。

    我们还添加了一个新方法,在 Spring 验证请求正文后将 String startdate 转换为 YearMonth,因此我们可以在服务中将其用作 YearMonth,而不必每次都转换它。

    现在当我们发送一个请求正文时:

    {
        "startdate": "2020-1"
    }
    

    我们收到了一个不错的 400 错误请求,响应如下:

    {
        "endDate": "{YearMonth.invalid}"
    }
    

    【讨论】:

      猜你喜欢
      • 2011-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-03
      • 1970-01-01
      • 2022-07-20
      • 2012-06-18
      • 2015-02-26
      相关资源
      最近更新 更多