Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use @ validated annotation exception to return JSON value

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article focuses on "how to use @ validated annotation exception return JSON value way", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Now let the editor take you to learn how to use @ validated annotation exception to return JSON value.

Catalogue

@ validated comment exception returns JSON value

Unified handling of parameter errors and exceptions using @ Valid annotations

The @ validated annotation exception returns the JSON value @ ControllerAdvicepublic class ValidParamExceptionHandler {@ ExceptionHandler (value = Exception.class) @ ResponseBody public Map allExceptionHandler (Exception e) {Map map = new HashMap (2); if (e instanceof BindException) {BindException ex = (BindException) e; BindingResult bindingResult = ex.getBindingResult (); StringBuilder errMsg = new StringBuilder (bindingResult.getFieldErrors (). Size () * 16) ErrMsg.append ("Invalid request:"); for (int I = 0; I

< bindingResult.getFieldErrors().size() ; i++) { if(i >

0) {errMsg.append (",");} FieldError error = bindingResult.getFieldErrors (). Get (I); errMsg.append (error.getField () + ":" + error.getDefaultMessage ());} map.put ("errcode", 500); map.put ("errmsg", errMsg.toString ()) } else {map.put ("errcode", 500); map.put ("errmsg", e.getMessage ());} return map;}

(1) here @ ControllerAdvice is annotated. @ ControllerAdvice is an enhanced version of @ Controller and is usually used with @ ExceptionHandler.

If you annotate @ Controller, exception handling only works on methods in the current controller class, but with @ ControllerAdvice, it works globally.

(2) enter the exception class class object you want to capture in the @ ExceptionHandler annotation

Unified handling of parameter errors and exceptions using @ Valid annotations

When we use springboot as the micro-service framework for agile development, we need to verify the transmitted data in order to ensure the security of the transmitted data, but in previous development, developers spend a lot of time verifying parameters in tedious judgment statements such as if else, which not only slows down our development speed, but also writes code with a lot of redundant code. In order to decouple the verification logic of the parameters from the business logic of the code, Java provides us with @ Valid annotation to help us verify the parameters, decoupling the business logic and the parameter verification logic to a certain extent, and increasing the simplicity and readability of the code.

There is a spring validation parameter verification framework in springboot, which is similar to @ valid in use. I will not repeat it here. This article mainly explains the unified treatment of errors caused by the failure of parameter verification in the use of @ valid.

First of all, a brief introduction to the unified handling of exceptions in micro-service development. The @ RestControllerAdvice annotation in spring can obtain exceptions with @ controller annotation classes, and handle exceptions together through @ ExceptionHandler (MyException.class) annotations. Examples are as follows:

/ * * General exception interception handler class (all controller exceptions are intercepted by default by aspect) * / @ Slf4j@RestControllerAdvicepublic class CommonExceptionHandler {/ * unified exception management method for runtime exceptions * @ param e * @ return * / @ ExceptionHandler (FlyException.class) / / FlyException class inherits from RuntimeException public ResponseEntity handlerException (FlyException e) {Map result = new HashMap (1) Result.put ("message", e.getMessage ()); return ResponseEntity.status (e.getCode ()) .body (result);}

Unified handling of exceptions is achieved through the combined use of the annotation @ RestControllerAdvice and the annotation @ ExceptionHandler, and then displayed in a friendly manner at the front end.

Examples of using @ Valid annotations are as follows:

@ PostMapping public ResponseEntity save (@ Valid BrandCreateRequestDto dto, BindingResult bindingResult) {/ / determine whether there is a parameter error if (bindingResult.hasErrors ()) {/ / get the parameter set List fieldErrorList = bindingResult.getFieldErrors (); Map result = new HashMap (fieldErrorList.size ()) FieldErrorList.forEach (error-> {/ / store the wrong parameter name and error reason in the map collection result.put (error.getField (), error.getDefaultMessage ();}); return ResponseEntity.status (HttpStatus.BAD_REQUEST.value ()) .body (result);} brandService.save (dto) Return ResponseEntity.status (HttpStatus.CREATED.value (). Build ();}

The @ Valid annotation does simplify our original parameter validation problem, but if we have multiple handler to deal with, don't we have to write such redundant code every time. By looking at the implementation mechanism of @ valid (not described here), a MethodArgumentNotValidException exception will be thrown when parameter verification fails (this exception will be thrown when parameters annotated with {@ code @ Valid} fail validation):

/ * * Exception to be thrown when validation on an argument annotated with {@ code @ Valid} fails. * * @ author Rossen Stoyanchev * @ since 3.1 * / @ SuppressWarnings ("serial") public class MethodArgumentNotValidException extends Exception {private final MethodParameter parameter; private final BindingResult bindingResult; / * Constructor for {@ link MethodArgumentNotValidException}. * @ param parameter the parameter that failed validation * @ param bindingResult the results of the validation * / public MethodArgumentNotValidException (MethodParameter parameter, BindingResult bindingResult) {this.parameter = parameter; this.bindingResult = bindingResult;}

According to our expectation, we only need to catch the MethodArgumentNotValidException exception in the original defined unified exception handling class, and then analyze and handle its error message. The code is as follows:

/ * * check exception handling methods for method parameters * / @ ExceptionHandler (MethodArgumentNotValidException.class) public ResponseEntity handlerNotValidException (MethodArgumentNotValidException exception) {log.debug ("begin resolve argument exception"); BindingResult result = exception.getBindingResult (); Map maps; if (result.hasErrors ()) {List fieldErrors = result.getFieldErrors (); maps = new HashMap (fieldErrors.size ()) FieldErrors.forEach (error-> {maps.put (error.getField (), error.getDefaultMessage ());});} else {maps = Collections.EMPTY_MAP;} return ResponseEntity.status (HttpStatus.BAD_REQUEST) .body (maps);}

However, after testing, we will find that it is ineffective to catch and handle the exception. This may be one of the problems encountered by me and everyone. After analyzing the source code of the execution process of @ Valid, the process of transferring the data to spring is roughly as follows: the front end transfers the data to spring,spring through the http protocol, converts the stream data to Map through the HttpMessageConverter class, and then binds the parameters to the method object through the ModelAttributeMethodProcessor class. And verify the parameters with @ Valid or @ Validated annotations. The method for processing and verifying the parameters is ModelAttributeMethodProcessor.resolveArgument (...). Part of the source code is as follows:

Public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {... Public final Object resolveArgument (MethodParameter parameter, @ Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @ Nullable WebDataBinderFactory binderFactory) throws Exception {... Object attribute = null; BindingResult bindingResult = null; if (mavContainer.containsAttribute (name)) {attribute = mavContainer.getModel (). Get (name);} else {/ / Create attribute instance try {attribute = createAttribute (name, parameter, binderFactory, webRequest);} catch (BindException ex) {if (isBindExceptionRequired (parameter)) {/ / No BindingResult parameter-> fail with BindException throw ex } / / Otherwise, expose null/empty value and associated BindingResult if (parameter.getParameterType () = = Optional.class) {attribute = Optional.empty ();} bindingResult = ex.getBindingResult ();}} / / for parameter binding and if (bindingResult = = null) {/ / binding and data validation of a pair of property objects; / / skipped if binding properties failed using the constructor. WebDataBinder binder = binderFactory.createBinder (webRequest, attribute, name); if (binder.getTarget ()! = null) {if (! mavContainer.isBindingDisabled (name)) {bindRequestParameters (binder, webRequest);} / / A pair of binding parameters failed to be verified, and the result information is given to the bindingResult object validateIfApplicable (binder, parameter) / / if the result of getting the parameter binding contains error information, throw an exception if (binder.getBindingResult () .hasErrors () & & isBindExceptionRequired (binder, parameter)) {throw new BindException (binder.getBindingResult ()) } / / Value type adaptation, also covering java.util.Optional if (! parameter.getParameterType (). IsInstance (attribute)) {attribute = binder.convertIfNecessary (binder.getTarget (), parameter.getParameterType (), parameter);} bindingResult = binder.getBindingResult ();} / / Add resolved attribute and BindingResult at the end of the model Map bindingResultModel = bindingResult.getModel (); mavContainer.removeAttributes (bindingResultModel); mavContainer.addAllAttributes (bindingResultModel); return attribute;}

By looking at the source code, when there is an error message in BindingResult, a BindException exception will be thrown. View the BindException source code as follows:

/ * Thrown when binding errors are considered fatal. Implements the * {link BindingResult} interface (and its super-interface {@ link Errors}) * to allow for the direct analysis of binding errors. * *

As of Spring 2.0, this is a special-purpose class. Normally, * application code will work with the {@ link BindingResult} interface, * or with a {@ link DataBinder} that in turn exposes a BindingResult via * {@ link org.springframework.validation.DataBinder#getBindingResult ()}. * * @ author Rod Johnson * @ author Juergen Hoeller * @ author Rob Harrop * @ see BindingResult * @ see DataBinder#getBindingResult () * @ see DataBinder#close () * / @ SuppressWarnings ("serial") public class BindException extends Exception implements BindingResult {private final BindingResult bindingResult; / * Create a new BindException instance for a BindingResult. * @ param bindingResult the BindingResult instance to wrap * / public BindException (BindingResult bindingResult) {Assert.notNull (bindingResult, "BindingResult must not be null"); this.bindingResult = bindingResult;}

We find that BindException implements the BindingResult interface (BindResult is a general interface for binding results, and BindResult inherits from the Errors interface), so the exception class has all the relevant information about BindingResult, so we can analyze and handle the error results by capturing the exception class. The code is as follows:

/ * * check exception handling methods for method parameters * / @ ExceptionHandler (BindException.class) public ResponseEntity handlerNotValidException (BindException exception) {log.debug ("begin resolve argument exception"); BindingResult result = exception.getBindingResult (); Map maps; if (result.hasErrors ()) {List fieldErrors = result.getFieldErrors (); maps = new HashMap (fieldErrors.size ()) FieldErrors.forEach (error-> {maps.put (error.getField (), error.getDefaultMessage ());});} else {maps = Collections.EMPTY_MAP;} return ResponseEntity.status (HttpStatus.BAD_REQUEST) .body (maps);}

In this way, we have solved the exception handling of parameter verification for requests whose content-type type is form (form). The reason why the MethodArgumentNotValidException exception does not work is mainly because it is related to the data format (content-type) initiated by the request, and different HttpMessageConverter (http parameter converters) are used to handle different data format spring. The following is a brief introduction to HttpMessageConverter:

The transmission of HTTP requests and responses is a byte stream, meaning that browsers and servers communicate through byte streams. However, use the methods in the Spring,controller class to return pure String types or other Java built-in objects. How to convert an object into a byte stream for transmission?

There is a problem of converting a byte stream to a java object when the message arrives at SpringMVC and goes out of SpringMVC. In SpringMVC, it is handled by HttpMessageConverter.

When the request message comes to the java, it will be encapsulated into an ServletInputStream input stream for us to read the message. The response message outputs the response message through an output stream of ServletOutputStream. The http request and the corresponding processing process are as follows:

Springmvc uses different message converters for different data formats. The following is the built-in message converter for springmvc:

From this, we can see that when using json as the transport format, springmvc uses MappingJacksonHttpMessageConverter message converter, and the underlying layer throws a MethodArgumentNotValidException exception when verifying the parameters, so we need to manage BindException and MethodArgumentNotValidException exceptions uniformly. The final code is shown below:

/ * * check exception handling for method parameters (valid for form submission only, invalid for submission in json format) * if it is a form type submission, spring will use the form data handling class (BindException exception will be thrown when a parameter verification error is made) * / @ ExceptionHandler (BindException.class) public ResponseEntity handlerBindException (BindException exception) {return handlerNotValidException (exception) } / * check the exception handling method for method parameters (the method submitted by the front end is json format will be handled by this exception class if an exception occurs) * when submitted in json format Spring will use a data converter for json data for processing (error in parameter verification is MethodArgumentNotValidException exception thrown) * / @ ExceptionHandler (MethodArgumentNotValidException.class) public ResponseEntity handlerArgumentNotValidException (MethodArgumentNotValidException exception) {return handlerNotValidException (exception) } public ResponseEntity handlerNotValidException (Exception e) {log.debug ("begin resolve argument exception"); BindingResult result; if (e instanceof BindException) {BindException exception = (BindException) e; result = exception.getBindingResult ();} else {MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e; result = exception.getBindingResult ();} Map maps If (result.hasErrors ()) {List fieldErrors = result.getFieldErrors (); maps = new HashMap (fieldErrors.size ()); fieldErrors.forEach (error-> {maps.put (error.getField (), error.getDefaultMessage ());});} else {maps = Collections.EMPTY_MAP } return ResponseEntity.status (HttpStatus.BAD_REQUEST) .body (maps);}

In this way, our unified handling of parameter verification exceptions is perfectly solved.

Here, I only uniformly handle the exceptions for parameter verification, that is, the response code returned to the front end is 400 (parameter format error). For custom exceptions or other exceptions, you can handle exceptions in this way.

At this point, I believe you have a better understanding of "how to use @ validated annotation exception return JSON value". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report