在此只寫了一個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
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>
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 }
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 }