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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM