SpringMVC底层数据传输校验的方案
团队的项目正常运行了很久,但近期偶尔会出现BUG。目前观察到的有两种场景:一是大批量提交业务请求,二是生成批量导出文件。出错后,再执行一次就又正常了。
经过跟踪日志,发现是在Server之间进行json格式大数据量传输时会丢失部分字符,造成接收方拿到完整字符串后不能正确解析成json,因此报错。
同其他团队同事们沟通后发现,不仅仅是我们项目有这个问题,我们不是一个人在战斗。
1 问题现象
服务器之间使用http+json的数据传输方案,在传输过程中,一些json数据发生错误,导致数据接收方解析json报错,系统功能因此失败。
下面截取了一小段真实数据错误,在传输的json中,有一个数据项是departmentIdList,其内容时一个长整型数组。

传输之前的数据为:
"departmentIdList" : [ 719, 721, 722, 723, 7367, 7369, 7371, 7373, 7375, 7377 ]
接收到的数据为:
"departmentIdlist" : [ 719, 721'373, 7375, 7377 ]
可以看到,这个错误导致了两个问题:
1、 json解析失败
2、 丢失了一些有效数据
详细检查系统日志之后,这是偶发bug,并且只在传输数据较大时发生。
2 可选的解决方案
2.1 请架构组协助解决
这是最直接的解决方案,因为我们项目使用架构组提供的环境,他们需要提供可靠的底层数据传输机制。
2.2 压缩传输数据
因为数据量大时容易发生,并且传输的都是普通文本,可以考虑对内容进行压缩后传输。普通文件压缩率也很高,压缩后内容长度能做到原数据10%以内,极大减少传输出错的几率。
2.3 对传输数据进行MD5校验
将传输数据作为一个完整数据块,传输之前先做一个md5摘要,并将原数据和摘要一并发送;接收方收到数据后,先进行数据校验工作,校验成功后再进行后续操作流程,如果不成功可以辅助重传或直接报错等机制。
3 方案设计
为了彻底解决这个问题,设计了一个底层方案
3.1 设计原则
1、 适用类型:Spring MVC项目,数据发送方使用RestTemplate工具类,使用fastjson作为json工具类。
2、 数据校验,使用MD5加密,当然也可以配合数据压缩机制,减少传输数据量。
3、 提供底层解决方案,不需要对系统代码做大规模调整。
3.2 核心设计

数据发送方,重载RestTemplate,在数据传输之前对数据进行md5摘要,并将原始数据和 md5摘要一并传输。
数据接收方,重载AbstractHttpMessageConverter,接收到数据后,对数据进行MD5校验。
3.3 DigestRestTemplate关键代码
对原json进行摘要,并同原始数据一起生成一个新的json对象。
|
private Object digestingJson(JSONObject json) throws Exception { String requestJsonMd5 = JsonDigestUtil.createMD5(json); JSONObject newJson = new JSONObject(); newJson.put("content", json); newJson.put("md5", requestJsonMd5); return newJson; } |
重载的postForEntity函数核心部分,如果传入参数是 JSONObject,则调用方法对数据进行摘要操作,并用新生成的json进行传输。
|
Object newRequest = null; if (request instanceof JSONObject) { JSONObject json = (JSONObject) request; try { newRequest = digestingJson(json); } catch (Exception e) { } } if (newRequest == null) { newRequest = request; } return super.postForEntity(url, newRequest, responseType); |
3.4 DigestFastJsonHttpMessageConverter 核心代码
首先会判断是否是经过md5摘要的json,是有摘要的数据进行校验,否则直接返回对象。
|
private JSONObject getDigestedJson(JSONObject json) { if (json.size()==2&&json.containsKey("md5")&&json.containsKey("content")) { String md5 = json.getString("md5"); String content = json.getString("content"); logger.info("degested json : {}", json); try { String newMd5 = JsonDigestUtil.createMD5(content); if (newMd5.equals(md5)) { json = JSON.parseObject(content); } else { logger.error("md5 is not same : {} vs {}", md5, newMd5); throw new RuntimeException("content is modified"); } } catch (Exception e) { } } else { logger.info("may not be digested json"); } return json; } |
原有的处理数据代码增加调用该方法的代码
|
@Override protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { JSONObject json = null; InputStream in = inputMessage.getBody(); Charset jsonCharset = fastJsonConfig.getCharset(); Feature[] jsonFeatures = fastJsonConfig.getFeatures(); json = JSON.parseObject(in, jsonCharset, clazz, jsonFeatures); json = getDigestedJson(json); return json; } |
当前的代码,如果数据校验失败,简单抛出异常。后续可以增加更多的机制,比如在RestTemplate处增加校验,如果发现校验失败,则重传。
3.5 数据发送方项目配置
以Spring Boot项目为例
在Main类中定义 restTemplate
|
@Bean(name = "restTemplate") public RestTemplate getRestTemplate() { RestTemplate restTemplate = new DigestRestTemplate(); return restTemplate; } |
需要调用RestTemplate的代码,只需要依赖注入RestTemplate
|
@Autowired RestTemplate restTemplate; |
3.6 数据接收方项目设置
在SpringBootApplication类中定义
|
@Bean public HttpMessageConverters fastJsonHttpMessageConverters() { DigestFastJsonHttpMessageConverter fastConverter = new DigestFastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); fastConverter.setFastJsonConfig(fastJsonConfig); HttpMessageConverter<?> converter = fastConverter; return new HttpMessageConverters(converter); } |
4 后记
经过测试,这个方案是可行的。如果为了能够适应更多的项目及更多的Java技术栈,需要对代码进行进一步完善。
SpringMVC底层数据传输校验的方案的更多相关文章
- SpringMVC底层数据传输校验的方案(修改版)
团队的项目正常运行了很久,但近期偶尔会出现BUG.目前观察到的有两种场景:一是大批量提交业务请求,二是生成批量导出文件.出错后,再执行一次就又正常了. 经过跟踪日志,发现是在Server之间进行jso ...
- springmvc的数据校验
springmvc的数据校验 在Web应用程序中,为了防止客户端传来的数据引发程序异常,常常需要对数据进行验证,输入验证分为客户端验证与服务器端验证. 客户端验证主要通过javaScript脚本 ...
- springmvc(四) springmvc的数据校验的实现
so easy~ --WH 一.什么是数据校验? 这个比较好理解,就是用来验证客户输入的数据是否合法,比如客户登录时,用户名不能为空,或者不能超出指定长度等要求,这就叫做数据校验. 数据校验分为客户端 ...
- SpringMVC学习(三)———— springmvc的数据校验的实现
一.什么是数据校验? 这个比较好理解,就是用来验证客户输入的数据是否合法,比如客户登录时,用户名不能为空,或者不能超出指定长度等要求,这就叫做数据校验. 数据校验分为客户端校验和服务端校验 客户端校验 ...
- 深入源码分析SpringMVC底层原理(二)
原文链接:深入源码分析SpringMVC底层原理(二) 文章目录 深入分析SpringMVC请求处理过程 1. DispatcherServlet处理请求 1.1 寻找Handler 1.2 没有找到 ...
- 设计模式:与SpringMVC底层息息相关的适配器模式
目录 前言 适配器模式 1.定义 2.UML类图 3.实战例子 4.总结 SpringMVC底层的适配器模式 参考 前言 适配器模式是最为普遍的设计模式之一,它不仅广泛应用于代码开发,在日常生活里也很 ...
- Android基于WIFI实现电脑和手机间数据传输的技术方案研究
Android手机和电脑间基于wifi进行数据传输,从技术上讲,主要有两种方案: 一种是通过ftp协议实现,Android手机作为数据传输过程中的ftp服务器: 一种是通过http协议实现.Andro ...
- SpringMVC + MyBatis分库分表方案
mybatis作为流行的ORM框架,项目实际使用过程中可能会遇到分库分表的场景.mybatis在分表,甚至是同主机下的分库都可以说是完美支持的,只需要将表名或者库名作为动态参数组装sql就能够完成.但 ...
- 学习SpringMVC必知必会(7)~springmvc的数据校验、表单标签、文件上传和下载
输入校验是 Web 开发任务之一,在 SpringMVC 中有两种方式可以实现,分别是使用 Spring 自带的验证 框架和使用 JSR 303 实现, 也称之为 spring-validator 和 ...
随机推荐
- fragment显示 Binary XML file line #12: Error inflating class fragment 错误
问题 最近换了新机子,今天在静态用fragment时突然发现闪退,一看显示 Binary XML file line #12: Error inflating class fragment 错误 后面 ...
- Unity3D寻路导航烘焙
在初次进行3D(三维)游戏体验中,避免不了对游戏有生疏的情况,因此在游戏中一般会插入新手指导.自动寻路.导航地图等AI人工智能技术到游戏中,方便玩家更快体验,为了玩家的体验更好,Unity3D寻路导航 ...
- KNN--用于手写数字识别
优点:精度高,对异常值不敏感,无数据输入假定 缺点:计算复杂度高,空间复杂度高 适用数据范围:数值型和标称型 一般流程: (1). 收集数据(网络抓取) (2).处理数据,将数据处 ...
- POJ3083 Children of the Candy Corn(Bfs + Dfs)
题意:给一个w*h的迷宫,其中矩阵里面 S是起点,E是终点,“#”不可走,“.”可走,而且,S.E都只会在边界并且,不会在角落,例如(0,0),输出的话,每组数据就输出三个整数,第一个整数,指的是,以 ...
- 04.redis集群+SSM整合使用
redis集群+SSM整合使用 首先是创建redis-cluster文件夹: 因为redis最少需要6个节点(三主三从),为了更好的理解,我这里创建了两台虚拟机(192.168.0.109 192.1 ...
- MongoDB入门学习(一):MongoDB的安装和管理
以前用MySQL数据库,整天都是写大堆大堆的SQL语句,要记住这些SQL关键字都要花好几天时间,写的蛋都爆了,当接触到MongoDB的时候,发现不用写SQL,瞬间觉得高大上,瞬间产生了学习使用它的冲动 ...
- MySQL用户管理及SQL语句详解
1.1 MySQL用户管理 1.1.1 用户的定义 用户名+主机域 mysql> select user,host,password from mysql.user; +--------+--- ...
- 使用TensorFlow实现DNN
这一节使用TF实现一个多层神经网络模型来对MNIST数据集进行分类,这里我们设计一个含有两个隐藏层的神经网络,在输出部分使用softmax对结果进行预测. 使用高级API实现多层神经网络 这里我们使用 ...
- oracle 10g下范围分区扫描的几种方式
oracle 10g下有几种扫描方式,注意最后一种扫描方式,当对分区的列进行计算时,会不走分区.这跟对索引列进行计算会导致无法用索引一样. --扫描单个分区 PARTITION RANGE SING ...
- 论文笔记:Chaotic Invariants of Lagrangian Particle Trajectories for Anomaly Detection in Crowded Scenes
[原创]Liu_LongPo 转载请注明出处 [CSDN]http://blog.csdn.net/llp1992 近期在关注 crowd scene方面的东西.由于某些原因须要在crowd scen ...