Before:
Don’t read for the sake of reading. Read with questions and thinking.
In Web development, we often need to verify various parameters, which is a tedious and important thing, for many people, when doing parameter verification, there will be the following types of processing.
Jilt pot type
If the caller sends the error, it is the caller’s problem, not the service’s problem. Throw 500 errors and let them reflect on it:
A model type
I write as many if statements as there are parameters to check, and write a friendly message if the check fails, such as:
Tool type
Write a general tool for parameter verification, and then call the tool method for verification for each parameter received in the request. If the verification fails, the verification result will be returned to the caller:
Semi-automatic type
To understand, the SpringMVC comprehensive friends all know that it supports Bean Validation, so you can through the use of the javax.mail. Validation. The annotation under constraints package, such as @ NotNull @ @ Max Min, To realize data verification by the framework.
First, add hibernate-Validator dependencies (SpringBoot has already added them automatically for us).
<dependency> <groupId> org.hibernate.validator </groupId> <artifactId> hibernate-validator </artifactId> <version> 6.0.10. Final < / version > < / dependency >Copy the code
Then, annotate the fields of the parameter object:
Finally, add the @valid annotation to the parameter object in the Controller and process the validation result:
Tip: If your parameter is not an object, be sure to annotate Controller with @Validated!
This way, each Controller method has to process the result, which is also a hassle.
Project analysis
All of the above methods have disadvantages:
First of all, parameter verification is a very important thing, the client should hold the first line of defense, and the server should take a mistrustful attitude, do parameter verification. Otherwise, if the parameters of illegal request are small, the user experience will be affected or garbage data will be generated. If large, it will drag across the whole system!
Secondly, checking all the parameters manually is rather tedious, error-prone and So boring
Finally, it’s better to do it with tools, but you have to make the tools elegant.
So, is there a better solution? The answer is: yes!
Best practices
In fact, the above semi-automatic solution, as long as further, you can achieve full automatic!
What if, in the semi-automatic example above, we did not process the validation results in the Controller method? The answer is, it throws an exception:
So, if we do global uniform exception handling, wouldn’t we be able to implement automatic verification and return the results we want? So we can do this:
@controllerAdvice public class GlobalExceptionHandler {/** Handle exception exception */ @ExceptionHandler @responseBody public ResultBean <? > handleValidationException (BindException e) {/ / get the String MSG = um participant etBindingResult () getAllErrors () stream (). The map ( DefaultMessageSourceResolvable ::getDefaultMessage) .collect( Collectors .joining(","
));
log.warn(
"MSG: {}"
, msg);
returnResultBean .fail(msg); }}Copy the code
However, if you only handle the exception BindException, you will find that sometimes this scheme works and sometimes it “breaks.” Why is that? Spring will throw different exceptions for different parameter parsing methods, and these exceptions have no inheritance relationship, and the way to obtain verification results from exceptions is different.
To sum up, there are the following exceptions to handle:
The object parameter receives the RequestBody, RequestBody:
MethodArgumentNotValidException
Request parameters bind to object parameters:
BindException
Common parameters:
ConstraintViolationException required parameters are missing: ServletRequestBindingException so complete processing method should be like this: @ExceptionHandler ({ ConstraintViolationException .class, MethodArgumentNotValidException .class, ServletRequestBindingException .class, BindException .class}) @ResponseBody public ResultBean <? > handleValidationException( Exception e) { String msg =""
;
if (e instanceof
MethodArgumentNotValidException
) {
MethodArgumentNotValidException
t = (
MethodArgumentNotValidException
) e;
msg = t.getBindingResult().getAllErrors().stream()
.map(
DefaultMessageSourceResolvable
::getDefaultMessage)
.collect(
Collectors
.joining(
","
));
} else if (e instanceof
BindException
) {
BindException
t = (
BindException
) e;
msg = t.getBindingResult().getAllErrors().stream()
.map(
DefaultMessageSourceResolvable
::getDefaultMessage)
.collect(
Collectors
.joining(
","
));
} else if (e instanceof
ConstraintViolationException
) {
ConstraintViolationException
t = (
ConstraintViolationException
) e;
msg = t.getConstraintViolations().stream()
.map(
ConstraintViolation
::getMessage)
.collect(
Collectors
.joining(
","
));
} else if (e instanceof
MissingServletRequestParameterException
) {
MissingServletRequestParameterException
t = (
MissingServletRequestParameterException
) e;
msg = t.getParameterName() +
"Can't be empty."
;
} else if (e instanceof
MissingPathVariableException
) {
MissingPathVariableException
t = (
MissingPathVariableException
) e;
msg = t.getVariableName() +
"Can't be empty."
;
} else {
msg =
"Required parameter missing"
;
}
log.warn(
"MSG: {}"
, msg);
return
ResultBean
.fail(msg);
}Copy the code
With the addition of this global exception handler, parameter verification can be done automatically! Experience the feeling of flying ~~
However, if the user accesses a page from a browser and the parameter verification fails, the unified exception handler returns json text. The average user would be confused by this text.
So how do you make a request to open a page return an error page and an Ajax request return JSON? My example code has been shown, interested can understand.
———————
Copyright notice: This article is the blogger’s original article, reprint please attach the blog link!