RequestBodyAdvice 和 ResponseBodyAdvice具有什么功能呢?
下文笔者讲述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; } }
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。