Validation in Spring MVC in Controllers or Service Layer?
In one of our previous projects, we had huge forms with very complex logic which meant a lot of validating code. So we used a third kind of solution. For every controller, we autowired a helper class. Example:
myview <-> MyController <- MyService <- MyDAO
^
|
MyHelper
Controllers
handled the view resolving.Services
handled mapping from dto-s to model objects for view and vice versa,DAO-s
handled database transactions and,Helpers
handled everything else including validation.
If now someone would have wanted to change the frontend from web to something else, it would have been a lot easier and at the same time, we didn't over-bloat the service implementation classes.
A common approach is to do validation on both places. But if you are talking about @Valid, from my experience it is nicer to put on Controllers level.
It also depends what kind of validation logic we are talking about. Let's say you have a bean:
@Data
public class MyBean {
@NotNull private UUID someId;
@NotEmpty private String someName;
}
It would make sense for this bean to be annotated with @Valid
on the controller level so it doesn't even reach the service. There is no benefit to putting the @Valid
on the service method, because why would you propagate it further while you can immediately in the controller decide if it is that kind of valid or not.
Then there is a second type of validation: business logic validation. Let's say for the same bean that the someId property is a timeUUid and its timestamp needs to be at most 2 days after some event occurred, in other case, the bean should be discarded by the service.
That seems like a business logic validation case, because by just looking at the bean, you wouldn't be able to validate it, unless you apply some logic to it.
Since both approaches to validation actually validate different things, it is obvious to see that each of your MVC components - Model, View and Controller, do their own validation and it should be reasonable about what it validates without introducing dependency to the other components.
As for showing the error to the user, yes, the Errors object is indeed intended to be used for bean validation at controller level, but you can design some filter that catches exceptions on any level and then pretty formats it for the user. There are many approaches to it, and I am not sure if Spring prescribes that any is better than the other.
Depending on different resolve mechanism (as in, for example, jstl or jackson or something else), you would probably be inclined to deal with validation in a different way. For example, a traditional jstl view resolver would nicely work with a contraption that uses Errors, while a jackson resolver would probably work nicer with a combination of @ResponseBody and some filter that catches errors and puts them in a predefined error part of the response object.