场景描述
一个三方合作的项目,对某工厂的产线生产情况进行大屏监控, 产线数据流转流程
产线采数 —> 数据解析 ----> 大屏展示
我们处于数据解析的环节, 有产线现场mes采数推送给我们, 然后我们解析完毕之后再推送给另一家公司进行大屏展示.
数据格式与实体类模板
mes采集的数据格式, 是一串标准的json格式, 但是json中的key 与实体类中的属性是不对应的
{"A01": 5032 ,"A02": 4811 ,"A03": 4905 ,"A04": 5449 ,"A05": 9164 ,"A06": 8385 ,
"A07": 779 ,"A08": 7 ,"A09": 91 ,"A10": 21 ,"A11": 15 ,"A12": 0 ,"A13": 0,
"A14": 110 ,"A15": 365 ,"A16": 43 ,"A17": 58 ,"A18": 6 ,"A19": 14 ,"A20": 40 ,
"A21": 9 ,"A22":-2147483647. ,"A23": 10031,"A24": 9357 ,"A25": 674 ,"A26": 138 ,
"A27": 90 ,"A28": 0 ,"A29": 32 ,"A30": 5 ,"A31": 0 ,"A32": 121 ,"A33": 118,
"A34": 73 ,"A35": 23 ,"A36": 17 ,"A37": 22 ,"A38": 26 ,"A39": 0 ,
"A40": 0.000000000 }
实体类结构
类字段很多, 并且有很多各类
不使用反射 进行数据解析
数据采集方法
mes数据的采集是采用的mqtt消息队列
这里只展示数据解析的过程, 不展示mqtt相关的代码
public void handleMessage(Message<?> message) throws MessagingException {
String topic = (String) message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC);
log.info("----------------------");
log.info("接收到了消息");
log.info("message: {}",message);
log.info("payload: {}",message.getPayload());
log.info("PacketId: {}",message.getHeaders().getId());
log.info("Qos: {}",message.getHeaders().get(MqttHeaders.QOS));
log.info("topic: {}",topic);
MesDataEntity mesData = new MesDataEntity();
mesData.setMessage(message.toString());
Object payload = message.getPayload();
if (payload != null) {
mesData.setPayload(payload.toString());
}
UUID id = message.getHeaders().getId();
if (id != null) {
mesData.setPacketId(id.toString());
}
Object o = message.getHeaders().get(MqttHeaders.QOS);
if (o != null) {
mesData.setQos(o.toString());
}
// 从mqtt取到核心的消息体
String data = payload.toString();
// 数据推送的方法
Boolean aBoolean = httpData(data);
/****** 其他的业务处理********/
/**.
.
.
.
.
./
}
数据推送方法
public Boolean httpData(String data){
// 数据解析
List<JSONObject> jsonObject = analyseData(data);
// 推送数据
HttpResponse responsse = HttpRequest.post(url)
.header("Content-Type","application/json;charset=UTF-8")
.body(jsonObject.toString())
.timeout(2)
.execute();
String body = responsse.body();
JSONObject responsseJson = JSONObject.parseObject(body);
Boolean success = (boolean)responsseJson.get("success");
return success;
}
数据解析方法
/**
* 解析数据
* @param data
* @return
*/
public List<JSONObject> analyseData(String data){
List<JSONObject> res = null;
JSONObject source= JSON.parseObject(data);
String time = source.get("time").toString();
String id = source.get("id").toString();
EquipmentEnum enumByValue = EquipmentEnum.getEnumByValue(id);
switch (enumByValue){
case ID_0001: { res = mappingMes13Dto0001(source.get("data").toString(),time);break;}
case ID_0047: { res = mappingMes13Dto0047(source.get("data").toString(),time);break;}
default: break;
}
return res;
}
public List<JSONObject> mappingMes13Dto0001(String json,String time){
List<JSONObject> res = new ArrayList<>();
Mes13Dto0001 mes13Dto0001 = JSONObject.parseObject(json, Mes13Dto0001.class);
// 01冷端实体封装
JSONObject jsonObject = mappingLengDJC01(mes13Dto0001,time);
// 02冷端实体封装
JSONObject lengDJC02 = mappingLengDJC02(mes13Dto0001,time);
// 上管机实体封装
JSONObject jsonObject1 = mappingShangGJ(mes13Dto0001, time);
JSONObject jsonObject2 = mappingReDJC(mes13Dto0001, time);
res.add(jsonObject);
return res;
}
/** 像这样不用反射, 需要再每一个实体封装的方法里面全部手动set一遍,
这里我只列举了两个实体类, 实际项目中有22个实体类需要去设置
尤其是如果涉及到共用字段的话 代码重复量太大了
*/
/**
* 冷端检测01
* @param mes13Dto0001
* @return
*/
public JSONObject mappingLengDJC01(Mes13Dto0001 mes13Dto0001,String time){
JSONObject json_1 = new JSONObject();
LengDJC lengDJC = new LengDJC();
lengDJC.setPower(mes13Dto0001.getA01().toString());
lengDJC.setFaultSignal(mes13Dto0001.getA02().toString());
lengDJC.setPingJiShu(mes13Dto0001.getA03().toString());
lengDJC.setSheBeiHao(mes13Dto0001.getA04().toString());
/**
* .
* .
* .
* .
* .
* .
*/
json_1.put("time",DateUtil.getLong(time,timeFormat));
json_1.put("deviceName",EquipmentEnum.LDJC_01.getValue());
json_1.put("data",lengDJC);
return json_1;
}
/**
* 冷端检测02
* @param mes13Dto0001
* @return
*/
public JSONObject mappingLengDJC02(Mes13Dto0001 mes13Dto0001,String time){
JSONObject json_1 = new JSONObject();
LengDJC lengDJC = new LengDJC();
lengDJC.setPower(mes13Dto0001.getA10().toString());
lengDJC.setFaultSignal(mes13Dto0001.getA11().toString());
lengDJC.setPingJiShu(mes13Dto0001.getA12().toString());
lengDJC.setSheBeiHao(mes13Dto0001.getA13().toString());
/**
* .
* .
* .
* .
* .
*/
json_1.put("time",DateUtil.getLong(time,timeFormat));
json_1.put("deviceName",EquipmentEnum.LDJC_02.getValue());
json_1.put("data",lengDJC);
return json_1;
}
/**** 一直往下再写七八个类似的封装方法 ******/
使用反射的方式
数据采集和数据推送方法没有变化
主要变化的是实体类封装的过程
首先需要新建立一个映射类
这里可以选择以元数据作为key 只初始化一个所有映射的集合
也可以选择以实体类属性作为key, 初始化每个类对应的hash映射
这里针对我的应用场景,考虑到解析映射是效率的问题, 我选择了第二种,建立每一个实体类的hash映射
public class MapRelation {
private static final Map<String,String> all;
private static final Map<String,String> lengDJC01;
static{
// 以元数据作为key
Map<String,String> map = new HashMap<>();
map.put("A01","");
/**
* 填入每一个的映射
* .
* .
* .
*/
all = Collections.unmodifiableMap(map);
}
static{
// 以实体类属性作为key
Map<String,String> map = new HashMap<>();
map.put("power","");
/**
* 填入每一个的映射
* .
* .
* .
*/
lengDJC01 = Collections.unmodifiableMap(map);
}
}
最终的实体映射类
public class MapRelation {
private static final Map<String,String> lengDJC01;
private static final Map<String,String> lengDJC02;
private static final Map<String,String> shangGJ01;
private static final Map<String,String> shangGJ02;
private static final Map<String,String> shangGJ03;
private static final Map<String,String> shangGJ04;
private static final Map<String,String> tuiHL;
private static final Map<String,String> zhuangHJ01;
private static final Map<String,String> zhuangHJ02;
private static final Map<String,String> dianB01;
private static final Map<String,String> reDJC01;
private static final Map<String,String> reDJC02;
private static final Map<String,String> reDJC03;
private static final Map<String,String> reDJC04;
// lengDJC01 映射
static{
Map<String,String> map = new HashMap<>();
map.put("power","A01");
map.put("faultSignal","A02");
// 其他字段省略
lengDJC01 = Collections.unmodifiableMap(map);
}
// lengDJC02 映射
static{
Map<String,String> map = new HashMap<>();
map.put("power","A03");
map.put("faultSignal","A04");
// 其他字段省略
lengDJC02 = Collections.unmodifiableMap(map);
}
// shangGJ01 映射
static{
Map<String,String> map = new HashMap<>();
map.put("power","A05");
map.put("faultSignal","A06");
map.put("gongZuoGenShu","A07");
map.put("meiBanGenShu","A08");
map.put("liaoCangGenSHu","A09");
map.put("guanNeiGenShu","A10");
shangGJ01 = Collections.unmodifiableMap(map);
}
// shangGJ02 映射
static{
Map<String,String> map = new HashMap<>();
map.put("power","A11");
map.put("faultSignal","A12");
// 其他字段省略
shangGJ02 = Collections.unmodifiableMap(map);
}
// shangGJ03 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
shangGJ03 = Collections.unmodifiableMap(map);
}
// shangGJ04 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
shangGJ04 = Collections.unmodifiableMap(map);
}
// zhuangHJ01 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
zhuangHJ01 = Collections.unmodifiableMap(map);
}
// zhuangHJ02 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
zhuangHJ02 = Collections.unmodifiableMap(map);
}
// reDJC01 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
reDJC01 = Collections.unmodifiableMap(map);
}
// reDJC02 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
reDJC02 = Collections.unmodifiableMap(map);
}
// reDJC03 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
reDJC03 = Collections.unmodifiableMap(map);
}
// reDJC04 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
reDJC04 = Collections.unmodifiableMap(map);
}
// tuiHL 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
tuiHL = Collections.unmodifiableMap(map);
}
// dianB01 映射
static{
Map<String,String> map = new HashMap<>();
// 映射省略
dianB01 = Collections.unmodifiableMap(map);
}
}
有的同学可能看到上面映射会有点疑问, 这样和创建实体类有什么区别呢, 创建实体类也要每一个方法里面都set, 这样只不过是把set转换成了map呀
那接下来我们来看一下实体类解析的方法, 如果不使用反射映射, 那么有多少个实体类就要写多少个方法
比如上面我们写了14个map映射, 那么久对应着14个实体类封装的方法
如果使用反射的话, 那么我们只需要一个方法就能搞定
/**
* 对象解析封装
* @param obj 元数据对象
* @param time 上报时间
* @param deviceName 设备名称
* @param tClass 目标对象class
* @param mapRelation 对象映射关系
* @param <T>
* @return
*/
public <T> JSONObject mappingData(Object obj,String time,String deviceName,Class<T> tClass,Map<String,String> mapRelation){
// 获取目标对象的属性
Field[] declaredFields = tClass.getDeclaredFields();
Object o = null;
String value = "";
try{
// 获取目标对象的实例化对象
o = tClass.newInstance();
for (Field declaredField : declaredFields) {
//设置属性可操作
declaredField.setAccessible(true);
//获取属性名称
String name = declaredField.getName();
//通过属性名称去hash映射中 获取对应的元数据key
value = mapRelation.get(name);
if (StringUtils.isBlank(value)) {
continue;
}
// 通过属性名称 获取元数据的属性
Field field = obj.getClass().getDeclaredField(value);
// 获取元数据的实例化对象
// 设置属性可操作
field.setAccessible(true);
// field.get(mes13Dto0001).toString() 获取元数据的属性值
// 给目标对象属性赋值
declaredField.set(o,field.get(obj).toString());
}
}catch (NoSuchFieldException e) {
log.info("字段解析异常,对象 {} 不包含该字段,{}",obj,value);
} catch (InstantiationException e) {
e.printStackTrace();
log.info("目标对象实例化异常 {}",tClass);
} catch (IllegalAccessException e) {
e.printStackTrace();
log.info("元数据属性获取异常, 元数据{}, 属性{}",obj,value);
}
// 封装推送数据
JSONObject jsonObject = new JSONObject();
jsonObject.put("time",DateUtil.getLong(time,timeFormat));
jsonObject.put("deviceName",deviceName);
jsonObject.put("data",o);
return jsonObject;
}
最终成型代码
映射类省略 参照上述最终的实体映射类
数据解析类
public class MqttMessageHandle implements MessageHandler {
@Autowired
IMesDataService mesDataService;
@Value("unicom.url")
String url;
private String timeFormat = "yyyy-MM-dd HH:mm:ss";
@Override
public void handleMessage(Message<?> message) throws MessagingException {
String topic = (String) message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC);
log.info("----------------------");
log.info("接收到了消息");
log.info("message: {}",message);
log.info("payload: {}",message.getPayload());
log.info("PacketId: {}",message.getHeaders().getId());
log.info("Qos: {}",message.getHeaders().get(MqttHeaders.QOS));
log.info("topic: {}",topic);
Object payload = message.getPayload();
// 数据推送
String data = payload.toString();
boolean aBoolean = httpData(data);
// 元数据封装入库
MesDataEntity mesData = new MesDataEntity();
mesData.setMessage(message.toString());
if (payload != null) {
mesData.setPayload(payload.toString());
}
UUID id = message.getHeaders().getId();
if (id != null) {
mesData.setPacketId(id.toString());
}
Object o = message.getHeaders().get(MqttHeaders.QOS);
if (o != null) {
mesData.setQos(o.toString());
}
// 是否推送成功
Integer ispush = aBoolean ? 1:0;
mesData.setIspush(ispush);
mesData.setTopic(topic);
mesData.setCreateTime(new Date());
mesDataService.insert(mesData);
}
/**
* 推送消息
* @param data
* @return
*/
public Boolean httpData(String data){
// 数据解析
List<JSONObject> jsonObject = analyseData(data);
// 推送数据
HttpResponse responsse = HttpRequest.post(url)
.header("Content-Type","application/json;charset=UTF-8")
.body(jsonObject.toString())
.timeout(2)
.execute();
String body = responsse.body();
JSONObject responsseJson = JSONObject.parseObject(body);
Boolean success = (boolean)responsseJson.get("success");
return success;
}
/**
* 解析数据
* @param data
* @return
*/
public List<JSONObject> analyseData(String data){
List<JSONObject> res = null;
JSONObject source= JSON.parseObject(data);
String time = source.get("time").toString();
String id = source.get("id").toString();
EquipmentEnum enumByValue = EquipmentEnum.getEnumByValue(id);
switch (enumByValue){
case ID_0001: { res = mappingMes13Dto0001(source.get("data").toString(),time);break;}
case ID_0047: { res = mappingMes13Dto0047(source.get("data").toString(),time);break;}
default: break;
}
return res;
}
/**
* 0001 盒子数据
* @param json
* @param time
* @return
*/
public List<JSONObject> mappingMes13Dto0001(String json,String time){
List<JSONObject> res = new ArrayList<>();
Mes13Dto0001 mes13Dto0001 = JSONObject.parseObject(json, Mes13Dto0001.class);
// 01冷端实体封装
JSONObject lengDJC01 = mappingData(mes13Dto0001, time, EquipmentEnum.LDJC_01.getValue(), LengDJC.class, MapRelation.lengDJC01);
// 02冷端实体封装
JSONObject lengDJC02 = mappingData(mes13Dto0001, time, EquipmentEnum.LDJC_02.getValue(), LengDJC.class, MapRelation.lengDJC02);
// 上管机01实体封装
JSONObject shangGJ01 = mappingData(mes13Dto0001, time, EquipmentEnum.SGJ_01.getValue(), ShangGJ.class, MapRelation.shangGJ01);
// 上管机02实体封装
JSONObject shangGJ02 = mappingData(mes13Dto0001, time, EquipmentEnum.SGJ_02.getValue(), ShangGJ.class, MapRelation.shangGJ02);
// 上管机03实体封装
JSONObject shangGJ03 = mappingData(mes13Dto0001, time, EquipmentEnum.SGJ_03.getValue(), ShangGJ.class, MapRelation.shangGJ03);
// 上管机04实体封装
JSONObject shangGJ04 = mappingData(mes13Dto0001, time, EquipmentEnum.SGJ_04.getValue(), ShangGJ.class, MapRelation.shangGJ04);
res.add(lengDJC01);
res.add(lengDJC02);
res.add(shangGJ01);
res.add(shangGJ02);
res.add(shangGJ03);
res.add(shangGJ04);
return res;
}
/**
* 0047 盒子数据
* @param json
* @param time
* @return
*/
public List<JSONObject> mappingMes13Dto0047(String json,String time){
List<JSONObject> res = new ArrayList<>();
Mes13Dto0047 mes13Dto0047 = JSONObject.parseObject(json, Mes13Dto0047.class);
// 01热端实体封装
JSONObject reDJC01 = mappingData(mes13Dto0047, time, EquipmentEnum.RQB_01.getValue(), ReDJC.class, MapRelation.reDJC01);
// 02热端实体封装
JSONObject reDJC02 = mappingData(mes13Dto0047, time, EquipmentEnum.RQB_02.getValue(), ReDJC.class, MapRelation.reDJC02);
// 03热端实体封装
JSONObject reDJC03 = mappingData(mes13Dto0047, time, EquipmentEnum.RQB_03.getValue(), ReDJC.class, MapRelation.reDJC03);
// 04热端实体封装
JSONObject reDJC04 = mappingData(mes13Dto0047, time, EquipmentEnum.RQB_04.getValue(), ReDJC.class, MapRelation.reDJC04);
// 电表01实体封装
JSONObject dianB01 = mappingData(mes13Dto0047, time, EquipmentEnum.DB_01.getValue(), DianB.class, MapRelation.dianB01);
res.add(reDJC01);
res.add(reDJC02);
res.add(reDJC03);
res.add(reDJC04);
res.add(dianB01);
return res;
}
/**
* 对象解析封装
* @param obj 元数据对象
* @param time 上报时间
* @param deviceName 设备名称
* @param tClass 目标对象class
* @param mapRelation 对象映射关系
* @param <T>
* @return
*/
public <T> JSONObject mappingData(Object obj,String time,String deviceName,Class<T> tClass,Map<String,String> mapRelation){
// 获取目标对象的属性
Field[] declaredFields = tClass.getDeclaredFields();
T t = null;
String value = "";
try{
// 获取目标对象的实例化对象
t = tClass.newInstance();
for (Field declaredField : declaredFields) {
//设置属性可操作
declaredField.setAccessible(true);
//获取属性名称
String name = declaredField.getName();
//通过属性名称去hash映射中 获取对应的元数据key
value = mapRelation.get(name);
if (StringUtils.isBlank(value)) {
continue;
}
// 通过属性名称 获取元数据的属性
Field field = obj.getClass().getDeclaredField(value);
// 获取元数据的实例化对象
// 设置属性可操作
field.setAccessible(true);
// field.get(mes13Dto0001).toString() 获取元数据的属性值
// 给目标对象属性赋值
declaredField.set(t,field.get(obj).toString());
}
}catch (NoSuchFieldException e) {
log.info("字段解析异常,对象不包含该字段,对象{} 字段{}",obj,value);
} catch (InstantiationException e) {
e.printStackTrace();
log.info("目标对象实例化异常 {}",tClass);
} catch (IllegalAccessException e) {
e.printStackTrace();
log.info("元数据属性获取异常, 元数据{}, 属性{}",obj,value);
}
// 封装推送数据
JSONObject jsonObject = new JSONObject();
jsonObject.put("time",DateUtil.getLong(time,timeFormat));
jsonObject.put("deviceName",deviceName);
jsonObject.put("data",t);
return jsonObject;
}
}