java 8583报文解析_ISO8583报文工具类(组装和解析报文) | 学步园

本文介绍了Java实现的ISO8583报文工具类,用于组装和解析银行领域的8583报文。详细讨论了报文结构、位图处理、定长与变长域的处理,并提供了代码示例,帮助读者快速理解和应用ISO8583报文处理。
摘要由CSDN通过智能技术生成

很久没来csdn了。现在的工作地点在银行,妈的,不让上网啊。

写写博客其实是对自己知识的总结,这么长时间了,也该写点东西了。接触银行的项目,避免不了

遇上8583报文。具体介绍就不细讲了,这个网上一大堆介绍的。关键是怎么去组装和解析8583报文?

这个代码还真不好找。在此,我把自己的研究写成一个工具类,看的懂其实很好改写,看不懂就直接拿去用吧。

package com.lsy.common.util;

import java.io.FileInputStream;

import java.io.UnsupportedEncodingException;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Properties;

import java.util.TreeMap;

/**

*

* 这是本人写的ISO8583报文工具类,包含了报文的组装和解析。

*

* 简单介绍下ISO8583。

* 这个东西说白了就是一种数据结构。我们定义一种规则把一堆东西放进去,再按照规则

* 把数据正确拿出来。这就是报文的实质。

*

* ISO8583报文的结构是:前面有16字节(128位)位图数据,后面就是数据。

* 报文最多有128个域(字段)。具体的一个报文不会有这么多,一般是几个域。

* 有哪几个就记录在位图中。而且域有定长和变长之分。

* 这些都是事先定义好的,具体可以看我写的properties定义文件.

*

* 位图转化成01字符串就是128个,如果某一位是1,代表这个域有值,然后按照properties定义的规则取值。

* 如果是0,则这个域没有值。

*

* 再说定长和变长。

* 定长域(定长比较好理解,一个字段规定是N位,那么字段值绝对不能超过N位,不足N位就在后面补空格)

* 变长域(变长域最后组装成的效果:例如变长3位,定义var3,这里的3是指长度值占3位,字段值是123456,最后结果就是006123456)

* 注意(变长的长度按照域值得字节长度计算,而不是按照域值字符串长度算!)

*

* 从网上不难找到ISO8583报文的介绍,这里就不多说了。

* 但是具体解析和组装的代码还真不好找,所以本人就写了一个让刚接触ISO8583报文的人更好入门。

*

*

*

* 解析的容器,我使用了Map,具体到工作中,还是要换成其他的容器的。

* 报文定义说明:config_8583.properties

* 例如

* FIELD031 = string,10

* FIELD032 = string,VAR2

*

* FIELD031是定长,长度是10

* FIELD032是变长,长度值占2位,也就是说长度值最大99,也就是域值最大长度99.

*

* @author lushuaiyin

*

*/

public class Lsy8583Util {

public static String packet_encoding="UTF-8";//报文编码 UTF-8 GBK

private static Map map8583Definition = null;// 8583报文128域定义器

static{

String basepath=Lsy8583Util.class.getClassLoader().getResource("").getPath();

System.out.println(basepath);

System.out.println("Lsy8583Util使用编码配置:[encoding:"+packet_encoding+"]");

Properties property = new Properties();

String path = basepath+"/config_8583.properties";

FileInputStream fis;

try {

fis = new FileInputStream(path);

property.load(fis);

Lsy8583Util.map8583Definition = new HashMap(property);

fis.close();

} catch (Exception e) {

e.printStackTrace();

}

}

// 8583报文初始位图:128位01字符串

public static String getInitBitMap(){

String initBitMap =

"10000000" + "00000000" + "00000000" + "00000000"

+ "00000000" + "00000000" + "00000000" + "00000000"

+ "00000000" + "00000000" + "00000000" + "00000000"

+ "00000000" + "00000000" + "00000000" + "00000000";

return initBitMap;

}

/**

* @param args

*/

public static void main(String[] args) {

try {

//***********************组装8583报文测试--start***********************//

TreeMap filedMap=new TreeMap();//报文域

filedMap.put("FIELD003", "1799");//交易码

filedMap.put("FIELD013", "2013-11-06");//交易日期

filedMap.put("FIELD008", "12345678901");//账号

filedMap.put("FIELD033", "aa索隆bb");//注意这个域是变长域!

filedMap.put("FIELD036", "123456");//注意这个域是变长域!

byte[] send=make8583(filedMap);

System.out.println("完成组装8583报文=="+new String(send,packet_encoding)+"==");

//***********************组装8583报文测试--end***********************//

//***********************解析8583报文测试--start***********************//

Map back=analyze8583(send);

System.out.println("完成解析8583报文=="+back.toString()+"==");

//***********************解析8583报文测试--end***********************//

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

}

/**

* 组装8583报文

* @param hm

* @return

*/

public static byte[] make8583(TreeMap filedMap){

byte[] whoe8583=null;

if(filedMap==null){

return null;

}

try {

String bitMap128=getInitBitMap();//获取初始化的128位图

//按照8583定义器格式化各个域的内容

Map all=formatValueTo8583(filedMap,bitMap128);

// 获取上送报文内容

whoe8583=getWhole8583Packet(all);

return whoe8583;

} catch (Exception e) {

e.printStackTrace();

}

return whoe8583;

}

/**

* 获取完整的8583报文体(128域)

* @param pacBody

* @return

*/

public static byte[] getWhole8583Packet(Map all){

if(all==null||a

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最近在做中国银行的一个快捷支付渠道,使用的是 ISO8583 协议,一开始用的是JPOS框架,但是感觉框架比较臃肿,而且文档也比较少。在等待银行专线的过程中,自己闭门造车做了一个简单的8583报文解析框架 —— Simple8583,将程序重写了一遍,渠道中的代码量少了不少,这几天中行的接口在测试环境终于调试完成了。抽空分享一下这段时间自己学到的知识。 数据类型与编码格式: 根据接触到的数据类型将数据分为如下几种类型:          CHAR(asc编码,直接使用字符串的getBytes(ENCODING)方法获取字节数组)   BINARY(二进制编码,在打包时将8位01值组装为一个字节),             NUMERIC(BCD编码,即8421码),                LLVAR(变长域,采用ASC编码,每个LLVAR类型的域前会有1字节的域字节长度,表示长度的字节用BCD编码表示)                LLLVAR(变长域,与LLVAR域类似,不同之处在于每个LLLVAR域前会有2字节的域字节长度,长度同样以BCD编码表示)             LLVAR_NUMERIC(变长域,采用BCD编码,前有1字节的长度,长度为域值的长度,而非字节长,如域值为123456,编码后长度为3字节,但是表示域长的字节值为6)       如果用到其它数据类型可以在IsoType中进行添加,并在IsoField中添加处理操作 BitMap:        BitMap是ISO8583报文的精髓所在,ISO8583报文支持64域和128域两种,但是并非每次请求都会将所有域都请求过去,BItMap就起到了标识哪些域是有效的请求域,接收方也会根据BitMap中约定的值对域进行解析。   那么BitMap又是如何工作的呢?          首先,BItMap分为8字节和16字节两种情况,分别表示支持64域和128域,其第一位值为1,表示BitMap为16字节,否则为8字节。       其次,BitMap中的每一位对应数据域的第几域,有效域会置为1,比如01001000表示第二域和第5域为有效位。 在Simple8583中具体的实现是通过BitMap类实现的,具体可参考源码。 mti:            mti即 message type identifier消息类型标识,为4位bcd编码的数字标识符,用于描述信息的类型。 同一个mti可以用于标识多个不同的交易,比如一般常用的0200可以用来表示消费交易,消费撤销,分期付款消费和分期付款撤销,但是对于同一个mti标识的数据域类型定义是类似的。           具体的实现,我将Simple8583的xml文件设置为了两部分,一部分为公用的报文头,如msgLength,tpdu,bitmap等,另外一部分分按照mti的不同分为多个package体。 粗略的实现流程:          1)组装请求的Map数据(只组装需要的数据域,key值为对应的数据域或包头的值)          2)请求数据进入SimpleClient代理,SimpleClient根据传入的值解析xml文件(jaxb实现,做了缓存)          3)根据传入值的mti寻找对应的IsoPackage类,对找到的IsoPackage类进行clone(避免污染),对clone值中的域进行值处理和格式化         4)生成BitMap,计算Mac值(如有)          5)使用ByteArrayOutputStream将组装成的IsoPackage域值进行拼装成为一个大的byte数组,在byte前拼装两个字节的长度          6)通过Socket将数据发送并接受响应(读取前两个字节长度,根据长度获取其剩余报文),根据IsoPackage解析报文域,解析得到BitMap后根据BitMap对数据域进行解析,并将值都放入到对应的field中          7)将数据都放在Map中返回,并进行MAC校验(如有) 标签:Simple8583
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值