通过固定实体类解析的参考我上一篇转载文章,在此基础上我修改为配置化解析报文。
原作者:
https://blog.csdn.net/weixin_33851604/article/details/88241284
关于jar包:hutool,fastjson,其他工具类报错可以自行解决。
实体类
MsgConfig :
package com.ins.common.msg.entity;
import java.util.LinkedList;
/**
* MsgConfig.java 报文配置实体类
*
* @author skysource
* @date 2019-06-03 11:56:07
* @since 1.0
*/
public class MsgConfig {
/**
* 消息类型
*/
String msgType;
/**
* 消息规则配置,可改为抽象方法来实现多个不同的规则
*/
LinkedList<MsgConfigInfo> msgConfigInfos;
/**
* @return the msgType
*/
public String getMsgType() {
return msgType;
}
/**
* @param msgType
* the msgType to set
*/
public void setMsgType(String msgType) {
this.msgType = msgType;
}
/**
* @return the msgConfigInfos
*/
public LinkedList<MsgConfigInfo> getMsgConfigInfos() {
return msgConfigInfos;
}
/**
* @param msgConfigInfos
* the msgConfigInfos to set
*/
public void setMsgConfigInfos(LinkedList<MsgConfigInfo> msgConfigInfos) {
this.msgConfigInfos = msgConfigInfos;
}
}
MsgConfigInfo:
package com.ins.common.msg.entity;
import java.util.LinkedList;
/**
* MsgConfigInfo.java 报文规则配置
*
* @author skysource
* @date 2019-06-03 11:57:44
* @since 1.0
*/
public class MsgConfigInfo {
/**
* 定长消息主体名称,如Head、Body等
*/
private String msgName;
/**
* msgName值对应的字段,如key:value
*/
private String msgField;
/**
* 循环字段,如值为"occurrenceCount",则表示需要根据报文字段occurrenceCount的值,循环当前报文体下面所有的值。如果occurrenceCount的值为5,则表示有5次循环
*/
private String cycleField;
/**
* 固定循环次数,如,50 表示循环50次,不足50次使用占位符表示
*/
private int fixedCycleCount;
/**
* 字段类型,0字符串,1Map对象,2List集合,4整数,5浮点数字
*/
private String fieldType;
/**
* 定长消息规则集合
*/
private LinkedList<MsgField> msgConfigs;
/**
* @return the msgName
*/
public String getMsgName() {
return msgName;
}
/**
* @param msgName
* the msgName to set
*/
public void setMsgName(String msgName) {
this.msgName = msgName;
}
/**
* @return the msgField
*/
public String getMsgField() {
return msgField;
}
/**
* @param msgField the msgField to set
*/
public void setMsgField(String msgField) {
this.msgField = msgField;
}
/**
* @return the msgConfigs
*/
public LinkedList<MsgField> getMsgConfigs() {
return msgConfigs;
}
/**
* @return the cycleField
*/
public String getCycleField() {
return cycleField;
}
/**
* @return the fixedCycleCount
*/
public int getFixedCycleCount() {
return fixedCycleCount;
}
/**
* @param fixedCycleCount
* the fixedCycleCount to set
*/
public void setFixedCycleCount(int fixedCycleCount) {
this.fixedCycleCount = fixedCycleCount;
}
/**
* @return the fieldType
*/
public String getFieldType() {
return fieldType;
}
/**
* @param fieldType
* the fieldType to set
*/
public void setFieldType(String fieldType) {
this.fieldType = fieldType;
}
/**
* @param cycleField
* the cycleField to set
*/
public void setCycleField(String cycleField) {
this.cycleField = cycleField;
}
/**
* @param msgConfigs
* the msgConfigs to set
*/
public void setMsgConfigs(LinkedList<MsgField> msgConfigs) {
this.msgConfigs = msgConfigs;
}
}
MsgField:
/**
* package-info.java
*
* @author skysource
* @date 2019-05-30 14:24:14
* @since 1.0
*/
package com.ins.common.msg.entity;
/**
* 消息域 MsgField.java
*
* @author skysource
* @date 2019-06-04 11:12:49
* @since 1.0
*/
public class MsgField {
public MsgField(String name, int length, char fillChar, FillSide fillSide) {
this.name = name;
this.length = length;
this.fillChar = fillChar;
this.fillSide = fillSide;
}
public MsgField(String name, int length, char fillChar, FillSide fillSide,String fieldType) {
this.name = name;
this.length = length;
this.fillChar = fillChar;
this.fillSide = fillSide;
this.fieldType = fieldType;
}
/**
* 填充位置
*
* @author Zhenwei.Zhang (2013-9-25)
*/
public enum FillSide {
LEFT, RIGHT
}
/**
* 字段名称
*/
private String name;
/**
* 长度
*/
private int length;
/**
* 填充字符
*/
private char fillChar;
/**
* 填充位置
*/
private FillSide fillSide;
/**
* 字段类型,0字符串,1Map对象,2List集合,4整数,5浮点数字
*/
private String fieldType;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public char getFillChar() {
return fillChar;
}
public void setFillChar(char fillChar) {
this.fillChar = fillChar;
}
public FillSide getFillSide() {
return fillSide;
}
public void setFillSide(FillSide fillSide) {
this.fillSide = fillSide;
}
public String getFieldType() {
return fieldType;
}
public void setFieldType(String fieldType) {
this.fieldType = fieldType;
}
}
主程序类
MsgPackage:
package com.ins.common.msg.mainPackage;
/**
* MsgPackage.java
*
* @author skysource
* @date 2019-05-30 14:26:44
* @since 1.0
*/
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import com.ins.common.msg.entity.MsgConfig;
import com.ins.common.msg.entity.MsgConfigInfo;
import com.ins.common.msg.entity.MsgField;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
/**
* 消息包,由多个消息片组成
*
*/
public abstract class MsgPackage {
/** 消息包的消息片数组 */
String[] pieces = null;
LinkedHashMap<String, MsgConfigInfo> msgConfigMap = new LinkedHashMap<>();
public MsgPackage(String... pieName) {
pieces = pieName;
}
public MsgPackage(LinkedList<MsgConfigInfo> msgConfigInfoList) {
msgConfigInfoList.stream().forEach(t -> msgConfigMap.put(t.getMsgName(), t));
}
/**
* 组包
*
* @param charsetName
* @return
* @throws Exception
*/
public byte[] pack(String charsetName) throws Exception {
int index = 0;
byte[] result = new byte[this.getLength()];
for (String p : pieces) {
PropertyDescriptor pd = new PropertyDescriptor(p, this.getClass());
Method getterMethod = pd.getReadMethod();
MsgPiece piece = (MsgPiece) getterMethod.invoke(this);
if (piece == null) { // 属性为空则该属性组空串
piece = (MsgPiece) pd.getPropertyType().newInstance();
}
byte[] t = piece.pack(charsetName);
System.arraycopy(t, 0, result, index, t.length);
index += t.length;
}
return result;
}
/**
* 解包
*
* @param msg
* @param charsetName
* @throws Exception
*/
public void unPack(byte[] msg, String charsetName) throws Exception {
if (msg.length != this.getLength()) {
throw new Exception("解消息出错,消息包长度不合法!");
}
int index = 0;
for (String p : pieces) { // 创建一个新的属性对象,解包,赋值
PropertyDescriptor pd = new PropertyDescriptor(p, this.getClass());
Method writeMethod = pd.getWriteMethod();
MsgPiece piece = (MsgPiece) pd.getPropertyType().newInstance();
byte[] t = new byte[piece.getLength()];
System.arraycopy(msg, index, t, 0, t.length);
piece.unPack(t, charsetName);
writeMethod.invoke(this, piece);
index += t.length;
}
}
/**
* 解包
*
* @param msg
* @param charsetName
* @param msgConifg
* @throws Exception
*/
public LinkedHashMap<String, Object> unPackByConfig(byte[] msg, String charsetName) throws Exception {
int msgConfigLength = this.getLengthByConfig();
if (msg.length != msgConfigLength) {
throw new Exception(String.format("解消息出错,消息包长度不合法!报文消息长度(%s)与报文配置长度不一致(%s)%n。", msg.length,msgConfigLength));
}
int inde