问题
I am using Spring Data Rest and all is going well.
I want to apply validation (JSR 303) on my entities.
The spring docs say I can intercept application events in a few ways (none of which I can get to work, and right now spring.io seems to be down).
However, I did get it working by putting
@Validated
on my respository:
@Validated
@RepositoryRestResource(collectionResourceRel = "workers", path = "workers")
public interface WorkerRepository extends PagingAndSortingRepository<Worker, Long> {
}
And it will throw an exception. Problem is it's a spring exception and not even the root one, and I need to basically take the validations and turn them into a custom entity payload of:
{
"foo": "must be of length 10",
"baz": "Must match pattern '[A-Z]+'"
}
So, in a nutshell, I want to
- Validate an entity using JSR 303
- Produce an HTTP entity with 400: and a mapping or field -> error
What's the most straightforward way to do this? I also stumbled on this:
Detected @ExceptionHandler methods in repositoryRestExceptionHandler
Which seems suspiciously useful. When I checkout that class it looks like what I need for sure
回答1:
Spring data rest is not applying bean validation automatically. If you want bean validation you need to register the appropriate validator in spring data rest.
The following configuration is doing the trick for me:
@Configuration
public class MyValidationConfiguration extends RepositoryRestConfigurerAdapter {
@Bean
@Primary
/**
* Create a validator to use in bean validation - primary to be able to autowire without qualifier
*/
Validator validator() {
return new LocalValidatorFactoryBean();
}
@Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
Validator validator = validator();
//bean validation always before save and create
validatingListener.addValidator("beforeCreate", validator);
validatingListener.addValidator("beforeSave", validator);
}
}
With this configuration every entity that has bean validation constraints is validated before update and create.
(This is not enabling bean validation for custom controllers in a spring-data-rest project - but this is not what your are asking for - is it?)
- the spring data rest validation mechanism is throwing a
RepositoryConstraintViolationException
- which is handled by
RepositoryRestExceptionHandler
- which results in the errors being serialized as
RepositoryConstraintViolationExceptionMessage
So a validation error response would result in a 400 Bad Request
with a body like this:
{
"errors" : [ {
"entity" : "MyEntity",
"message" : "may not be null",
"invalidValue" : "null",
"property" : "price"
}, {
"entity" : "MyEntity",
"message" : "may not be empty",
"invalidValue" : "",
"property" : "name"
}
}
Custom Controllers
You can leverage your spring-data-rest registered validators using the spring-data-rest entity lifecycle application events. e.g. you can emit a BeforeSaveEvent in your custom controller to trigger all your event handlers and also the validating event listener that spring-data-rest provides. Thus you can achieve to get the same errors and error representation.
回答2:
in general it will be a painful, you must to take a full control under hibernate list of constrains violations. MethodValidationPostProcessor can help you to trigger validation process for @Validated interfaces/classes. If your return object or argument is your complex class it must be marked as @Valid also.
Next article can help you a little bit: https://dzone.com/articles/method-validation-spring-31
Unfortunately I've not found anything like spring-webmvc has DataBinding mechanism that reports Errors with conversion/validation problems in one place (and it looks it cannot be reusable somehow)
来源:https://stackoverflow.com/questions/36437823/spring-data-rest-validation-exception-mapper-confusing