8583报文解析1.0
8583报文解析1.0
文章目录
- 8583报文解析1.0
- 一、规则
- 1.1:域规范简表
- 1.2:规范说明
- 1.2.1: 报文头
- 1.2.2: 操作类型
- 1.2.3: 位图:有效域明细
- 1.2.4:域规范简表的表达解释
- 1.2.5:域长度说明
- 二、代码
- 2.1:工具类
- 2.2:解析结果对象
一、规则
6000030000613200321001
0200
7024068420C48A11
166224242900000097
000000
000000006633
000737
2806
0720
0000
00
A557408463A49AB0A96CEA1BCEF80F88
48797BEED5677DCD7996A2A9ED47D0F33F5FFEFB806712582E
3836303030393032
383433313735303738333241494C4C
00725049303637303430323032303531373030303033313032393031373039323339383934373135303630363030303039373037303834314632443443453038303856312E322E392020
313536
0600000000000000
01329F260857A5387B3B16E7949F2701809F101307011703A00000010A0100000000006821587C9F3704065893499F360202C5950500000000009A031901119C01009F02060000000066335F2A02015682027C009F1A0201569F03060000000000009F3303E0E1C89F3501228408A0000003330101029F090200309F1E086D6639305F303100
001422000005000601
4630443332384230
1.1:域规范简表
- 域的定义是基本业内规范,但是不代表要完全跟随规范,不同的项目需求不一样,与规范会有极小差异。
- 这里仅供参考。
域 | 长度(字符) | 规则说明 |
---|---|---|
报文头 | 26 | |
0 | 4 | 操作类型 |
1 | 16 | 有效的域的定义,16进制格式 |
2 | 2+len | 主账号,前1个字节定义内容长度 |
3 | 6 | 交易处理码 |
4 | 12 | 交易金额 |
5 | ||
6 | ||
7 | ||
8 | ||
9 | ||
10 | ||
11 | 6 | 受卡方系统跟踪号 |
12 | 6 | 受卡方所在地时间,格式:hhmmss |
13 | 4 | 受卡方所在地日期,格式:MMDD |
14 | 4 | 卡有效期,格式:YYMM |
15 | 4 | 清算日期,格式:MMDD |
16 | ||
17 | ||
18 | ||
19 | ||
20 | ||
21 | ||
22 | 3 | 服务点输入方式码 |
23 | 3 | 卡序列号 |
24 | ||
25 | 2 | 服务点条件码 |
26 | 2 | 服务点PIN获取码 |
27 | ||
28 | ||
29 | ||
30 | ||
31 | ||
32 | 2+len | 受理机构标识码,前1个字节定义内容长度 |
33 | ||
34 | ||
35 | 2+len | 2磁道数据,前1个字节定义内容长度 |
36 | 4+len | 3磁道数据,前2个字节定义内容长度 |
37 | 12 | 检索参考号 |
38 | 6 | 授权标识应答码 |
39 | 2 | 应答码 |
40 | ||
41 | 8*2 | 受卡机终端标识码 |
42 | 15*2 | 受卡方标识码 |
43 | ||
44 | 2+len | 附加响应数据,前1个字节定义内容长度 |
45 | ||
46 | ||
47 | ||
48 | 4+len | 附加数据-私有,前2个字节定义内容长度 |
49 | 3*2 | 交易货币代码 |
50 | ||
51 | ||
52 | 8*2 | 个人标识码数据 |
53 | 16 | 安全控制信息 |
54 | 4+len | 余额,前2个字节定义内容长度 |
55 | 4+len | IC卡数据域,前2个字节定义内容长度 |
56 | ||
57 | ||
58 | 4+len | PBOC电子钱包标准的交易信息,前2个字节定义内容长度 |
59 | 4+len | 自定义域,前2个字节定义内容长度 |
60 | 4+len | 自定义域,前2个字节定义内容长度 |
61 | 4+len | 原始信息域,前2个字节定义内容长度 |
62 | 4+len | 自定义域,前2个字节定义内容长度 |
63 | 4+len | 自定义域,前2个字节定义内容长度 |
64 | 16 | 报文鉴别码 |
1.2:规范说明
1.2.1: 报文头
- 目前未找到准确拆解报文头的线管教学,期待后续补充…
1.2.2: 操作类型
- 位于报文体0域,固定2字节的数字
请求码 | 响应码 | 类型说明 |
---|---|---|
0200 | 0210 | 余额查询磁条卡消费银联扫码银联posp扫码 |
0220 | 0230 | 打印确认通知 |
0400 | 0410 | 冲正 |
0500 | 0510 | 批结算 |
0700 | 0710 | 微信二维码微信扫码支付宝二维码支付宝扫码银联二维码银联二维码状态查询 |
0800 | 0810 | 签到参数下载 |
0820 | 0830 | 签退pos状态上送 |
0840 | 0850 | 主秘钥下载 |
1.2.3: 位图:有效域明细
- 位于报文体1域,固定8字节的16进制字符
- 以案例为例:
7024068420C48A11
- 先把值转换成二进制:
0111000000100100000001101000010000100000110001001000101000010001
- 长度刚好64位,分别对应64个域,
1
代表报文中有该域的存在
1.2.4:域规范简表的表达解释
求生本能解释:纯个人理解的定义,有误请及时提出,谢谢。
- 域:报文从报文头往后,每一段有意义的字符串
- 域长度:分为固定长和自定义长
2.1 固定长:以简表中 纯数字 表示
2.2 自定义长:以简表中“数字+len”表示
2.2.1 数字:“长度标识”占据“数字”个字符,“长度标识”代表该域内容长度的数字(不包含标识本身)
2.2.2 len:该域内容长度(不包含标识本身),长度根据不同的压缩方式存在倍数差异,两倍长或三倍长
1.2.5:域长度说明
- 域长度以字节为单位,所以如果长度是5个字符,实为后补0的6个字符长度(简单理解为长度必须偶数)
- 传输的报文可能经过压缩的,但“长度标识”描述的长度是原文的长度,因此长度存在倍数差异
二、代码
- 默认解析规则仅根据李大爷目前项目常见规定而定
- 只做了初步拆解,并不涉及子域解析,请酌情享用(有时间会考虑2.0版本)
2.1:工具类
import com.lidaye.test.porttest.Test8583.enums.Msg8583;import java.util.*;/*** @author lidaye* @date 2022/6/28*/
public class Test8583 {/*** 默认域解析规则*/private final static Map<Integer, String> DEFAULT_RULE = new HashMap<>(64);/*** 类型校验规则*/private final static Set<String> TYPE_CHECK_LIST = new HashSet<>();static {/** 默认域解析规则赋值 **/// 请求头DEFAULT_RULE.put(-1,"22");// 操作类型DEFAULT_RULE.put(0,"4");// 位图DEFAULT_RULE.put(1,"16");// 业务域DEFAULT_RULE.put(2,"2-1");DEFAULT_RULE.put(3,"6");DEFAULT_RULE.put(4,"12");DEFAULT_RULE.put(11,"6");DEFAULT_RULE.put(12,"6");DEFAULT_RULE.put(13,"4");DEFAULT_RULE.put(14,"4");DEFAULT_RULE.put(15,"4");DEFAULT_RULE.put(22,"3");DEFAULT_RULE.put(23,"3");DEFAULT_RULE.put(25,"2");DEFAULT_RULE.put(26,"2");DEFAULT_RULE.put(32,"2-1");DEFAULT_RULE.put(35,"2-1");DEFAULT_RULE.put(36,"4-1");DEFAULT_RULE.put(37,"12");DEFAULT_RULE.put(38,"6");DEFAULT_RULE.put(41,"16");DEFAULT_RULE.put(42,"30");DEFAULT_RULE.put(44,"2-1");DEFAULT_RULE.put(46,"4-2");DEFAULT_RULE.put(48,"4-1");DEFAULT_RULE.put(49,"6");DEFAULT_RULE.put(52,"16");DEFAULT_RULE.put(53,"16");DEFAULT_RULE.put(54,"4-1");DEFAULT_RULE.put(55,"4-2");DEFAULT_RULE.put(58,"4-1");DEFAULT_RULE.put(59,"4-1");DEFAULT_RULE.put(60,"4-1");DEFAULT_RULE.put(61,"4-1");DEFAULT_RULE.put(62,"4-4");DEFAULT_RULE.put(63,"4-4");DEFAULT_RULE.put(64,"16");// 类型校验规则赋值TYPE_CHECK_LIST.add("0100");TYPE_CHECK_LIST.add("0110");TYPE_CHECK_LIST.add("0200");TYPE_CHECK_LIST.add("0210");TYPE_CHECK_LIST.add("0220");TYPE_CHECK_LIST.add("0230");TYPE_CHECK_LIST.add("0320");TYPE_CHECK_LIST.add("0330");TYPE_CHECK_LIST.add("0400");TYPE_CHECK_LIST.add("0410");TYPE_CHECK_LIST.add("0500");TYPE_CHECK_LIST.add("0510");TYPE_CHECK_LIST.add("0620");TYPE_CHECK_LIST.add("0630");TYPE_CHECK_LIST.add("0800");TYPE_CHECK_LIST.add("0810");TYPE_CHECK_LIST.add("0820");TYPE_CHECK_LIST.add("0830");TYPE_CHECK_LIST.add("0920");TYPE_CHECK_LIST.add("0930");}/*** 解析入口* 解析规则格式:域 => 规则(纯数字:长度以值固定,带符号“-”:)* 解析规则格式-规则:* * 1. 纯数字:长度以值固定* * 2. 带符号“-”:域长度标识的长度-长度倍数,如下案例,35域以头2位作为长度标识,内容长度为长度的2倍长(纯数字/ASCII=1、十六进制=2、二进制=4)* 解析规则样例:{-1:"0",35:"2-2"}* @param s8583 8583原文* @param ruleMap 报文解析规则* @return*/public static Msg8583 analysis(String s8583, Map<Integer, String> ruleMap) {// 报文长度异常,解析失败if (Objects.isNull(s8583) || s8583.length() < 22) { return null; }// 默认值赋值DEFAULT_RULE.forEach(ruleMap::putIfAbsent);// 计步器int pointer = 0;// 解析结果Msg8583 msg8583 = new Msg8583();/** 报文头 **/int headLen = Integer.parseInt(ruleMap.get(-1));msg8583.setHead(s8583.substring(pointer, headLen));pointer = headLen;/** 报文体 **/Map<Integer, String> regionMap = new TreeMap<>();msg8583.setRegionMap(regionMap);// 操作类型String type = s8583.substring(pointer, pointer + 4);if (!checkType(type)) {msg8583.setMsg("报文类型或报文头识别异常");return msg8583;}regionMap.put(0,type);pointer += 4;// 位图,有效的域String validRegion = s8583.substring(pointer, pointer + 16);regionMap.put(1,validRegion);pointer += 16;List<Integer> regionNumList = readValidRegion(validRegion);if (Objects.isNull(regionNumList) || regionNumList.isEmpty()) {msg8583.setMsg("位图识别异常");return msg8583;}msg8583.setRegionNumList(regionNumList);// 遍历拆解接下来的域for (Integer regionNum : regionNumList) {String value;try {value = readRegion(regionNum, pointer, s8583, ruleMap);}catch (Exception e) {msg8583.setMsg(regionNum+"域解析失败");break;}if (Objects.isNull(value)) {msg8583.setMsg(regionNum+"域解析失败");break;}regionMap.put(regionNum,value);pointer += value.length();}// 最后如果没报错,检查下是不是完全解析完了if (Objects.isNull(msg8583.getMsg())&& pointer != s8583.length()) {msg8583.setMsg("解析失败,仍有剩余内容未解析:"+s8583.substring(pointer));}return msg8583;}/*** 读一个域的内容(包含长度)* @param regionNum 域号* @param pointer 指针位置* @param s8583 8583原文* @param ruleMap 域解析规则* @return*/private static String readRegion(int regionNum, int pointer, String s8583, Map<Integer, String> ruleMap) {// 取外设的规则String ruleStr = ruleMap.get(regionNum);// 解析失败:规则识别不到if (ruleStr == null || "".equals(ruleStr)) { return null; }// 拆解配置的规则:长度位数-倍率String[] rule = ruleStr.split("-");int len = Integer.parseInt(rule[0]);// 固定长度if (rule.length == 1) {return s8583.substring(pointer, pointer + ceilToEven(len));}// 读长度Integer length = Integer.parseInt(s8583.substring(pointer, pointer + len));// 倍率值int multipleNum = Integer.parseInt(rule[1]);return s8583.substring(pointer,pointer + ceilToEven(len + length * multipleNum));}/*** 解读1域:有效域列表* @param validRegion 1域值* @return*/private static List<Integer> readValidRegion(String validRegion) {List<Integer> resList = new ArrayList<>();String binary = hexToBinary(validRegion);if (Objects.isNull(binary)) { return null; }char[] validArr = binary.toCharArray();for (int i = 0; i < validArr.length; i++) {if (validArr[i] == '1') { resList.add(i+1); }}return resList;}/*** 十六进制转二进制* @param hex 十六进制字符串* @return*/private static String hexToBinary(String hex) {StringBuilder res = new StringBuilder();for (char c : hex.toCharArray()) {StringBuilder binary = new StringBuilder("0000");if (c >= '0' && c <= '9') {binary.append(Integer.toBinaryString(Integer.parseInt(c + "")));}if (c == 'A') {binary.append(Integer.toBinaryString(10));}if (c == 'B') {binary.append(Integer.toBinaryString(11));}if (c == 'C') {binary.append(Integer.toBinaryString(12));}if (c == 'D') {binary.append(Integer.toBinaryString(13));}if (c == 'E') {binary.append(Integer.toBinaryString(14));}if (c == 'F') {binary.append(Integer.toBinaryString(15));}if (binary.length() == 4) { return null; }res.append(binary.substring(binary.length()-4));}return res.toString();}/*** 检查类型* @param type* @return*/private static boolean checkType(String type) {return TYPE_CHECK_LIST.contains(type);}/*** 向上取偶数* 1个字节占两位,报文内容不可能占半个字节,所以向上多取一位,取满一个字节* @param num 数值* @return*/private static int ceilToEven(int num) {return num%2 == 0? num: num + 1;}/*** 测试案例* @param args*/public static void main(String[] args) {// 8583报文String baowen = "600003000061320032100102007024068420C48A1116622424290000009700000000000000663300073728060720000000A557408463A49AB0A96CEA1BCEF80F8848797BEED5677DCD7996A2A9ED47D0F33F5FFEFB806712582E3836303030393032383433313735303738333241494C4C00725049303637303430323032303531373030303033313032393031373039323339383934373135303630363030303039373037303834314632443443453038303856312E322E392020313536060000000000000001329F260857A5387B3B16E7949F2701809F101307011703A00000010A0100000000006821587C9F3704065893499F360202C5950500000000009A031901119C01009F02060000000066335F2A02015682027C009F1A0201569F03060000000000009F3303E0E1C89F3501228408A0000003330101029F090200309F1E086D6639305F3031000014220000050006014630443332384230";// 特殊规则,与默认规则不一致的Map<Integer, String> ruleMap = new HashMap<>();ruleMap.put(30,"32");// 解析打印System.out.println(analysis(baowen,ruleMap));}
}
2.2:解析结果对象
import lombok.Data;import java.util.List;
import java.util.Map;
import java.util.Optional;/*** 8583解析结果* @author lidaye* @date 2022/6/30*/
@Data
public class Msg8583 {/*** 请求头*/private String head;/*** 位图解析出来的有效域*/private List<Integer> regionNumList;/*** 域数据*/private Map<Integer, String> regionMap;/*** 错误提示信息*/private String msg;@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append("[解析结果]:");sb.append(Optional.ofNullable(msg).orElse("解析成功"));sb.append("\r\n");sb.append("[头部]:");sb.append(head);sb.append("\r\n");sb.append("[有效域]:");sb.append(regionNumList);sb.append("\r\n");regionMap.forEach((k,v) -> {sb.append('[');sb.append(k);sb.append("]:");sb.append(v);sb.append("\r\n");});return sb.toString();}
}
8583报文解析1.0相关推荐
- 银联银行卡交换系统8583报文解析
前言 最近在做8583报文这块解析,也遇到一些坑.下面将会介绍自己学习和了解8583报文这块的经验,希望可以帮到那些刚刚接触8583报文的同学们. 入门 首先我们需要知道的是我们的8583报文是基于P ...
- Go语言银联8583报文解析库,支持联小额免密付和银商聚合支付
很早之前就整过一个Go语言版的银联8583报文解析库,当时仅是8583报文的解析. 最近整合了进了银联小额双免交易和银商的聚合支付交易通道,这可以是网上最简单的8583报文解析库了. 银联双免支付通道 ...
- 第一章 银联8583报文解析
1报文格式定义 POS终端上送POS中心的消息报文结构包括TPDU.报文头和应用数据三部分: -- TPDU说明:长度为10个字节, 压缩时用BCD码表示为5个字节长度的数值. -- 报文头说明:总长 ...
- 《中国银联银联卡受理终端应用规范》笔记(1)银联8583报文解析
0. 前言 阅读的规范版本为20140404修订版 1. 报文格式说明 POS终端上送POS中心的消息报文结构包括TPDU.报文头和应用数据三部分: TPDU 报文头 应用数据 ISO8583 Msg ...
- java 8583报文解析_ISO8583报文工具类(组装和解析报文) | 学步园
很久没来csdn了.现在的工作地点在银行,妈的,不让上网啊. 写写博客其实是对自己知识的总结,这么长时间了,也该写点东西了.接触银行的项目,避免不了 遇上8583报文.具体介绍就不细讲了,这个网上一大 ...
- 8583 报文解析过程
一. 全局概述 1. <多渠道平台接入接口规范>这个标准规定了各种接入端(主要包括直联多渠道平台的终端, 包括这里主要关注的POS机)与中国银联多渠道平台之间进行联机交易时使用的报文接口, ...
- 8583报文解析实例介绍
现在我们有ISO8583报文如下(十六进制表示法): 60 00 03 00 00 60 31 00 31 07 30 02 00 30 20 04 C0 20 C0 98 11 00 00 00 0 ...
- java 8583报文解析_8583报文 55域JAVA的解析
银联55域 : 本域将根据不同的交易种类包含不同的子域.银联处理中心仅在受理方和发卡方之间传递这些适用于IC卡交易的特有数据,而不对它们进行任何修改和处理. 为适应该子域需要不断变化的情况 ,本域 ...
- java 8583报文解析_java解析8583报文55域
package com.xq.src; import java.util.ArrayList; import java.util.HashMap; import java.util.List; imp ...
最新文章
- OKR案例:德勤如何引入OKR
- UNIX网络编程——UDP缺乏流量控制(改进版)
- idea中build项目之后生成的target看不见
- python怎么网络通信_深入Python中的网络通信
- Light Head R-CNN论文笔记
- 1.1 objective-c中的内存管理
- 操作索引库-创建索引库
- C++set容器-内置类型指定排序
- C++ 普通函数与函数模板 区别以及调用规则01
- 有问有答 | 算法和数据结构精华问答
- “3D几何与视觉技术”全球在线研讨会第四期~几何深度学习
- 设计模式之Observer(观察者)模式
- 长宽相等的矩阵(二维数组)逆时针旋转90度
- python paramiko_Python3之paramiko模块
- 盈不足术与老鼠打洞问题的近似解
- centos7 php多版本切换_CentOS7服务搭建----搭建私有云盘01
- 在C/C++中使用输入输出流
- bat脚本重启IIS中的网站
- java中strictfp么意思_java中的strictfp的作用
- 微信小程序日期选择器控件xxxx-xx-xx格式