当前位置: 首页 > news >正文

河北住房和城乡建设厅网站卡/汕头网站建设方案维护

河北住房和城乡建设厅网站卡,汕头网站建设方案维护,北京公司网站建设费用,杭州市人民政府官网综述 RequestBodyAdvice RequestBodyAdvice是SpringMVC4.2提供的一个接口,它允许请求体被读取并转换为对象,并将处理结果对象作为RequestBody参数或者 HttpEntity方法参数。由此可见,它的作用范围为: 使用RequestBody进行标记的…

综述

RequestBodyAdvice
RequestBodyAdvice是SpringMVC4.2提供的一个接口,它允许请求体被读取并转换为对象,并将处理结果对象作为@RequestBody参数或者 @HttpEntity方法参数。由此可见,它的作用范围为:

使用@RequestBody进行标记的参数
参数为HttpEntity

ResponseBodyAdvice
ResponseBodyAdvice是SpringMVC4.1提供的一个接口,它允许在 执行 @ResponseBody后自定义返回数据,或者将返回@ResponseEntity的 Controller Method在写入主体前使用 HttpMessageConverter进行自定义操作。由此可见,它的作用范围为:

使用@ResponseBody注解进行标记
返回@ResponseEntity

源码

这是spring 4.2新加的两个接口

1、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);@NullableObject handleEmptyBody(@Nullable Object var1, HttpInputMessage var2, MethodParameter var3, Type var4,             Class<? extends HttpMessageConverter<?>> var5);
}

AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters()方法调用了这个接口的方法。

@Nullableprotected <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;}}

HttpMessageConverter处理request body的前后做一些处理和body为空的时候做处理。

从这个可以看出,我们可以在使用这些HandlerMethodArgumentResolver的时候,我们能对request body进行前处理和解析后处理

ResponseBodyAdvice

public interface ResponseBodyAdvice<T> {boolean supports(MethodParameter var1, Class<? extends HttpMessageConverter<?>> var2);@NullableT beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class<? extends HttpMessageConverter<?>> var4,             ServerHttpRequest var5, ServerHttpResponse var6);
}

此可以对@ResponseBody的返回结果在输出到响应之前做处理。

通过泛型,指定需要被“拦截”的响应体对象类型。该接口的实现会在 Controller 方法返回数据,并且匹配到了 HttpMessageConverter 之后,HttpMessageConverter 进行序列化之前执行。可以通过覆写 beforeBodyWrite 来统一的对响应体进行修改。

应用

RequestBodyAdvice的使用

首先一个实现类实现RequestBodyAdvice,后在类上加上注解@ControllerAdvice,这俩个缺一不可。比如有些请求的请求体已经做加密处理,可以在此将请求体解密。核心的方法就是 supports,该方法返回的boolean值,决定了是要执行 beforeBodyRead 方法。而我们主要的逻辑就是在beforeBodyRead方法中,对客户端的请求体进行解密。注意:不用加@Component注解
//@Component
@ControllerAdvice
public class RequestBodyDecrypt implements RequestBodyAdvice {@Referenceprivate EquipmentService equipmentService;@Overridepublic boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {return true;  // 必须为true才会执行beforeBodyRead和afterBodyRead方法}@Overridepublic 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 = RSAUtils.decryptByPrivateKey(json.getString("applyData"), privateKey); // 私钥解密后的请求体} catch (Exception e) {throw new RuntimeException("数据错误");}     // 将解密后的请求体封装到HttpInputMessage中返回return new DecodedHttpInputMessage(httpInputMessage.getHeaders(), new ByteArrayInputStream(decrypt.getBytes(StandardCharsets.UTF_8)));}@Overridepublic Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type,                                               Class<? extends HttpMessageConverter<?>> aClass) {return body;}@Overridepublic 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;}@Overridepublic InputStream getBody() throws IOException {return body;}@Overridepublic HttpHeaders getHeaders() {return headers;}}
}

decryptByPrivateKey:

public static String decryptByPrivateKey(String encryptData, String priKey) throws NoSuchAlgorithmException,    InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {byte[] sourceBytes = Base64.getDecoder().decode(encryptData);byte[] keyBytes = Base64.getDecoder().decode(priKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");Key priK = keyFactory.generatePrivate(pkcs8KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, priK);int inputLen = sourceBytes.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 对数据分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_DECRYPT_BLOCK) {cache = cipher.doFinal(sourceBytes, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(sourceBytes, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}String decryptedData = out.toString("UTF-8");out.close();return decryptedData;}

ResponseBodyAdvice的使用

首先一个实现类实现ResponseBodyAdvice,后在类上加上注解@ControllerAdvice,

@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Result> {/*** 加密串一*/private static String md5_keyone;/*** 加密串二*/private static String md5_keytwo;@PostConstructpublic 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)*/@Overridepublic 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)*/@Overridepublic 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 = MD5.md5(md5_keyone + jsonString);// 第二次加密String data_encode_two = MD5.md5(data_encode_one + md5_keytwo);body.setToken(data_encode_two);return body;}}

为什么说要加上@ControllerAdvice注解,且实现RequestBodyAdvice或ResponseBodyAdvice接口

现在来分析为什么需要实现RequestBodyAdvice接口的同时要加上ControllerAdvice注解。
简单来说,要想执行afterBodyRead方法,必须实现ResponseBodyAdvice接口。

RequestResponseBodyAdviceChain的afterBodyRead方法:调用getMatchingAdvice方法,获取RequestBodyAdvice类型的advice

其中:class RequestResponseBodyAdviceChain implements RequestBodyAdvice, ResponseBodyAdvice

public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,     Class<? extends HttpMessageConverter<?>> converterType) {Iterator var6 = this.getMatchingAdvice(parameter, RequestBodyAdvice.class).iterator();while(var6.hasNext()) {RequestBodyAdvice advice = (RequestBodyAdvice)var6.next(); // 此advice就是我们定义的类if (advice.supports(parameter, targetType, converterType)) { //如果supports方法的返回值为true,则执行RequestBodyAdvice的afterBodyRead方法body = advice.afterBodyRead(body, inputMessage, parameter, targetType, converterType);}}return body;}

getMatchAdvice:获取RequestBodyAdvice类型的advice(此advice是我们定义的),如果不是RequestBodyAdvice类型就不会加到结果集,所以这就是我们实现RequestBodyAdvice的原因

private <A> List<A> getMatchingAdvice(MethodParameter parameter, Class<? extends A> adviceType) {List<Object> availableAdvice = this.getAdvice(adviceType);//获取RequestBodyAdvice类型的advice(此advice是我们定义实现RequestBodyAdvice接口的类)if (CollectionUtils.isEmpty(availableAdvice)) {return Collections.emptyList();} else {List<A> result = new ArrayList(availableAdvice.size());Iterator var5 = availableAdvice.iterator();while(true) {Object advice;while(true) {if (!var5.hasNext()) {return result;}advice = var5.next();if (!(advice instanceof ControllerAdviceBean)) {break;}ControllerAdviceBean adviceBean = (ControllerAdviceBean)advice;if (adviceBean.isApplicableToBeanType(parameter.getContainingClass())) {advice = adviceBean.resolveBean(); // 返回的是我们定义的Advice,即根据Bean的名称从BeanFactory中获取Bean对象break;}}// 判断这个类是否是RequestBodyAdvice类型,如果不是就不会加到结果集,所以这就是我们实现RequestBodyAdvice的原因if (adviceType.isAssignableFrom(advice.getClass())) {result.add(advice);}}}}
private List<Object> getAdvice(Class<?> adviceType) {if (RequestBodyAdvice.class == adviceType) {return this.requestBodyAdvice;} else if (ResponseBodyAdvice.class == adviceType) {return this.responseBodyAdvice;} else {throw new IllegalArgumentException("Unexpected adviceType: " + adviceType);}}
public Object resolveBean() {if (this.resolvedBean == null) {Object resolvedBean = this.obtainBeanFactory().getBean((String)this.beanOrName); // obtainBeanFactory()返回BeanFactory对象if (!this.isSingleton) {return resolvedBean;}this.resolvedBean = resolvedBean;}return this.resolvedBean;}

加上@ControllerAdvice注解

简单说,只有加上@ControllerAdvice,才能找到ControllerAdviceBean。

HandlerAdapter字面上的意思就是处理适配器,它的作用用一句话概括就是调用具体的方法对用户发来的请求来进行处理。当handlerMapping获取到执行请求的controller时,DispatcherServlte会根据controller对应的controller类型来调用相应的HandlerAdapter来进行处理。

RequestMappingHandlerAdapter就比较复杂了,可以说,该类是整个SpringMVC中最复杂的类了,却也是目前SpringMVC中使用到的频率最高的类。目前在SpringMVC的使用过程中,对请求的处理主要就是依赖RequestMappingHandlerMapping和RequestMappingHandlerAdapter类的配合使用。下面重点介绍下RequestMappingHandlerAdapter类

RequestMappingHandlerAdapter初始化流程:
RequestMappingHandlerAdapter实现了InitializingBean接口,Spring容器会自动调用其afterPropertiesSet方法。

http://www.lbrq.cn/news/1457353.html

相关文章:

  • 专业做俄语网站建设/个人网站制作教程
  • wordpress前端注册/搜索引擎优化的英文缩写
  • 学校网站的作用和意义/廊坊seo关键词排名
  • 企业网站整站/汕头网站建设方案开发
  • 微山网站建设多少钱/bt搜索引擎下载
  • 网站怎么防k/百度公司简介
  • 网站域名怎么设置/长春网站开发公司
  • 汕头潮南网站建设/合肥seo整站优化
  • Wordpress 充值 卡密/资阳市网站seo
  • 秒玩大型游戏的网站/武汉大学人民医院精神科
  • 做外贸网站要有域名/深圳建站公司
  • 网站常用文件夹/源码时代培训机构官网
  • 一级a做爰片免费观看网站/百度建站官网
  • 网站开发宣传标语/百度官方网平台
  • 做图海报网站/百度交易平台
  • 做网站可以自由职业吗/网络软营销
  • 做网站如何使用特殊字体/互联网营销推广服务商
  • 如何做网站的教程视频/百度关键词优化公司
  • 国外有哪些做服装的网站有哪些/网络营销相关的岗位有哪些
  • 自己如何免费做网站/seo交流论坛
  • 新网站建设公司/seo行业岗位
  • 中国搜索提交网站/百度企业认证怎么认证
  • 美工做网站尺寸多少/拉新app推广平台
  • 陕西政府门户网站建设 招标信息/免费的域名和网站
  • 地方门户网站的出路/整合营销是什么
  • 网站后期维护/谷歌关键词
  • 网站建设预算申请表/深圳网络营销推广培训
  • 个人备案网站名称怎么写/网络推广营销策划方案
  • 未来中森网站建设公司/电商平台有哪些?
  • 商丘做网站公司/宣传推广方案范文
  • 文件与目录操作命令
  • CMake 命令行参数完全指南(2)
  • 网关与路由器的区别
  • (FD Conv)Frequency Dynamic Convolution for Dense Image Prediction论文精读(逐段解析)
  • LLM Prompt与开源模型资源(2)提示工程关键技术
  • 嵌入式教学的云端革命:高精度仿真如何重塑倒车雷达实验与工程教育——深圳航天科技创新研究院赋能新一代虚实融合实训平台