ISO8583报文解析

在此只写了一个8583报文的拆包,组包其实也差不多的。

不多说直接上文件,

具体思路过程,在解析类里面写的有。

其中包含了四个文件

8583resp.txt报文

ISO8583medata配置文件

Bean8583Factory.java 8583配置文件解析类

Parse8583.java 8583报文解析类

8583报文

29 01 30 34 31 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 00 00 00 00
30 38 34 31 30 31 36 32 00 30 32 31 30 F2 3E 40
81 8E F0 80 00 00 00 00 00 10 00 00 E1 31 36 35
32 33 39 35 39 30 30 30 30 31 34 31 32 32 38 30
30 30 30 30 30 30 30 30 30 30 30 30 39 38 37 36
31 30 39 30 38 31 34 35 33 33 34 34 31 30 31 36
32 31 34 35 33 33 34 30 39 30 38 33 30 30 38 30
31 30 35 36 30 31 33 30 30 30 38 36 33 30 34 30
32 35 30 30 38 36 33 30 34 30 30 30 30 30 30 30
30 30 30 34 31 30 31 36 32 35 35 35 33 32 32 30
30 37 37 37 37 37 37 37 37 30 32 38 30 30 30 30
31 30 39 20 20 20 20 20 B4 FA C0 ED C6 F3 D2 B5
CD F8 D2 F8 D7 A8 D3 C3 B2 E2 CA D4 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
32 35 30 30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 31 35 36 30 38
36 33 30 34 30 30 30 30 30 30 30 30 31 38 20 20
20 20 20 20 20 20 20 20 20 20 B2 E2 CA D4 31 34
30 39 35 4E 20 20 30 30 30 31 30 31 39 35 33 37
37 30 30 30 30 30 30 35 30 30 30 30 20 20 30 30
30 30 30 30 20 20 30 30 32 20 2D 30 30 35 34 36
37 32 35 31 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
31 30 33 43 34 44 45 44 33 37                  
View Code

 

8583配置文件

<?xml version="1.0" encoding="utf-8"?>
<sdoroot package_type="iso8583" store-mode="GBK">
 <H1 type="string" length="1" isHeader="true" encoding="GBK" isBCD="true"/>
 <H2 type="string" length="1" isHeader="true" encoding="GBK" isBCD="true"/>
 <H3 type="string" length="4" isHeader="true" encoding="GBK"/>
 <H4 type="string" length="11" isHeader="true" encoding="GBK"/>
 <H5 type="string" length="11" isHeader="true" encoding="GBK"/>
 <H6 type="string" length="3" isHeader="true" encoding="GBK" isBCD="true"/>
 <H7 type="string" length="1" isHeader="true" encoding="GBK" isBCD="true"/>
 <H8 type="string" length="8" isHeader="true" encoding="GBK" />
 <H9 type="string" length="1" isHeader="true" encoding="GBK" isBCD="true"/>
 <MsgType type="string" length="4" encoding="GBK"/>
 <bitmap1 length="8" type="bitmap"/>
 <bitmap2 length="8" type="bitmap"/>
 <F2 type="string" length="19" variable_flag="2" field_index="2" encoding="GBK"/>
 <F3 type="string" length="6" field_index="3" encoding="GBK"/>
 <F4 type="string" length="12" field_index="4" encoding="GBK"/>
 <F6 type="string" length="12" field_index="6" encoding="GBK"/>
 <F7 type="string" length="10" field_index="7" encoding="GBK"/>
 <F10 type="string" length="8" field_index="10" encoding="GBK"/>
 <F11 type="string" length="6" field_index="11" encoding="GBK"/>
 <F12 type="string" length="6" field_index="12" encoding="GBK"/>
 <F13 type="string" length="4" field_index="13" encoding="GBK"/>
 <F14 type="string" length="4" field_index="14" encoding="GBK"/>
 <F15 type="string" length="4" field_index="15" encoding="GBK"/>
 <F18 type="string" length="4" field_index="18" encoding="GBK"/>
 <F22 type="string" length="3" field_index="22" encoding="GBK"/>
 <F23 type="string" length="3" field_index="23" encoding="GBK"/>
 <F25 type="string" length="2" field_index="25" encoding="GBK"/>
 <F26 type="string" length="2" field_index="26" encoding="GBK"/>
 <F28 type="string" length="9" field_index="28" encoding="GBK"/>
 <F32 type="string" length="11" variable_flag="2" field_index="32" encoding="GBK"/>
 <F33 type="string" length="11" variable_flag="2" field_index="33" encoding="GBK"/>
 <F35 type="string" length="37" variable_flag="2"  field_index="35" encoding="GBK"/>
 <F36 type="string" length="104" variable_flag="3" field_index="36" encoding="GBK"/>
 <F37 type="string" length="12" field_index="37" encoding="GBK"/>
 <F38 type="string" length="6" field_index="38" encoding="GBK"/>
 <F39 type="string" length="2" field_index="39" encoding="GBK"/>
 <F41 type="string" length="8" field_index="41" encoding="GBK"/>
 <F42 type="string" length="15" field_index="42" encoding="GBK"/>
 <F43 type="string" length="40" field_index="43" encoding="GBK"/>
 <F44 type="string" length="25" variable_flag="2" field_index="44" encoding="GBK"/>
 <F47 type="string" length="100" variable_flag="3" field_index="47" encoding="GBK"/>
 <F48 type="string" length="400" variable_flag="3" field_index="48" encoding="GBK"/>
 <F49 type="string" length="3" field_index="49" encoding="GBK"/>
 <F51 type="string" length="3" field_index="51" encoding="GBK"/>
 <F52 type="string" length="8" field_index="52" encoding="GBK"/>
 <F53 type="string" length="16" field_index="53" encoding="GBK"/>
 <F54 type="string" length="40" variable_flag="3" field_index="54" encoding="GBK" />
 <F55 type="string" length="300" variable_flag="3" field_index="55" encoding="GBK" />
 <F57 type="string" length="100" variable_flag="3" field_index="57" encoding="GBK" />
 <F60 type="string" length="100" variable_flag="3" field_index="60" encoding="GBK"/>
 <F61 type="string" length="200" variable_flag="3" field_index="61" encoding="GBK"/>
 <F62 type="string" length="200" variable_flag="3" field_index="62" encoding="GBK"/>
 <F70 type="string" length="3" field_index="70" encoding="GBK"/>
 <F90 type="string" length="42" field_index="90" encoding="GBK"/>
 <F91 type="string" length="1" field_index="91" encoding="GBK"/>
 <F96 type="string" length="8" field_index="96" encoding="GBK"/>
 <F100 type="string" length="11" variable_flag="2" field_index="100" encoding="GBK"/>
 <F102 type="string" length="32" variable_flag="2" field_index="102" encoding="GBK"/>
 <F103 type="string" length="32" variable_flag="2" field_index="103" encoding="GBK"/>
 <F108 type="string" length="32" variable_flag="3" field_index="108" encoding="GBK"/>
 <F121 type="string" length="100" variable_flag="3" field_index="121" encoding="GBK"/>
 <F122 type="string" length="50" variable_flag="3" field_index="122" encoding="GBK"/>
 <F123 type="string" length="400" variable_flag="3" field_index="123" encoding="GBK"/>
 <F128 type="string" length="8" field_index="128" encoding="GBK"/>
</sdoroot>
View Code

 

8583配置类

 

  1 package com.handle8583;
  2 
  3 import java.io.File;
  4 import java.util.HashMap;
  5 import java.util.Iterator;
  6 import java.util.List;
  7 import java.util.Map;
  8 import java.util.Properties;
  9 
 10 import org.apache.commons.logging.Log;
 11 import org.apache.commons.logging.LogFactory;
 12 import org.dom4j.Document;
 13 import org.dom4j.DocumentException;
 14 import org.dom4j.Node;
 15 import org.dom4j.io.SAXReader;
 16 
 17 
 18 public class Bean8583Factory {
 19 
 20     private static Map<String,Properties> map = new HashMap<String, Properties>();
 21     
 22     private static Bean8583Factory instance = null;
 23     
 24     private static Log log = LogFactory.getLog(Bean8583Factory.class);
 25     
 26     public static Bean8583Factory getInstance(){
 27         if(null == instance){
 28             map.clear();
 29             instance = new Bean8583Factory();
 30         }
 31         return instance;
 32     }
 33     
 34     private Bean8583Factory(){
 35         init();
 36     }
 37     
 38     public void init() {
 39         System.out.println("加载8583配置开始");
 40 
 41         File f = new File("D:/workspace/springweb/src/com/handle8583/ISO8583medata.xml");
 42         if ((f.exists()) && (f.isFile())) {
 43             SAXReader reader = new SAXReader();
 44             try {
 45                 Iterator<Node> iterator2;
 46                 Document doc = reader.read(f);
 47                 List obj = doc.getRootElement().elements();
 48                 if (obj == null) {
 49                     return;
 50                 }
 51                 Iterator<Node> iterator = obj.iterator();
 52                 while (iterator.hasNext()) {
 53                     Node imetadata = iterator.next();
 54                     Properties pop = new Properties();
 55                     
 56                     Node isHeader = imetadata.selectSingleNode("@isHeader");
 57                     if(null != isHeader){
 58                         pop.setProperty("isHeader", isHeader.getText());
 59                     }
 60                     
 61                     Node isBCD = imetadata.selectSingleNode("@isBCD");
 62                     if(null != isBCD){
 63                         pop.setProperty("isBCD", isBCD.getText());
 64                     }
 65                     
 66                     Node type = imetadata.selectSingleNode("@type");
 67                     if(null != type){
 68                         pop.setProperty("type", type.getText());
 69                     }
 70                     
 71                     Node length = imetadata.selectSingleNode("@length");
 72                     if(null != length){
 73                         pop.setProperty("length", length.getText());
 74                     }
 75                     
 76                     Node variable_flag = imetadata.selectSingleNode("@variable_flag");
 77                     if(null != variable_flag){
 78                         pop.setProperty("variable_flag", variable_flag.getText());
 79                     }
 80                     
 81                     Node field_index = imetadata.selectSingleNode("@field_index");
 82                     if(null != field_index){
 83                         pop.setProperty("field_index", field_index.getText());
 84                     }
 85                     
 86                     Node encoding = imetadata.selectSingleNode("@encoding");
 87                     if(null != encoding){
 88                         pop.setProperty("encoding", encoding.getText());
 89                     }
 90                     
 91                     pop.setProperty("name", imetadata.getName());
 92                     map.put(imetadata.getName(),pop);
 93                     
 94                 }
 95             } catch (DocumentException e) {
 96                 e.printStackTrace();
 97                 System.out.println("加载8583配置异常");
 98             }
 99         }
100         System.out.println("加载8583配置完成");
101     }
102 
103     public Map<String, Properties> getMap() {
104         return map;
105     }
106     
107     public Properties getFieldPropertie(String fieldName) {
108         return map.get(fieldName);
109     }
110     
111     public String getFieldPropertieVal(String fieldName,String propertieName) {
112         return map.get(fieldName).getProperty(propertieName);
113     }
114 
115 }
View Code

 

8583解析类

  1 package com.handle8583;
  2 
  3 import java.io.UnsupportedEncodingException;
  4 import java.util.ArrayList;
  5 import java.util.Collections;
  6 import java.util.Comparator;
  7 import java.util.HashMap;
  8 import java.util.List;
  9 import java.util.Map;
 10 import java.util.Properties;
 11 import java.util.Set;
 12 
 13 import com.parseToString.FileTools;
 14 /*
 15  * @description:
 16  * 准备包含8583报文头、报文类型标识、位图、报文体各域的ISO8583metadata.xml配置文件
 17  * 准备8583十六进制报文
 18  * 使用SAXReader读取ISO8583metadata.xml文件,将文件中的内容解析成Map<String,Properties>
 19  * 使用文件输入流读取8583十六进制报文到字节数组输出流,字节数组输出流转换为字节数组
 20  * 将字节数组转换成字符串,此刻字符串的内容与十六进制里的内容完全一致,并将字符串换行、空去掉
 21  * 将字符串转换成字节数组(即将十六进制转换成十进制的字节数组)
 22  * 解析报文头(根据ISO8583metadata.xml中:isBCD确定编码、length确定长度、encoding确定编码、name作为标签名。现根据长度截取,再判断isBCD编码,根据相应的编码解码。)
 23  * 解析报文类型标识(根据长度,byte子数组,根绝对应的encoding编码进行解码)
 24  * 解析位图(判断第一个字节的二进制最高位是否为1,为1则使用扩展位图,为0则不使用扩展位图;根据长度获取byte字数组,转换成对应的二进制;根据二进制判断存在哪些域有值)
 25  * 解析报文体(将存在的域循环进行处理:判断是否变长,如果变长,先获取变长所表示的长度值,比如n..11(LLVAR)为两位变长,有两个字节表示长度,先拿两个字节计算本域所占几个字节,再获取相应字节数,再根据encoding编码进行解码;如果非变长,直接根据length获取长度,再根据encoding编码进行解码)
 26  * 将解析完成的8583报文信息所在的Map排序,便于打印阅览(此处不再说明,看代码即可)
 27  * 
 28  * @warn注意点
 29  * 对于0~9的数字
 30  *         十六进制转换成十进制,相应于BCD码转换成十进制
 31  *         一个十六进制相当于一个byte,相当于两个[0,9]
 32  * 
 33  * @see
 34  * 8583报文拆组包关键点:
 35  *     报文头各域、表问类型标识、位图或者报文体域所使用的编码方式,比如BCD编码还是普通的十六进制
 36  *     位图的使用
 37  *     报文体域的变长处理
 38  * 
 39  * @see
 40  * 拆组包8583报文需要对于编码和解码、进制转换、字符集有一个充分和系统的了解
 41  */
 42 public class Parse8583 {
 43     static int currentIndex = 0;
 44     static Map<String, Properties> map = Bean8583Factory.getInstance().getMap();
 45     public static void main(String[] args) throws UnsupportedEncodingException {
 46         //获取8583报文
 47         byte[] resp = FileTools.readContent("D:/workspace/springweb/src/com/handle8583/8583resp.txt");
 48         String str = new String(resp).trim().replace("\r\n", "").replace("\r","").replace("\n", "").replace(" ", "");
 49         //将报文解析成字节数组
 50         byte[] retByte = parseTo8583bytes(str);
 51         //解析8583报文体
 52         Map<String,String> fieldMap = parse8583(retByte);
 53         //获取有序的keys
 54         List<String> keyList = getKeyList(fieldMap);
 55         //输出各域信息
 56         for(String key:keyList){
 57             System.out.println("["+key+"] = "+fieldMap.get(key));
 58         }
 59     }
 60 
 61     // 报文处理函数
 62     private static Map<String, String> parse8583(byte[] byteArr)
 63             throws UnsupportedEncodingException {
 64         Map<String,String> fieldMap = new HashMap<String,String>();
 65         //获取报文头信息
 66         parseHeaders(byteArr, fieldMap);
 67         // 获取MsgType
 68         parseMsgType(byteArr, fieldMap);
 69         // 获取位图
 70         String bitMap1_value = getBitMap(byteArr);
 71         fieldMap.put("F1", bitMap1_value);
 72         // 根据位图判断存在哪些域及获取域的值
 73         parseFields(byteArr, fieldMap, bitMap1_value);
 74         // 返回
 75         return fieldMap;
 76     }
 77     //获取报文头信息
 78     private static void parseHeaders(byte[] byteArr,Map<String, String> fieldMap)
 79             throws UnsupportedEncodingException {
 80         for(int i=1;i<=10;i++){
 81             Properties headProperties = map.get("H"+i);
 82             if(headProperties == null) continue;
 83             
 84             int head_length = Integer.parseInt(headProperties.getProperty("length"));
 85             byte[] head_value_byte = new byte[head_length];
 86             System.arraycopy(byteArr, currentIndex, head_value_byte, 0, head_length);
 87             currentIndex += head_length;
 88             
 89             String isBCD = headProperties.getProperty("isBCD");
 90             if("true".equals(isBCD)){
 91                 String head_value = bcd_bytes_to_String(head_value_byte);
 92                 fieldMap.put(headProperties.getProperty("name"), head_value);
 93             }else{
 94                 String head_value = new String(head_value_byte, headProperties.getProperty("encoding"));
 95                 fieldMap.put(headProperties.getProperty("name"), head_value);
 96             }
 97         }
 98     }
 99     //bcd_bytes_to_String
100     private static String bcd_bytes_to_String(byte[] bytes){
101         StringBuffer sb = new StringBuffer(bytes.length*2);
102         for(int i=0;i<bytes.length;i++){
103             sb.append(String.valueOf((int)bytes[i]));
104         }
105         return sb.toString();
106     }
107     //解析各个域
108     private static void parseFields(byte[] byteArr,Map<String, String> fieldMap,String bitMap1_value_2) throws UnsupportedEncodingException {
109         List<Integer> exitFieldList = getExitField(bitMap1_value_2);
110         // 获取各域值
111         for(int i=0;i<exitFieldList.size();i++){
112             int field = exitFieldList.get(i);
113             Properties fieldProperties = map.get("F"+field);
114             //如果不存在,跳过
115             if(fieldProperties == null)continue;
116             
117             String field_variable_flag = fieldProperties.getProperty("variable_flag");
118             if(field_variable_flag == null || "".equals(field_variable_flag)){
119                 int field_length = Integer.parseInt(fieldProperties.getProperty("length"));
120                 byte[] field_value_byte = new byte[field_length];
121                 System.arraycopy(byteArr, currentIndex, field_value_byte, 0, field_length);
122                 currentIndex += field_length;
123                 String field_value = new String(field_value_byte, fieldProperties.getProperty("encoding"));
124                 fieldMap.put(fieldProperties.getProperty("name"), field_value);
125             }else{
126                 //先获取变长域的长度值
127                 int variable_flag_length = Integer.parseInt(field_variable_flag);
128                 byte[] variable_flag_byte = new byte[variable_flag_length];
129                 System.arraycopy(byteArr, currentIndex, variable_flag_byte, 0, variable_flag_length);
130                 currentIndex += variable_flag_length;
131                 String variable_flag_value = new String(variable_flag_byte, fieldProperties.getProperty("encoding"));
132                 //再获取变长域的真实值
133                 int field_length = Integer.parseInt(variable_flag_value);
134                 byte[] field_value_byte = new byte[field_length];
135                 System.arraycopy(byteArr, currentIndex, field_value_byte, 0, field_length);
136                 currentIndex += field_length;
137                 String field_value = new String(field_value_byte, fieldProperties.getProperty("encoding"));
138                 fieldMap.put(fieldProperties.getProperty("name"), field_value);
139             }
140         }
141     }
142     //获取二进制位图字符串
143     private static String getBitMap(byte[] byteArr) {
144         Properties bitMap1 = map.get("bitmap1");
145         int bitMap1_length = Integer.parseInt(bitMap1.getProperty("length"));
146         byte[] bitMap1_value_byte = new byte[bitMap1_length];
147         System.arraycopy(byteArr, currentIndex, bitMap1_value_byte, 0,bitMap1_length);
148         currentIndex += bitMap1_length;
149         String bitMap1_value_2 = binary(bitMap1_value_byte, 2);
150         if (bitMap1_value_2.startsWith("1")) {
151             Properties bitMap2 = map.get("bitmap2");
152             int bitMap2_length = Integer.parseInt(bitMap2.getProperty("length"));
153             byte[] bitMap2_value_byte = new byte[bitMap2_length];
154             System.arraycopy(byteArr, currentIndex, bitMap2_value_byte, 0,bitMap2_length);
155             currentIndex += bitMap2_length;
156             String bitMap2_value_2 = binary(bitMap2_value_byte, 2);
157             bitMap1_value_2 += bitMap2_value_2;
158         }
159         return bitMap1_value_2;
160     }
161     //解析MsgType
162     private static void parseMsgType(byte[] byteArr,Map<String, String> mapRet)
163             throws UnsupportedEncodingException {
164         Properties msgType = map.get("MsgType");
165         int msgType_length = Integer.parseInt(msgType.getProperty("length"));
166         byte[] msgType_value_byte = new byte[msgType_length];
167         System.arraycopy(byteArr, currentIndex, msgType_value_byte, 0,msgType_length);
168         currentIndex += msgType_length;
169         String msgType_value = new String(msgType_value_byte, msgType.getProperty("encoding"));
170         mapRet.put("F0", msgType_value);
171     }
172     //根据二进制位图字符串获取存在的域
173     private static List<Integer> getExitField(String bitMap2String) {
174         List<Integer> exitFieldList = new ArrayList<Integer>();
175         for (int i=2;i<=bitMap2String.length();i++) {
176             int field_index = Integer.parseInt(String.valueOf(bitMap2String.charAt(i-1)));
177             if (field_index == 1) {
178                 exitFieldList.add(i);
179             }
180         }
181         return exitFieldList;
182     }
183     //将报文解析成字节数组
184     private static byte[] parseTo8583bytes(String str) {
185         String value = null;
186         byte[] retByte = new byte[str.length() / 2];
187         for (int i = 0; i < str.length(); i = i + 2) {
188             value = str.substring(i, i + 2);
189             retByte[i / 2] = (byte) Integer.parseInt(value, 16);
190         }
191         return retByte;
192     }
193     //获取有序的keys
194     private static List<String> getKeyList(Map<String, String> fieldMap) {
195         Set<String> keySet = fieldMap.keySet();
196         List<String> keyList = new ArrayList<String>(keySet);
197         Collections.sort(keyList, new Comparator<String>(){
198             @Override
199             public int compare(String str1, String str2) {
200                 // TODO Auto-generated method stub
201                 Integer value1 = Integer.parseInt(str1.substring(1));
202                 Integer value2 = Integer.parseInt(str2.substring(1));
203                 return value1.compareTo(value2);
204             }});
205         Collections.sort(keyList, new Comparator<String>(){
206             @Override
207             public int compare(String str1, String str2) {
208                 // TODO Auto-generated method stub
209                 char value1 = str1.charAt(0);
210                 char value2 = str2.charAt(0);
211                 return value1 < value2 ? 1 : 0;
212             }});
213         return keyList;
214     }
215     //将字节数组转换成二进制字符串
216     private static String binary(byte[] bytes, int radix) {
217         StringBuilder sb = new StringBuilder();
218         for (byte b : bytes) {
219             sb.append(byteToBit(b));
220         }
221         return sb.toString();
222     }
223     /**
224      * Byte转Bit
225      */
226     private static String byteToBit(byte b) {
227         return "" + (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
228                 + (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1)
229                 + (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
230                 + (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1);
231     }
232 
233 
234 }
View Code

 

posted @ 2016-10-21 16:42  独特之最  阅读(4399)  评论(0编辑  收藏  举报