This is the 12th day of my participation in the August Text Challenge.More challenges in August

Bloggers have recently encountered requests for BodyAdvice in Spring while using annotations.

1 Overview about RequestBodyAdvice

/**
 * Allows customizing the request before its body is read and converted into an
 * Object and also allows for processing of the resulting Object before it is
 * passed into a controller method as an {@code @RequestBody} or an
 * {@code HttpEntity} method argument.
 *
 * <p>Implementations of this contract may be registered directly with the
 * {@code RequestMappingHandlerAdapter} or more likely annotated with
 * {@code @ControllerAdvice} in which case they are auto-detected.
 *
 * @author Rossen Stoyanchev
 * @since4.2 * /
public interface RequestBodyAdvice {

	boolean supports(MethodParameter methodParameter, Type targetType, Class
       > converterType);


	Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class
       > converterType);

	HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class
       > converterType) throws IOException;

	Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class
       > converterType);

}
Copy the code

As you can see from the above source code, this interface is a new interface in Spring4.2. According to the data, this interface is mainly used to enhance the processing of parameters before and after the request body.

Look at the source of beforeBodyRead method, see RequestResponseBodyAdviceChain classes implement this interface, and call the method, and continue to see down, found AbstractMessageConverterMethodArgumentR Esolver readWithMessageConverters method call this method in an abstract class. The abstract class implements the interface HandlerMethodArgumentResolver processing parameters are given.

.for(HttpMessageConverter<? > converter :this.messageConverters) { Class<HttpMessageConverter<? >> converterType = (Class<HttpMessageConverter<? >>) converter.getClass();if (converter instanceofGenericHttpMessageConverter) { GenericHttpMessageConverter<? > genericConverter = (GenericHttpMessageConverter<? >) converter;if (genericConverter.canRead(targetType, contextClass, contentType)) {
						if (logger.isDebugEnabled()) {
							logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
						}
						if(inputMessage.getBody() ! =null) {
                            // Call the implementation method under the interface
							inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
							body = genericConverter.read(targetType, contextClass, inputMessage);
							body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
						}
						else {
							body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
						}
						break; }}...Copy the code

HttpMessageConverter () {HttpMessageConverter ();

The realization of the AbstractMessageConverterMethodArgumentResolver abstract class subclasses

  • HttpEntityMethodProcessorThe method argument to handle controller is HttpEntity or RequestEntity)
  /**
 * Resolves {@link HttpEntity} and {@link RequestEntity} method argument values
 * and also handles {@link HttpEntity} and {@link ResponseEntity} return values.
 **/
Copy the code
  • RequestPartMethodArgumentResolverThe handler parameters are @requestPart and MultipartFile and Part
/**
 * Resolves the following method arguments:
 * <ul>
 * <li>Annotated with {@code @RequestPart}
 * <li>Of type {@link MultipartFile} in conjunction with Spring's {@link MultipartResolver} abstraction
 * <li>Of type {@codeJavax.servlet.http. Part} in conjunction with servlet 3.0 multipart requests * </ul> **/
Copy the code
  • RequestResponseBodyMethodProcessorThe handler parameter is RequestBody
/**
 * Resolves method arguments annotated with {@code @RequestBody} and handles return
 * values from methods annotated with {@code @ResponseBody} by reading and writing
 * to the body of the request or response with an {@link HttpMessageConverter}.
 **/
Copy the code

From the above knowable, when using HandlerMethodArgumentResolver interface, can the request parameter parsed pretreatment, aftertreatment. And the supports method overrides to return True to enable parameter handling.

2 About the use of RequestBodyAdvice

1 Preparing the Environment

Build a SpringBoot environment that can run.

1 Preparing Documents

1 application.yml

server:
  port: 8081
spring:
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/test
Copy the code

2 entity class

@Data
public class User {

    private String id;

}
Copy the code

3 Controller Controller

@RestController
@RequestMapping("/consumer")
@Slf4j
public class ConsumerController {

    @RequestMapping("/query")
    public String queryById(@RequestBody User user) {
        log.info("Request parameters =={}", user.toString());
        log.info("Response parameter =={}"."H1 style of id");

        return "<h1>" + user.toString() + "<h1>"; }}Copy the code

Create an interceptor class that implements the RequestBodyAdvice interface

@ControllerAdvice
@Slf4j
public class LogRequestBodyAdvice implements RequestBodyAdvice {
	
    // Whether to enable interception True Enable false Disable
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class
       > aClass) {
        return true;
    }

    /** * Request body parsing before processing *@param httpInputMessage
     * @param methodParameter
     * @param type
     * @param aClass
     * @return
     * @throws IOException
     */
    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class
       > aClass) throws IOException {

        // Common scenarios are as follows: 1 Log recording 2 Content encryption and decryption 3 Check whether paging is enabled
        log.info("Intercepted request parameter = {}",methodParameter.toString());
        Method method=methodParameter.getMethod();
        log.info("Request body before reading ={}==>{}==>{}==>{}",method.getDeclaringClass().getSimpleName(),method.getName(),type.toString(),aClass.getName());
        return httpInputMessage;
    }

    /** * Request body parse after processing *@param o
     * @param httpInputMessage
     * @param methodParameter
     * @param type
     * @param aClass
     * @return* /
    @Override
    public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class
       > aClass) {
        Method method=methodParameter.getMethod();
        log.info("Request body read after ={}.{}:{}",method.getDeclaringClass().getSimpleName(),method.getName(),o.toString());
        return o;
    }

    /** * Processing has no arguments *@param o
     * @param httpInputMessage
     * @param methodParameter
     * @param type
     * @param aClass
     * @return* /
    @Override
    public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class
       > aClass) {
        Method method=methodParameter.getMethod();
        log.info("No arguments ={}.{}",method.getDeclaringClass().getSimpleName(),method.getName());
        return o;
  }
Copy the code

3 Use the Postman tool

1 Postman sends a request

2 Project Logs

3 summary

The interception before and after the parsing of the request body parameters can better help realize business functions without invading the code logic. Common usage scenarios are as follows:

  • 1 Recording Logs

  • 2 Content encryption and decryption

  • 3 Check whether paging is enabled