最近在做POS接入涉及到如何正确解析ISO8583协议的问题,遇到了一些很讨厌的问题今天将他们总结一
下写在博客中,供大家参考。
1. 对于小白首先要了解什么是ISO8583协议,请参考该文章http://www.itpub.net/thread-419521-1-1.html 讲解的非常详细。2 .了解完ISO853协议以后,考虑用JAVA怎么解析8583协议报文。网上百度了下说到可以使用J8583CN来解析,下载地址http://sourceforge.net/projects/j8583cn/ 下载完后里 面有个example的目录运行Example.java就可以运行起来了。但是这里的J8583CN完全不能正常解析真实场合中的报文数据,
需要手工修改里面的解析方法。在这里我只说需要修改的几个重要点,其它要注意的地方大家参考部分资料就能解决了。
(a)根据《第七卷-中国银联POS前置系统指南》中讲到的ISO8583协议报文格式如下 TPDU+报文头+应用数据(ISO8583MSG)TPDU 说明:长度为10 个字节, 压缩时用BCD 码表示为5 个字节长度的数值。 报文头说明:总长度为12 字节,压缩时用BCD 码表示为6 个字节长度的数值。
如整消费交易消息:6132003215010200302004c020c09811000000000000000001000133021000123762258857
41255749d0000101296490017105603532303739303030303031333332303630313230303033313536e6b
52efda2c3f13726000000000000000014220006060006013242414635334638
消息头:613200321501(这个是自定义没有明确固定的数据,每家公司可能都不一样)
I SO8583数据:(
消息类型-0200
位图描述-302004c020c09811
位图数据-00000000000000000100013302100012376225885741255749d0000101296490017
105603532303739303030303031333332303630313230303033313536e6b52efda2c3f13726000000000000000014220006060006013242414635334638 )
(b)仔细阅读《第七卷-中国银联POS前置系统指南》中位图的详细描述
域22,3个字节的定长数字字符域,压缩时用右靠BCD码表示的2个字节的定长域。说明该位图数据在传输时使用BCD编码的
域63, ANS...163(LLLVAR),3个字节的长度值+最大163个字节的数据。压缩时用右靠BCD码表示的2个字节的长度值+用ASCII码表示的最大163个字节的数据。
仔细看位图描述就会发现有的域使用BCD编码,有的不是。问题就出在了那种变长的数据处理如LLVR和LLLVR的处理。
比如变长位域长度是经过BCD编码的,而对应的数据却不是BCD编码的或者数据是用ASCII码表示的(刚接触时不仔细看《第七卷-中国银联POS前置系统指南》会误认为都是BCD编码)。比如
44域 AN..25,2个字节长度+ 最大25个字节的数据。压缩时用右靠BCD码表示的1个字节的长度值+用ASCII码表示的最大25个字节的数据。60域 N...17(LLLVAR),3个字节的长度值+最大17个字节的数字字符域。压缩时用右靠BCD码表示的2个字节的长度值+用左靠BCD码表示的最大9个字节的数据。
这时候需要先读取BCD编码的数据长度,然后将BCD码转换为十进制数据,十进制数就是对应的数据长度。这时候根据长度取后面的数据需要区位图是BCD编码和ASCII码
1.如果变长是ASCII码:如果是ASCII码的方式直接根据分析的十进制整数乘以2就是对应待取数据的长度,
为什么要乘以2因为数据包通过POS机发出来的包都是经过BCD编码的,2位BCD码表示一字节,所以在
数据报文byte[]中需要乘以2.
2.如果是BCD编码的:算出来的长度不需要乘以2,但是如果长度是奇数需要加一变成偶数,因为经过BCD
编码位数不足会补0,所以需要判断奇数还是偶数长度。
这里已经描述完了解析时要注意的特别点。J8583CN中修改的文件是cnFieldParseInfo.java,修改的方法
"public cnValue<?> parse(byte[] buf, int pos, int bitSetIndex) throws ParseException " 修改方法中内容如下
if (type == cnType.LLVAR) {
//原始写法
//length = ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48);
//return new cnValue<String>(type, new String(buf, pos + 2, length));
//修改后的写法
if (bitSetIndex == 44) {
length = ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48);
length=length*2;
return new cnValue<String>(type, new String(buf, pos + 2, length));
} else {
length = ((buf[pos] - 48) * 10) + (buf[pos + 1] - 48);
// 修改caiqiang-2015-08-25 判断取数据如果是奇数加一个补成偶数
if (length % 2 == 1) {
length = length + 1;
}
return new cnValue<String>(type, new String(buf, pos + 2, length));
}
} else if (type == cnType.LLLVAR) {
//原始写法
//length = ((buf[pos] - 48) * 100) + ((buf[pos + 1] - 48) * 10) + (buf[pos + 2] - 48);
//return new cnValue<String>(type, new String(buf, pos + 3, length));
//修改后的写法
if (bitSetIndex == 63 || bitSetIndex == 62) {
String lengthBcd = new String(buf, pos, 4);// 取得BCD码数据
length = Hex.BCDtoInt(lengthBcd);// BCD码转换为十进制数据
length=length*2;
return new cnValue<String>(type, new String(buf, pos + 4, length));
} else {
String lengthBcd = new String(buf, pos, 4);// 取得BCD码数据
length = Hex.BCDtoInt(lengthBcd);// BCD码转换为十进制数据
// 判断奇数还是偶数 压缩BCD码后是偶数长度
if (length % 2 == 1) {
length = length + 1;
}
return new cnValue<String>(type, new String(buf, pos + 4, length));
}
}
原始报文如:6132003215010200302004c020c0981100000000000000000100013302100012376225
885741255749d000010129649001710560353230373930303030303133333230363031323030303331
3536e6b52efda2c3f13726000000000000000014220006060006013242414635334638
10:07:32,599 DEBUG: parsing config from xml file: [config.xml]typeid: [0200]
hearder: [613200321501]
位图数据: [302004c020c09811]
bitmap data(binary format): [0011000000100000000001001100000000100000110000001001100000010001]
bitmap(1-128): [{3, 4, 11, 22, 25, 26, 35, 41, 42, 49, 52, 53, 60, 64}]
fieldid=[3] <NUMERIC> [000000] ---> [000000]
fieldid=[4] <AMOUNT> [000000000001] ---> [0.01]
fieldid=[11] <ALPHA> [000133] ---> [000133]
fieldid=[22] <NUMERIC> [0210] ---> [0210]
fieldid=[25] <NUMERIC> [00] ---> [00]
fieldid=[26] <NUMERIC> [12] ---> [12]
fieldid=[35] <LLVAR> [6225885741255749d000010129649001710560] ---> [6225885741255749d000010129649001710560]
fieldid=[41] <ALPHA> [3532303739303030] ---> [3532303739303030]
fieldid=[42] <ALPHA> [303031333332303630313230303033] ---> [303031333332303630313230303033]
fieldid=[49] <ALPHA> [313536] ---> [313536]
fieldid=[52] <ALPHA> [e6b52efda2c3f137] ---> [e6b52efda2c3f137]
fieldid=[53] <ALPHA> [2600000000000000] ---> [2600000000000000]
fieldid=[60] <LLLVAR> [22000606000601] ---> [22000606000601]
fieldid=[64] <ALPHA> [3242414635334638] ---> [3242414635334638]