springmvc Get Exception Handling for @ Requestbody Transformation

  • 2021-10-27 07:13:18
  • OfStack

1. Introducing problems

Using spring automatic @ RequestBody, you can easily convert parameters into objects. However, if there is an exception in automatic conversion, you will send HTTP exception code and error information directly by default. How can you customize your own exception?

2. Solutions

There are many ways to answer questions. One common way to answer questions is to use @ ExceptionHandler

2.1 For example, when the passed request body is JSON

Spring can be automatically packaged into one Map


@PostMapping(value = "/check",consumes = "application/json")
public ApiResult check(@RequestBody Map<String,String> paramBody) {
 // .........
}

2.2 If there is an abnormal JSON format in the request body

Then an exception occurs and you can see that it is of type com. fasterxml. jackson. core. JsonParseException (jackson is the default json parsing library for spring boot)

14:29:40.891 [http-nio-9091-exec-3] WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver - Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized character escape '[' (code 91); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized character escape '[' (code 91)

The prompt returned to the front end may be in the following format, but the default format is not easy to handle


{
    "timestamp": 1551680980906,
    "status": 400,
    "error": "Bad Request",
    "message": "JSON parse error: Unrecognized character escape '[' (code 91); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized character escape '[' (code 91)\n at [Source: (PushbackInputStream); line: 66, column: 29]",
    "path": "/check"
}

2.3 Custom Error Format Output


@ExceptionHandler(value = JsonParseException.class)
public @ResponseBody ApiResult exceptionHandler(JsonParseException e ) {
 return new ApiResult(500, " Call interface exception and parse request body JSON Format error ", null);
}

2.4 What if you still want to get the passed request body parameters

Because the request body is in the form of a stream, it can only be read once. After parsing the request body, the stream has been closed. Add request to the above code to get the request body, and you will get a closed stream. The following is a combination of online examples and practical solutions

2.4. 1 Defining an filter, caching requests


/**
 * 
 * @author Bob.chen
 * @date 2019 Year 3 Month 4 Day - Afternoon 2:10:01
 * @desc  Wrapper under the request, is the request body can be in the @ExceptionHandler Use in 
 */

@Component
public class RequestWrapperFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(new ContentCachingRequestWrapper(httpServletRequest), httpServletResponse);
    }
}

2.4. 2 Using cached requests in custom error format


@ExceptionHandler(value = JsonParseException.class)
public @ResponseBody ApiResult exceptionHandler(JsonParseException e, ServletRequest request) {
  if (request != null && request instanceof ContentCachingRequestWrapper) {
   ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
   LOG.warn("BAD_REQUEST_BODY:{}", StringUtils.toEncodedString(wrapper.getContentAsByteArray(),
     Charset.forName(wrapper.getCharacterEncoding())));
  }
  return new ApiResult(500, " Call interface exception and parse request body JSON Format error ", null);
 }

One note for @ RequestBody annotation

1. @ RequestBody annotations are used to get the data in the request body

Direct use yields key=value & key = value …, so get mode is not applicable (@ RequestBody can't get any data under get mode).

Example:


public void test1(@RequestBody String body){
 system.out.println(body);
}

Output:

username=hehe & age=20

2. After using @ RequestBody annotation,

A collection object can be created in the method, and the collection data submitted by the front end can be directly injected into the collection object of the method without creating an pojo object to encapsulate the collection.

3. If you want to automatically encapsulate the front-end submitted json string into an object

You need to import the relevant jar package for jackson and use the @ RequestBody annotation.

Note: springmvc uses MappingJacksonHttpMessageConverter to convert json data by default.

4. Use @ RequestBody

The number of front and back end parameters should be matched, and the field name should be 1.


Related articles: