我正在尝试解析ISO 8583消息并获取单个数据元素。 下面是我到目前为止尝试过的代码
ISOResponse.java
public class ISOResponse {
private static final String TAG = "ISOResponse";
private static final String ISOResponseMessage = "60010203040210303800000E8002000000000000000031000046741306511212383334363133303034363734313330363534303036323730353532340012910A59218CDAFBBCD2520014";
public void parseISO8583(final Context context) throws ParseException, IOException {
MessageFactory<IsoMessage> messageFactory = new MessageFactory<IsoMessage>();
if (1 == 0) {
ConfigParser.configureFromDefault(messageFactory);
} else {
PrintLog.log(TAG, "Messagefactory is done");
InputStream inputData = context.getResources().openRawResource(R.raw.j8583_config);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputData));
ConfigParser.configureFromReader(messageFactory, bufferedReader);
}
messageFactory.setIgnoreLastMissingField(true);
IsoMessage isoMessage = messageFactory.parseMessage(ISOResponseMessage.getBytes(),10);
if (isoMessage != null) {
PrintLog.log(TAG, "Message type: %04x%n" + isoMessage.getType());
PrintLog.log(TAG, "FIELD TYPE VALUE");
for (int i = 2; i <= 64; i++) {
IsoValue<?> f = isoMessage.getField(i);
if (f != null) {
PrintLog.log(TAG, "%5d %-6s [" + i + f.getType());
PrintLog.log(TAG, f.toString());
PrintLog.log(TAG, "" + ']');
}
}
}
}
}
j8583_config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE j8583-config PUBLIC "-//J8583//DTD CONFIG 1.0//EN"
"http://j8583.sourceforge.net/j8583.dtd">
<j8583-config>
<!-- This is a test config file -->
<!-- These are the ISO headers to be prepended to the message types specified -->
<header type="0800"/>
<template type="0280">
<field num="3" type="NUMERIC" length="2">99</field>
</template>
<!-- The server example uses this to read the requests -->
<parse type="0200">
<field num="3" type="NUMERIC" length="6" />
<field num="4" type="AMOUNT" />
<field num="7" type="DATE10" />
<field num="11" type="NUMERIC" length="6" />
<field num="12" type="TIME" />
<field num="13" type="DATE4" />
<field num="15" type="DATE4" />
<field num="17" type="DATE_EXP" />
<field num="32" type="LLVAR" />
<field num="35" type="LLVAR" />
<field num="37" type="NUMERIC" length="12" />
<field num="41" type="ALPHA" length="16" />
<field num="43" type="ALPHA" length="40" />
<field num="48" type="LLLVAR" />
<field num="49" type="ALPHA" length="3" />
<field num="60" type="LLLVAR" />
<field num="61" type="LLLVAR" />
<field num="100" type="LLVAR" />
<field num="102" type="LLVAR" />
</parse>
<!-- The client example uses this to read the responses -->
<parse type="0210">
<field num="3" type="NUMERIC" length="6" />
<field num="4" type="AMOUNT" length="12" />
<field num="11" type="NUMERIC" length="6" />
<field num="12" type="TIME" length="6" />
<field num="13" type="DATE4" length="4" />
<field num="37" type="NUMERIC" length="12" />
<field num="38" type="NUMERIC" length="6" />
<field num="39" type="NUMERIC" length="2" />
<field num="41" type="ALPHA" length="8" />
<field num="55" type="LLLVAR" length="255" />
</parse>
<!-- this is for binary tests (message encoding AND fields) -->
<parse type="0600">
<field num="4" type="AMOUNT" />
<field num="7" type="DATE10" />
<field num="11" type="NUMERIC" length="6" />
<field num="41" type="BINARY" length="8" />
<field num="42" type="BINARY" length="4" />
<field num="43" type="ALPHA" length="40" />
<field num="62" type="LLBIN" />
<field num="63" type="LLBIN" />
<field num="64" type="LLLBIN" />
<field num="65" type="LLLBIN" />
<field num="102" type="LLLVAR" />
</parse>
<parse type="0800">
<field num="3" type="ALPHA" length="6"/>
<field num="12" type="DATE4" length="14"/>
<field num="17" type="DATE4" length="8"/>
<field num="11" type="NUMERIC" length="6"/>
<field num="41" type="LLVAR" length="16"/>
</parse>
<parse type="0810" extends="0800">
<field num="17" type="exclude"/>
<field num="39" type="ALPHA" length="2"/>
</parse>
<parse type="0201">
<field num="3" type="NUMERIC" length="19" />
</parse>
<parse type="0202">
<field num="3" type="NUMERIC" length="22" />
</parse>
<parse type="0280">
<field num="3" type="NUMERIC" length="2" />
</parse>
此后,我的代码将引发
无效的ISO 8583标头
例外。我尝试删除标头数据并在isoMessage
中使标头长度为0,但仍然给出相同的异常。
任何人都可以帮助我找到代码错误。 预先感谢。
答案 0 :(得分:0)
我尝试解析您的消息,我知道了:
False
看来您的邮件标题长度为14,其中包括 MTI (或10,不含 MTI )
答案 1 :(得分:0)
我建议使用另一种方法来打包和拆包邮件。 iso-8583-packer允许您将邮件解压缩到以下字段
<f>
<f name="Header" val="6001020304" valHex="6001020304"/>
<f name="MTI" val="0210" valHex="0210"/>
<f name="Bitmap" bitmapHex="303800000E800200" bitSet="{3, 4, 11, 12, 13, 37, 38, 39, 41, 55}">
<f name="ProcessingCode" fieldNum="3" val="000000" valHex="000000"/>
<f name="Amount" fieldNum="4" val="000000003100" valHex="000000003100"/>
<f name="SystemTraceAuditNumber" fieldNum="11" val="004674" valHex="004674"/>
<f name="LocalTransactionTimeHHMMSS" fieldNum="12" val="130651" valHex="130651"/>
<f name="LocalTransactionDateMMDD" fieldNum="13" val="1212" valHex="1212"/>
<f name="PosNumber" fieldNum="37" val="8346130046741" valHex="38333436...36373431"/>
<f name="ApprovalCode" fieldNum="38" val="306540" valHex="333036353430"/>
<f name="ActionCode" fieldNum="39" val="06" valHex="3036"/>
<f name="TerminalId" fieldNum="41" val="2705524" valHex="32373035353234"/>
<f name="EMV" fieldNum="55" val="910A59218CDAFBBCD2520014" lenHex="0012" valHex="910A5921...D2520014"/>
</f>
</f>
消息具有以下定义
<f type="MSG">
<f type="VAL" name="Header" bodyPacker="LiteralBodyPacker" len="5"/>
<f type="VAL" name="MTI" bodyPacker="BcdBodyPacker" len="2"/>
<f type="BIT_SET" name="Bitmap" bitMapPacker="IfbBitmapPacker">
<f type="VAL" fieldNum="3" name="ProcessingCode" bodyPacker="HexBodyPacker" len="3"/>
<f type="VAL" fieldNum="4" name="Amount" bodyPacker="BcdBodyPacker" len="6"/>
<f type="VAL" fieldNum="11" name="SystemTraceAuditNumber" bodyPacker="BcdBodyPacker" len="3"/>
<f type="VAL" fieldNum="12" name="LocalTransactionTimeHHMMSS" bodyPacker="BcdBodyPacker" len="3"/>
<f type="VAL" fieldNum="13" name="LocalTransactionDateMMDD" bodyPacker="BcdBodyPacker" len="2"/>
<f type="VAL" fieldNum="37" name="PosNumber" bodyPacker="AsciiBodyPacker" len="13"/>
<f type="VAL" fieldNum="38" name="ApprovalCode" bodyPacker="AsciiBodyPacker" len="6"/>
<f type="VAL" fieldNum="39" name="ActionCode" bodyPacker="AsciiBodyPacker" len="2"/>
<f type="VAL" fieldNum="41" name="TerminalId" bodyPacker="AsciiBodyPacker" len="7"/>
<f type="LEN_VAL" fieldNum="55" name="EMV" lengthPacker="BcdLengthPacker" bodyPacker="HexBodyPacker"/>
</f>
</f>
整个示例位于GitHub上。 注意:我是iso-8583-packer Java库的作者。
答案 2 :(得分:0)
我知道这是一个老问题,但我最近在使用这个库时遇到了类似的问题,只是想分享这个解决方案,以便它可以帮助其他人。 j8583 config.xml 由两部分组成,用于构建 iso 消息的标记和用于从字符串中解压消息的标记。其中每一个都有子元素字段、类型和子元素 num、类型和长度,用于定义 iso 8583 字段中的每一个。根据经验,使用j8583解析iso消息的最佳方式是使用位图并生成配置文件,然后设置消息工厂。配置 XML 在 j8583.dtd 中导入一组定义的值并用作父标记,此文件存储在服务器中,因此您需要互联网在运行时下载它或自己下载并作为系统导入,如果您是使用 android 或应用程序在与互联网通信时遇到问题,最好将这些定义添加到 [] 中,而不是使用 PUBLIC -path 在这里查看更多信息 https://www.w3schools.com/xml/xml_dtd.asp。同样重要的是,在解析响应时,不要在响应字符串消息中包含其总长度(前 4 个字符)或 tdpu 标头(之后的下 10 个字符)。
构建响应消息配置文件
private void setResponseFactory(String responseMessage) throws IOException {
Log.i(TAG, "in setResponseFactory");
StringBuilder xmlParser = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE j8583-config [\n<!ELEMENT j8583-config ( header*, template*, parse* ) >\n" +
"\n" +
"<!ELEMENT header ( #PCDATA ) >\n" +
"<!ATTLIST header type NMTOKEN #REQUIRED >\n" +
"<!ATTLIST header ref NMTOKEN #IMPLIED >\n" +
"<!ATTLIST header binary ( true | false ) #IMPLIED >\n" +
"\n" +
"<!ELEMENT template ( field* ) >\n" +
"<!ATTLIST template type NMTOKEN #REQUIRED >\n" +
"<!ATTLIST template extends NMTOKEN #IMPLIED >\n" +
"\n" +
"<!ELEMENT parse ( field* ) >\n" +
"<!ATTLIST parse type NMTOKEN #REQUIRED >\n" +
"<!ATTLIST parse extends NMTOKEN #IMPLIED >\n" +
"\n" +
"<!ELEMENT field ( #PCDATA|field )* >\n" +
"<!ATTLIST field num NMTOKEN #REQUIRED >\n" +
"<!ATTLIST field length NMTOKEN #IMPLIED >\n" +
"<!ATTLIST field tz NMTOKEN #IMPLIED >\n" +
"<!ATTLIST field type ( ALPHA | NUMERIC | AMOUNT | DATE4 | DATE6 | DATE10 | DATE12 | DATE14 | DATE_EXP | TIME | LLVAR | LLLVAR | LLLLVAR | BINARY | LLBIN | LLLBIN | LLLLBIN | LLBCDBIN | LLLBCDBIN | LLLLBCDBIN | exclude) #REQUIRED >\n]>\n\n\t\t<!-- This file is generated at runtime, for iso message parsing (unpacking), response message types are request type + 10 -->\n\n");
String messageType = responseMessage.substring(0, 4); // response message type 0210 - sale, 0230 - advice ect...
Log.i(TAG, "response message type " + messageType);
Log.i(TAG, "hex bitmap " + responseMessage.substring(4, 20));
String bitmap = new BigInteger(responseMessage.substring(4, 20), 16).toString(2);
int length = 64 - bitmap.length();
char[] padArray = new char[length];
Arrays.fill(padArray, '0');
String padString = new String(padArray);
bitmap = padString + bitmap; // padd bitmap with zeros to the left
Log.i(TAG, "response bitmap " + bitmap);
HashMap<Integer, Pair<IsoType, Integer>> config = new HashMap<>(); // iso response field dictionary
config.put(Field_Indexes.PRIMARY_ACCOUNT_NUMBER, new Pair<>(IsoType.LLBIN, 0));
config.put(Field_Indexes.PROCESS_CODE, new Pair<>(IsoType.NUMERIC, 6));
config.put(Field_Indexes.TRANSACTION_AMOUNT, new Pair<>(IsoType.NUMERIC, 12));
config.put(Field_Indexes.TRACE_AUDIT_NUMBER, new Pair<>(IsoType.NUMERIC, 6));
config.put(Field_Indexes.LOCAL_TRANSMISSION_TIME, new Pair<>(IsoType.NUMERIC, 6));
config.put(Field_Indexes.LOCAL_TRANSMISSION_DATE, new Pair<>(IsoType.NUMERIC, 4));
config.put(Field_Indexes.POS_ENTRY_MODE, new Pair<>(IsoType.NUMERIC, 4));
config.put(Field_Indexes.NETWORK_INTERNATIONAL_IDENTIFIER, new Pair<>(IsoType.NUMERIC, 4));
config.put(Field_Indexes.POS_CONDITION_CODE, new Pair<>(IsoType.NUMERIC, 2));
config.put(Field_Indexes.RETRIEVAL_REFERENCE_NUMBER, new Pair<>(IsoType.BINARY, 12));
config.put(Field_Indexes.AUTHORIZATION_IDENTIFICATION_RESPONSE, new Pair<>(IsoType.BINARY, 6));
config.put(Field_Indexes.RESPONSE_CODE, new Pair<>(IsoType.BINARY, 2));
config.put(Field_Indexes.CARD_ACCEPTOR_TERMINAL_IDENTIFICATION, new Pair<>(IsoType.BINARY, 8));
config.put(Field_Indexes.ICC_DATA, new Pair<>(IsoType.LLLLBCDBIN, 0));
config.put(Field_Indexes.RN_FIELD_60, new Pair<>(IsoType.LLLLBIN, 0));
config.put(Field_Indexes.RP_FIELD_63, new Pair<>(IsoType.LLLLBCDBIN, 0));
config.put(Field_Indexes.MESSAGE_AUTHENTICATION_CODE_64, new Pair(IsoType.BINARY, 16));
xmlParser.append("<j8583-config>\n\t\t<parse type=\"" + messageType + "\">");
for(int i = 1; i<= 64; i++) // first bitmap if you are using secondary bitmap change to 128 instead of 64
if(bitmap.charAt(i - 1) == '1')
xmlParser.append("\n\t\t\t<field num=\"" + i + "\" type=\"" + config.get(i).first.toString() + "\""
+ ((config.get(i).second > 0) ? " length=\"" + config.get(i).second + "\" ": "") + "/>");
xmlParser.append("\n\t\t</parse>\n</j8583-config>");
wrtieFileOnInternalStorage(xmlParser.toString());
File root = new File(StateMachine.mContext.get().getFilesDir(),"response");
File file = new File(root, "isoresponse.xml");
responseFactory = ConfigParser.createFromClasspathConfig(file.getCanonicalPath());
}
调用消息解析器
public static void main (String[] args){
setResponseFactory(responseMessage);
responseFactory.setUseBinaryMessages(false);
Log.i(TAG, "in analize response");
HashMap<Integer, String> isoResponseData = SimpleParser.unpackIsoMessage(responseFactory, responseMessage); // remove tag, tdpu header and trailing 0
}
使用简单解析器https://github.com/SergeyZyazyulkin/j8583/blob/master/src/main/java/com/solab/iso8583/util/SimpleParser.java的实际解包
public static HashMap<Integer, String> unpackIsoMessage(MessageFactory mf, String message) throws UnsupportedEncodingException, ParseException {
HashMap<Integer, String> messageValues = new HashMap<>();
Log.i(TAG, "message: " + message);
if (message != null && message.length() > 0) {
IsoMessage m = mf.parseMessage(message.getBytes(), 0);
if (m != null) {
for (int i = 2; i <= 128; i++) {
IsoValue<?> f = m.getField(i);
if (f != null) {
Log.i(TAG, "f value class name " + f.getValue().getClass().getSimpleName());
if(f.getValue().getClass() == byte[].class)
messageValues.put(i, HexCodec.hexEncode((byte[])f.getValue(), 0, ((byte[]) f.getValue()).length));
else if(f.getValue().getClass().getSimpleName().equals("Long")){
messageValues.put(i, f.getValue() + "");
}
else
messageValues.put(i, (String) f.getValue());
Log.i(TAG, "iso value index " + i + " value " + messageValues.get(i));
}
}
}
}
return messageValues;
}
}