RequestBodyAdvice 和 ResponseBodyAdvice具有什么功能呢?

欣喜 SpringBoot 发布时间:2024-04-28 16:24:48 阅读数:6953 1
下文笔者讲述RequestBodyAdvice 和 ResponseBodyAdvice的功能简介说明,如下所示

RequestBodyAdvice

RequestBodyAdvice 
    是SpringMVC4.2提供一个接口
    它允许请求体被读取并转换为对象
    并将处理结果对象作为@RequestBody参数
       或
     @HttpEntity方法参数

ResponseBodyAdvice

ResponseBodyAdvice
   是SpringMVC4.1提供一个接口
  它允许在运行@ResponseBody后自定义返回数据
    或
  将返回@ResponseEntity的Controller Method
    在写入主体前使用 HttpMessageConverter进行自定义操作

RequestBodyAdvice 和 ResponseBodyAdvice源码简介

//RequestBodyAdvice源码

public interface RequestBodyAdvice {
    boolean supports(MethodParameter var1, Type var2, Class<? extends HttpMessageConverter<?>> var3);

    HttpInputMessage beforeBodyRead(HttpInputMessage var1, MethodParameter var2, Type var3, Class<? extends HttpMessageConverter<?>> var4)    
   throws IOException;
    Object afterBodyRead(Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5);

    @Nullable
    Object handleEmptyBody(@Nullable Object var1, HttpInputMessage var2, MethodParameter var3, Type var4,         
     Class<? extends HttpMessageConverter<?>> var5);
}
 
//AbstractMessageConverterMethodArgumentResolver
 // readWithMessageConverters()方法调用了这个接口的方法。

@Nullable
    protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType)       
          throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
        boolean noContentType = false;

        MediaType contentType;
        try {
            contentType = inputMessage.getHeaders().getContentType();
        } catch (InvalidMediaTypeException var16) {
            throw new HttpMediaTypeNotSupportedException(var16.getMessage());
        }

        if (contentType == null) {
            noContentType = true;
            contentType = MediaType.APPLICATION_OCTET_STREAM;
        }

        Class<?> contextClass = parameter.getContainingClass();
        Class<T> targetClass = targetType instanceof Class ? (Class)targetType : null;
        if (targetClass == null) {
            ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
            targetClass = resolvableType.resolve();
        }

        HttpMethod httpMethod = inputMessage instanceof HttpRequest ? ((HttpRequest)inputMessage).getMethod() : null;
        Object body = NO_VALUE;

        AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage message;
        try {
            label94: {
                message = new AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage(inputMessage);
                Iterator var11 = this.messageConverters.iterator();

                HttpMessageConverter converter;
                Class converterType;
                GenericHttpMessageConverter genericConverter;
                while(true) {
                    if (!var11.hasNext()) {
                        break label94;
                    }

                    converter = (HttpMessageConverter)var11.next();
                    converterType = converter.getClass();
                    genericConverter = converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter)converter : null;
                    if (genericConverter != null) {
                        if (genericConverter.canRead(targetType, contextClass, contentType)) {
                            break;
                        }
                    } else if (targetClass != null && converter.canRead(targetClass, contentType)) {
                        break;
                    }
                }

                if (message.hasBody()) {
                    HttpInputMessage msgToUse = this.getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
                    body = genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :                 
                                                                           converter.read(targetClass, msgToUse);
                    body = this.getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
                } else {
                    body = this.getAdvice().handleEmptyBody((Object)null, message, parameter, targetType, converterType);
                }
            }
        } catch (IOException var17) {
            throw new HttpMessageNotReadableException("I/O error while reading input message", var17, inputMessage);
        }

        if (body != NO_VALUE) {
            LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
                String formatted = LogFormatUtils.formatValue(body, !traceOn);
                return "Read \"" + contentType + "\" to [" + formatted + "]";
            });
            return body;
        } else if (httpMethod != null && SUPPORTED_METHODS.contains(httpMethod) && (!noContentType || message.hasBody())) {
            throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
        } else {
            return null;
        }
    }

RequestBodyAdvice示例

首先一个实现类实现RequestBodyAdvice
后在类上加上注解@ControllerAdvice
两者缺一不可
   如:
     有些请求请求体已经做加密处理
     可在此将请求体解密。

   核心的方法就是 supports,该方法返回的boolean值
    决定运行beforeBodyRead方法
 
注意事项:
    不用加@Component注解
 
//@Component
@ControllerAdvice
public class RequestBodyDecrypt implements RequestBodyAdvice {
    @Reference
    private EquipmentService equipmentService;
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;  // 必须为true才会执行beforeBodyRead和afterBodyRead方法
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type,                                     Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
        String equipmentNo = httpInputMessage.getHeaders().getFirst("equipmentNo"); // 从请求头中获取equipmentNo,getFirst()方法根据请求头的名称获取值
        String privateKey = null;
        list<EquipmentDTO> mapList = equipmentService.getByEquipmentNo(equipmentNo);
        if (mapList.size() > 0) {
            EquipmentDTO equipmentDTO = mapList.get(0);
            privateKey = equipmentDTO.getProdPriKey();
        }

        // 提取数据
        InputStream is = httpInputMessage.getBody(); // 从HTTPInputMessage中获取请求体,得到字节输入流
        byte[] data = new byte[is.available()];
        is.read(data);
        String dataStr = new String(data, StandardCharsets.UTF_8);
        JSONObject json = JSONObject.parseObject(dataStr);
        String decrypt = null;
        try {
            decrypt = //解密逻辑
        } catch (Exception e) {
            throw new RuntimeException("数据错误");
        }     // 将解密后的请求体封装到HttpInputMessage中返回
        return new DecodedHttpInputMessage(httpInputMessage.getHeaders(), new ByteArrayInputStream(decrypt.getBytes(StandardCharsets.UTF_8)));
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type,                                               Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type,                                                Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }

    static class DecodedHttpInputMessage implements HttpInputMessage {
        HttpHeaders headers;
        InputStream body;

        public DecodedHttpInputMessage(HttpHeaders headers, InputStream body) {
            this.headers = headers;
            this.body = body;
        }

        @Override
        public InputStream getBody() throws IOException {
            return body;
        }

        @Override
        public HttpHeaders getHeaders() {
            return headers;
        }
    }
}

ResponseBodyAdvice示例

//对返回结果加密
//定义一个实现类实现ResponseBodyAdvice
//后在类上加上注解@ControllerAdvice

@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Result> {
 
    /**
     * 加密串一
     */
    private static String md5_keyone;
    /**
     * 加密串二
     */
    private static String md5_keytwo;
 
    @PostConstruct
    public void init() throws Exception {
        md5_keyone = Utils.PT.getProps("md5_keyone");
        md5_keytwo = Utils.PT.getProps("md5_keytwo");
    }
 
    /**
     * 判断支持的类型
     * 
     * @param returnType
     * @param converterType
     * @return
     * @see org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#supports(org.springframework.core.MethodParameter,
     *      java.lang.Class)
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return returnType.getMethod().getReturnType().isAssignableFrom(Result.class);
    }
 
    /**
     * 对于结果进行加密
     * 
     * @param body
     * @param returnType
     * @param selectedContentType
     * @param selectedConverterType
     * @param request
     * @param response
     * @return
     * @see org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#beforeBodyWrite(java.lang.Object,
     *      org.springframework.core.MethodParameter,
     *      org.springframework.http.MediaType, java.lang.Class,
     *      org.springframework.http.server.ServerHttpRequest,
     *      org.springframework.http.server.ServerHttpResponse)
     */
    @Override
    public Result beforeBodyWrite(Result body, MethodParameter returnType,org.springframework.http.MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,ServerHttpResponse response) {
        String jsonString = JSON.toJSONString(body.getData());
        System.out.println(jsonString);
        // 第一次加密
        String data_encode_one = //加密
        // 第二次加密
        String data_encode_two = //加密
        body.setToken(data_encode_two);
        return body;
    }
 
}
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaFramework/SpringBoot/202404/8120.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者