我有一个带有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);
}
}
好吧,我制定了一个对我来说可行的解决方案。我在下面添加了解决方案,供将来发现此线程并遇到与我相同问题的人使用。
使用一个简单的正则表达式模式创建一个自定义验证器:
@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注释被我们新的自定义验证器取代,并将其改为String,而不是YearMonth。现在可以执行验证器注释,因为到YearMonth的映射不会再失败了。
我们还添加了一个新方法,在Spring验证请求主体后将String startdate转换为YearMonth,这样我们就可以在服务中将其用作YearMonths,而不必每次都转换它。
现在,当我们发送带有以下内容的请求体时:
{
"startdate": "2020-1"
}
我们收到了一个不错的400坏请求,并得到了以下响应:
{
"endDate": "{YearMonth.invalid}"
}