我正在Spring REST Controller类中进行验证。如果参数对象本身发生约束冲突,则不会执行我的自定义约束验证器。
期望
请求
{
fieldA: "2020-01-05",fieldB: "2020-01-02",fieldC: ""
}
响应:
{
errors: [
"Field C is mandatory","Invalid date range"
]
}
当前-场景1
请求
{
fieldA: "2020-01-05",fieldC: ""
}
响应:
{
errors: [
"Field C is mandatory"
]
}
当前-方案2
请求
{
fieldA: "2020-01-05",fieldC: "<some-value>"
}
响应:
{
errors: [
"Invalid date range."
]
}
这是代码段
SomeAPI.java
@RestController
@RequestMapping(value = "/")
@Validated
public class SomeAPI {
@PostMapping
@SomeValidation
public ResponseEntity<Map<String,Object>> saveSomething(@Valid @RequestBody SomeForm form) {
return new ResponseEntity<>(responseBody,HttpStatus.CREATED);
}
}
SomeForm.java
public class SomeForm {
@NotNull(message = "Field A is mandatory")
private LocalDate fieldA;
@NotNull(message = "Field B is mandatory")
private LocalDate fieldB;
@NotBlank(message = "Field C is mandatory")
private String fieldC;
// Setters and getters
}
SomeValidation.java
@Documented
@Constraint(validatedBy = SomeValidator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface SomeValidation {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
class SomeValidator implements ConstraintValidator<SomeValidation,Object[]> {
private static Logger logger = LoggerFactory.getLogger(SomeValidator.class);
@Override
public boolean isValid(Object[] value,ConstraintValidatorContext context) {
context.disableDefaultConstraintViolation();
SomeForm form = (SomeForm) value[0];
boolean valid = true;
if (!isValid(form)) {
valid = false;
context.buildConstraintViolationWithTemplate("Invalid date range").addConstraintViolation();
}
return valid;
}
private boolean isValid(SomeForm form) {
logger.info("isValid");
return form.getFieldA().isBefore(form.getFieldB());
}
}
APIExceptionHandler.java
@ControllerAdvice
public class APIExceptionHandler extends ResponseEntityExceptionHandler {
private static final String TIMESTAMP_KEY = "timestamp";
private static final String STATUS_KEY = "status";
private static final String ERRORS_KEY = "errors";
@Override
protected ResponseEntity<Object> handleBindException(BindException ex,HttpHeaders headers,HttpStatus status,WebRequest request) {
Map<String,Object> body = new LinkedHashMap<>();
body.put(TIMESTAMP_KEY,new Date());
body.put(STATUS_KEY,status.value());
List<String> errors = ex.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage)
.collect(Collectors.toList());
body.put(ERRORS_KEY,errors);
return new ResponseEntity<>(body,headers,status);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,status.value());
List<String> errors = ex.getBindingResult().getallErrors().stream().map(ObjectError::getDefaultMessage)
.collect(Collectors.toList());
body.put(ERRORS_KEY,status);
}
@ExceptionHandler({ ConstraintViolationException.class })
public ResponseEntity<Object> handleConstraintViolation(final ConstraintViolationException ex,final WebRequest request) {
Map<String,HttpStatus.BAD_REQUEST.value());
List<String> errors = ex.getconstraintViolations().stream().map(ConstraintViolation::getMessage)
.collect(Collectors.toList());
body.put(ERRORS_KEY,new HttpHeaders(),HttpStatus.BAD_REQUEST);
}
}