-
Notifications
You must be signed in to change notification settings - Fork 0
五、进阶知识
- 注解方式语义清晰,适合终端系统对报文进行处理;
- YAML/XML文件具有动态加载功能,工具包提供在线刷新方法,可手动触发或与第三方配置中心服务集成,可以做到配置热更新; 所以YAML/XML方式适合交易转发类应用,修改配置无需重启;
- 相对与YAML,XML可以通过schema增强校验,减少配置出错的概率;
- 数据库配置方式同YAML/XML文件配置方式优势基本相同,但数据库方式语义更强,配置更灵活;可以同后台管理系统集成,通过页面进行维护。
注:四种配置方式可以同时使用,针对同一报文配置项,先加载会被后加载的覆盖。
YAML/XML/数据库配置方式通过调用MessageDefinitionBuilder#refresh()
方法,实现配置在线刷新;注解方式不支持在线刷新。
注:在线刷新时可能会导致报文解析过程出现中间状态,建议通过应用层面解决(比如灰度发布),后续版本考虑优化该问题。
前文提到YAML/XML方式对应自定义容器MessageHolder
,注解方式对应其配置POJO
;以上为默认映射关系,特殊场景下可手动进行变换。
alatka.messages:
remark: 明细查询
type: fixed
group: "0395"
code: 3116
holder:
request: com.xxx.yyy.POJO1
response: com.xxx.yyy.POJO2
subPayload:
F13: com.xxx.yyy.POJO3
.....
<request clazz="com.xxx.yyy.POJO1">
......
</request>
<response clazz="com.xxx.yyy.POJO2">
......
</response>
<subPayload domain="F13" clazz="com.xxx.yyy.POJO3">
......
</subPayload>
ALK_MESSAGE_DEFINITION
M_ID | M_TYPE | M_GROUP | M_CODE | M_KIND | M_DOMAIN | M_USAGE | M_DOMAIN_TYPE | M_HOLDER | M_CHARSET | M_REMARK |
---|---|---|---|---|---|---|---|---|---|---|
3 | fixed | 0395 | 3116 | request | NONE | com.xxx.yyy.POJO1 | GB18030 | 明细查询请求报文 | ||
4 | fixed | 0395 | 3116 | response | NONE | com.xxx.yyy.POJO2 | GB18030 | 明细查询应答报文 | ||
5 | fixed | 0395 | 3116 | subPayload | F13 | NONE | com.xxx.yyy.POJO3 | GB18030 | 明细查询应答分页子域 |
注:POJO字段名称及java类型需要与YAML/XML/数据库配置中一一对应。
@MessageMeta(
type = MessageDefinition.Type.fixed,
group = "0395",
code = "3116",
kind = MessageDefinition.Kind.response,
customize = true, // true: MessageHolder, false: 当前POJO
remark = "明细查询")
public class Fixed3006Res extends FixedHeader {
@FixedFieldMeta(domainNo = 8, length = 19, remark = "卡号")
private String cardNbr;
// getter setter
}
前置类系统转发交易数据,一般只需解析个别域,大部分域是不处理原样转发;
针对无需解析的域,一般的处理方式是将该域的class
属性配置为byte[]
,这样可以省去java类型映射转换的操作,但变长域的场景下,仍然需要对长度域进行处理;
如果变长域也不需要处理,可以配置该域的status
属性为RAW
;注:配置status = RAW
后该域的class
属性不再生效,域值将以byte[]
形式进行存储。
对接外卡组织的前置系统,一般涉及到EBCDIC码、BCD码、ASCII码、HEX相互转换;以对接JCB为例,该场景下可做如下配置:
对接外卡组织jcb.common.iso.yml
YAML文件:
......
- { "domainNo": 2, "name": "pan", "fixed": false, "length": 1, "maxLength": 10, "remark": "主账号", "clazz": "java.lang.String", "parseType": "BCD" }
- { "domainNo": 3, "name": "processingCode", "fixed": true, "length": 3, "remark": "交易处理码", "clazz": "java.lang.String", "parseType": "BCD" }
- { "domainNo": 4, "name": "amtTrans", "fixed": true, "length": 6, "remark": "交易金额", "clazz": "java.math.BigDecimal", "parseType": "BCD" }
......
- { "domainNo": 37, "name": "retrivlRefNum", "fixed": true, "length": 12, "remark": "检索参考号", "clazz": "java.lang.String", "parseType": "EBCDIC" }
- { "domainNo": 38, "name": "authrIdResp", "fixed": true, "length": 6, "remark": "授权标识应答码", "clazz": "java.lang.String", "parseType": "EBCDIC" }
......
对接行内jcb.bank.iso.yml
YAML文件:
......
- { "domainNo": 2, "name": "pan", "fixed": false, "length": 2, "maxLength": 19, "remark": "主账号", "clazz": "java.lang.String" }
- { "domainNo": 3, "name": "processingCode", "fixed": true, "length": 6, "remark": "交易处理码", "clazz": "java.lang.String" }
- { "domainNo": 4, "name": "amtTrans", "fixed": true, "length": 12, "remark": "交易金额", "clazz": "java.math.BigDecimal" }
......
- { "domainNo": 37, "name": "retrivlRefNum", "fixed": true, "length": 12, "remark": "检索参考号", "clazz": "java.lang.String" }
- { "domainNo": 38, "name": "authrIdResp", "fixed": true, "length": 6, "remark": "授权标识应答码", "clazz": "java.lang.String" }
......
jcb发送行内的交易
byte[] unpack = ...; // jcb->前置的交易报文
MessageHolder holder = MessageBuilder.init("iso:jcb:common:payload").unpack(unpack); // 解包为MessageHolder
MessageHolder holder1 = holder.copyOf("iso:jcb:bank:payload"); // MessageHolder复制
byte[] pack = MessageBuilder.init("iso:jcb:bank:payload").pack(holder1); //前置->行内的交易报文打包
行内发送jcb的交易
byte[] unpack = ...; // 行内->前置的交易报文
MessageHolder holder = MessageBuilder.init("iso:jcb:bank:payload").unpack(unpack); // 解包为MessageHolder
MessageHolder holder1 = holder.copyOf("iso:jcb:common:payload"); // MessageHolder复制
byte[] pack = MessageBuilder.init("iso:jcb:common:payload").pack(holder1); //前置->jcb的交易报文打包
MessageBuilder
除了解析完整8583/固定格式报文以外,还可以单独解析8583某一子域;
MessageBuilder.init("iso:cups:common:subPayload:F55").unpack(bytes); // 银联55域
MessageBuilder.init("iso:cups:common:subPayload:F48:IN").unpack(bytes); // 银联48域usage=IN
MessageBuilder.init("iso:cups:common:subPayload:F60_F11").unpack(bytes); // 银联60.11域
MessageBuilder.init("iso:cups:common:subPayload:F59$QR_F3").unpack(bytes); // 银联59域usage=QR F3子域
注:不能单独解析分页子域和不定长子域。
工具包提供完善的错误信息日志及跟踪日志,方便线上问题跟踪和线下debug。
针对打包解包功能,提供精确到具体域的报错信息,例如:
- 银联48域未配置子域usage=ON
java.lang.RuntimeException: MessageDefinition{iso:cups:common:payload:NONE:银联8583报文} -> {F48:addtnlDataPrivate:3~512:附加数据——私有}解析报错
at com.alatka.messages.message.MessageBuilder.doUnpack(MessageBuilder.java:113)
at com.alatka.messages.message.MessageBuilder.lambda$unpack$3(MessageBuilder.java:95)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at com.alatka.messages.message.MessageBuilder.unpack(MessageBuilder.java:96)
at com.alatka.messages.message.MessageBuilder.unpack(MessageBuilder.java:84)
at com.alatka.messages.DomainTest.test(DomainTest.java:454)
... 80 more
Caused by: java.lang.RuntimeException: {F48:addtnlDataPrivate:3~512:附加数据——私有}未配置子域usage: ON
at com.alatka.messages.field.SubdomainFieldBuilder.validate(SubdomainFieldBuilder.java:68)
at com.alatka.messages.field.AbstractULVSubdomainFieldBuilder.unpack(AbstractULVSubdomainFieldBuilder.java:50)
at com.alatka.messages.field.UVASSubdomainFieldBuilder.unpack(UVASSubdomainFieldBuilder.java:52)
at com.alatka.messages.field.UVASSubdomainFieldBuilder.unpack(UVASSubdomainFieldBuilder.java:18)
at com.alatka.messages.field.SubdomainFieldBuilder.toObjectWithNone(SubdomainFieldBuilder.java:49)
at com.alatka.messages.field.AbstractFieldBuilder.toObject(AbstractFieldBuilder.java:103)
at com.alatka.messages.field.AbstractFieldBuilder.deserialize(AbstractFieldBuilder.java:34)
at com.alatka.messages.message.MessageBuilder.doUnpack(MessageBuilder.java:110)
... 80 more
- 银联123域数据超过最大长度(最大100,实际226)
java.lang.RuntimeException: MessageDefinition{iso:cups:common:payload:NONE:银联8583报文} -> {F123:issrInstResvd:3~100:发卡方保留}解析报错
at com.alatka.messages.message.MessageBuilder.lambda$unpack$3(MessageBuilder.java:113)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at com.alatka.messages.message.MessageBuilder.unpack(MessageBuilder.java:115)
at com.alatka.messages.message.MessageBuilder.unpack(MessageBuilder.java:98)
at com.alatka.messages.MessageCupsYamlTest.doTest(MessageCupsYamlTest.java:17)
at com.alatka.messages.MessageCupsYamlTest.test04(MessageCupsYamlTest.java:48)
... 80 more
Caused by: java.lang.IllegalArgumentException: fieldDefinition: {F123:issrInstResvd:3~100:发卡方保留} max length: 100, actually length: 226
at com.alatka.messages.domain.LVDomainParsed.unpack(LVDomainParsed.java:42)
at com.alatka.messages.message.MessageBuilder.doUnpack(MessageBuilder.java:124)
at com.alatka.messages.message.MessageBuilder.lambda$unpack$3(MessageBuilder.java:111)
... 80 more
- 银联60.1域据超过最大长度(最大4,实际5)
java.lang.RuntimeException: MessageDefinition{iso:cups:common:payload:NONE:银联8583报文} -> {F60:reserved:3~100:自定义域}解析报错
at com.alatka.messages.message.MessageBuilder.lambda$pack$0(MessageBuilder.java:74)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:474)
at com.alatka.messages.message.MessageBuilder.pack(MessageBuilder.java:79)
at com.alatka.messages.DomainTest.doTest(DomainTest.java:31)
at com.alatka.messages.DomainTest.test16(DomainTest.java:414)
... 78 more
Caused by: java.lang.RuntimeException: MessageDefinition{iso:cups:common:subPayload:F60:NONE:银联8583报文} -> {F1:f60f1:4:报文原因码}解析报错
at com.alatka.messages.message.MessageBuilder.lambda$pack$0(MessageBuilder.java:74)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:474)
at com.alatka.messages.message.MessageBuilder.pack(MessageBuilder.java:79)
at com.alatka.messages.field.FixedSubdomainFieldBuilder.pack(FixedSubdomainFieldBuilder.java:24)
at com.alatka.messages.field.SubdomainFieldBuilder.fromObjectToNone(SubdomainFieldBuilder.java:40)
at com.alatka.messages.field.AbstractFieldBuilder.fromObject(AbstractFieldBuilder.java:68)
at com.alatka.messages.field.AbstractFieldBuilder.serialize(AbstractFieldBuilder.java:26)
at com.alatka.messages.message.MessageBuilder.doPack(MessageBuilder.java:87)
at com.alatka.messages.message.MessageBuilder.lambda$pack$0(MessageBuilder.java:72)
... 78 more
Caused by: java.lang.IllegalArgumentException: {F1:f60f1:4:报文原因码} actual length: 5, expected length: 4
at com.alatka.messages.domain.AbstractDomainParsed.padding(AbstractDomainParsed.java:28)
at com.alatka.messages.domain.FixedDomainParsed.pack(FixedDomainParsed.java:30)
at com.alatka.messages.message.UnfixedSubdomainMessageBuilder.doPack(UnfixedSubdomainMessageBuilder.java:41)
at com.alatka.messages.message.MessageBuilder.lambda$pack$0(MessageBuilder.java:72)
... 93 more
- TODO
MessageHolder容器提供格式化输出功能,方便线上打印日志及线下问题调试。
@Test
public void test01() {
String hex = "2E02303535383134353338323030202020303030313030303020202000000000303030303030303000303030303030323030F23A46C1A8E19A100000000010000080313636323234323432303030303030303231303030303030303030303030303130303030303531313233343230333030303031323233343230333035313130353131353431313035313030303030303630383932303130303030303839323031303030303334363232343234323030303030303032314432393032323031353639393033313030373030303030303030303031323132333435363738313233343536373839303132333435D6D0B9FAD2F8C1AA4348494E4120554E494F4E5041592053494D554C41544F52202020202020202030343741534F4E30343031323232313132323231313232323131323232313132323231313232323131323232313132323231313536EC2804D2AC42710A323630303030303030303030303030303131355F2A02015682027D00950500001800009A032405119C01019F02060000000100009F03060000000000009F09009F100807000103A02000019F1A0201569F1E0832303033313233309F26085576AF9865559F3E9F2701809F3303E098C09F34036003029F3501229F360200139F37040B7FBD483032373030303030363030303330303030303030303030303031323030303038313435333832303030343335314353323230303030303435303331303030303020202030303030303030303030303030303030303030";
String header = hex.substring(0, 92);
String body = hex.substring(92);
MessageHolder headerMessage = MessageBuilder.init("iso:cups:common:header").unpack(header);
System.out.println(headerMessage);
MessageHolder bodyMessage = MessageBuilder.init("iso:cups:common:payload").unpack(body);
System.out.println(bodyMessage);
}
输出内容:
{
"{F1:headerLength:1:报文头长度}" : 46,
"{F2:version:1:头标识和版本号}" : "00000010",
"{F3:messageLength:4:报文长度}" : 558,
"{F4:destinationId:11:目的ID}" : "14538200",
"{F5:sourceId:11:源ID}" : "00010000",
"{F6:reserved:3:保留使用}" : null,
"{F7:batchNum:1:批次号}" : "00000000",
"{F8:transInfo:8:交易信息}" : "00000000",
"{F9:userInfo:1:用户信息}" : "00000000",
"{F10:rejectCode:5:拒绝码}" : "00000"
}
{
"{F0:messageType:4:报文类型}" : "0200",
"{F1:bitMap:16~null:位图}" : {
"1" : true,
"2" : true,
"3" : true,
"4" : true,
"5" : false,
"6" : false,
"7" : true,
"8" : false,
"9" : false,
"10" : false,
"11" : true,
"12" : true,
"13" : true,
"14" : false,
"15" : true,
"16" : false,
"17" : false,
"18" : true,
"19" : false,
"20" : false,
"21" : false,
"22" : true,
"23" : true,
"24" : false,
"25" : true,
"26" : true,
"27" : false,
"28" : false,
"29" : false,
"30" : false,
"31" : false,
"32" : true,
"33" : true,
"34" : false,
"35" : true,
"36" : false,
"37" : true,
"38" : false,
"39" : false,
"40" : false,
"41" : true,
"42" : true,
"43" : true,
"44" : false,
"45" : false,
"46" : false,
"47" : false,
"48" : true,
"49" : true,
"50" : false,
"51" : false,
"52" : true,
"53" : true,
"54" : false,
"55" : true,
"56" : false,
"57" : false,
"58" : false,
"59" : false,
"60" : true,
"61" : false,
"62" : false,
"63" : false,
"64" : false,
"65" : false,
"66" : false,
"67" : false,
"68" : false,
"69" : false,
"70" : false,
"71" : false,
"72" : false,
"73" : false,
"74" : false,
"75" : false,
"76" : false,
"77" : false,
"78" : false,
"79" : false,
"80" : false,
"81" : false,
"82" : false,
"83" : false,
"84" : false,
"85" : false,
"86" : false,
"87" : false,
"88" : false,
"89" : false,
"90" : false,
"91" : false,
"92" : false,
"93" : false,
"94" : false,
"95" : false,
"96" : false,
"97" : false,
"98" : false,
"99" : false,
"100" : true,
"101" : false,
"102" : false,
"103" : false,
"104" : false,
"105" : false,
"106" : false,
"107" : false,
"108" : false,
"109" : false,
"110" : false,
"111" : false,
"112" : false,
"113" : false,
"114" : false,
"115" : false,
"116" : false,
"117" : false,
"118" : false,
"119" : false,
"120" : false,
"121" : true,
"122" : false,
"123" : false,
"124" : false,
"125" : false,
"126" : false,
"127" : false,
"128" : false
},
"{F2:pan:2~19:主账号}" : "6224242000000021",
"{F3:processingCode:6:交易处理码}" : "000000",
"{F4:amtTrans:12:交易金额}" : 10000,
"{F5:amtSettlmt:12:清算金额}" : null,
"{F6:amtCdhldrBil:12:持卡人扣账金额}" : null,
"{F7:transmsnDateTime:10:交易传输时间}" : [ 2024, 5, 11, 23, 42, 3 ],
"{F9:convRateSettlmt:8:清算汇率}" : null,
"{F10:convRateCdhldrBil:8:持卡人扣账汇率}" : null,
"{F11:sysTraceAuditNum:6:系统跟踪号}" : 12,
"{F12:timeLocalTrans:6:受卡方所在地时间}" : [ 23, 42, 3 ],
"{F13:dateLocalTrans:4:受卡方所在地日期}" : "--05-11",
"{F14:dateExpr:4:卡有效期}" : null,
"{F15:dateSettlmt:4:清算日期}" : "--05-11",
"{F16:dateConv:4:兑换日期}" : null,
"{F18:mchntType:4:商户类型}" : "5411",
"{F19:mchntCntryCode:3:商户国家代码}" : null,
"{F22:posEntryModeCode:3:服务点输入方式码}" : "051",
"{F23:cardSeqId:3:卡序列号}" : "000",
"{F25:posCondCode:2:服务点条件码}" : "00",
"{F26:posPinCaptrCode:2:服务点PIN获取码}" : "06",
"{F28:amtTransFee:9:交易费}" : null,
"{F32:acqInstIdCode:2~11:代理机构标识码}" : "92010000",
"{F33:fwdInstIdCode:2~11:发送机构标识码}" : "92010000",
"{F35:tracK2Data:2~37:第二磁道数据}" : "6224242000000021D29022015699031007",
"{F36:tracK3Data:3~104:第三磁道数据}" : null,
"{F37:retrivlRefNum:12:检索参考号}" : "000000000012",
"{F38:authrIdResp:6:授权标识应答码}" : null,
"{F39:respCode:2:应答码}" : null,
"{F41:cardAccptrTermnlId:8:受卡机终端标识码}" : "12345678",
"{F42:cardAccptrId:15:受卡方标识码}" : "123456789012345",
"{F43:cardAccptrNameLoc:40:受卡方名称地址}" : "中国银联CHINA UNIONPAY SIMULATOR",
"{F44:addtnlRespCode:2~25:附加响应数据}" : null,
"{F45:tracK1Data:2~76:第一磁道数据}" : null,
"{F48:addtnlDataPrivate:3~512:附加数据——私有}" : {
"ON" : {
"{F1:orderNo:40:订单号}" : "1222112221122211222112221122211222112221"
}
},
"{F49:currcyCodeTrans:3:交易货币代码}" : "156",
"{F50:currcyCodeSettlmt:3:清算货币代码}" : null,
"{F51:currcyCodeCdhldrBil:3:持卡人帐户货币代码}" : null,
"{F52:pinData:8:个人标识码数据}" : "EC2804D2AC42710A",
"{F53:secRelatdCtrlInfo:16:安全控制信息}" : {
"{F1:keyType:1:重置密钥的类型/PIN格式}" : "2",
"{F2:encryptionMethodUsed:1:加密算法标志}" : "6",
"{F3:reserved:14:保留使用}" : "00000000000000"
},
"{F54:addtnlAmt:3~40:实际余额}" : null,
"{F55:iccData:3~255:IC卡数据域}" : {
"{F1:crypt:8:应用密文}" : "5576AF9865559F3E",
"{F2:cryptInfoData:1:密文信息数据}" : "80",
"{F3:issuerAppData:-2147483648~32:发卡行应用数据}" : "07000103A0200001",
"{F4:unpredictableNumber:4:不可预知数}" : "0B7FBD48",
"{F5:appTransCounter:2:应用交易计数器}" : "13",
"{F6:termVerificationResult:5:终端验证结果}" : "180000",
"{F7:transDate:3:交易日期}" : [ 2024, 5, 11 ],
"{F8:transType:1:交易类型}" : 1,
"{F9:transAmt:6:授权金额}" : 10000,
"{F10:transCurrencyCode:2:交易货币代码}" : 156,
"{F11:appInterchangeProfile:2:应用交互特征}" : "7D00",
"{F12:termCountryCode:2:终端国家代码}" : 156,
"{F13:otherAmt:6:其它金额}" : 0,
"{F14:termCap:3:终端性能}" : "E098C0",
"{F15:cardholderVerificationMethodResults:3:持卡人验证方法结果}" : "600302",
"{F16:termType:1:终端类型}" : 22,
"{F17:interfaceDeviceSerialNumber:8:接口设备序列号}" : "20031230",
"{F18:dedicatedFileName:-2147483648~16:专用文件名称}" : null,
"{F19:termAppVersionNumber:2:应用版本号}" : null,
"{F20:transSequenceCounter:-2147483648~4:交易序列计数器}" : null,
"{F21:issuerAuthenticationData:-2147483648~16:发卡行认证数据}" : null,
"{F22:issuerScriptTemplate1:-2147483648~128:发卡行脚本1}" : null,
"{F23:issuerScriptTemplate2:-2147483648~128:发卡行脚本2}" : null,
"{F24:issuerScriptResults:-2147483648~21:发卡方脚本结果}" : null,
"{F25:issuerAuthorizationCode:6:电子现金发卡行授权码}" : null,
"{F26:cardProductIdentification:16:卡产品标识信息}" : null,
"{F27:authorizationResponseCode:2:授权响应码}" : null
},
"{F56:addtnlData56:3~512:附加信息}" : null,
"{F57:addtnlData57:3~100:附加交易信息}" : null,
"{F59:detailInqrng:3~600:明细查询数据}" : null,
"{F60:reserved:3~100:自定义域}" : {
"{F1:f60f1:4:报文原因码}" : "0000",
"{F2:f60f2:1:账户所有人类型}" : "0",
"{F3:f60f3:1:终端读取能力}" : "6",
"{F4:f60f4:1:IC卡条件代码}" : "0",
"{F5:f60f5:1:保留使用}" : "0",
"{F6:f60f6:2:终端类型}" : "03",
"{F7:f60f7:1:受理免验密码标志}" : "0",
"{F8:f60f8:1:IC卡验证可靠性标志}" : "0",
"{F9:f60f9:2:电子商务标志}" : "00",
"{F10:f60f10:1:交互方式标志}" : "0",
"{F11:f60f11:-1~15:交易发生附加信息}" : {
"{F1:f60f11f1:2:特殊计费类型}" : "00",
"{F2:f60f11f2:1:特殊计费档次}" : "0",
"{F3:f60f11f3:3:保留使用(第3位为MAC算法标识)}" : "000",
"{F4:f60f11f4:1:支持部分承兑和返回余额标志}" : "0",
"{F5:f60f11f5:1:交易发起方式}" : "1",
"{F6:f60f11f6:1:交易介质}" : "2",
"{F7:f60f11f7:1:IC 卡的应用类型}" : "0",
"{F8:f60f11f8:2:账户结算类型}" : "00",
"{F9:f60f11f9:1:卡账户等级}" : null,
"{F10:f60f11f10:2:卡产品}" : null
}
},
"{F61:chAuthInfo:3~200:持卡人身份认证信息}" : null,
"{F62:switchingData:3~200:交换中心数据}" : null,
"{F63:finaclNetData:3~512:金融网络数据}" : null,
"{F70:netwkMgmtInfoCode:3:网络管理信息码}" : null,
"{F90:origDataElemts:42:原始数据元}" : null,
"{F96:msgSecurityCode:8:报文安全码}" : null,
"{F100:rcvgInstIdCode:2~11:接收机构标识码}" : "14538200",
"{F102:acctId1:2~28:帐户标识1}" : null,
"{F103:acctId2:2~28:帐户标识2}" : null,
"{F104:addtnlData104:3~512:附加信息}" : null,
"{F113:addtnlData113:3~512:附加信息}" : null,
"{F116:addtnlData116:3~512:附加信息}" : null,
"{F117:addtnlData117:3~256:附加信息}" : null,
"{F121:nationalSwResved:3~100:银联处理中心保留}" : {
"{F1:f121f1:1:应答原因码}" : "5",
"{F2:f121f2:1:单/双或双/单转换码}" : "1",
"{F3:f121f3:1:卡性质}" : "C",
"{F4:f121f4:40:CUPS保留}" : "S22000004503100000 0000000000000000000",
"{F5:f121f5:38:转入和转出方标识代码/手续费信息}" : null
},
"{F122:acqInstResvd:3~100:受理方保留}" : null,
"{F123:issrInstResvd:3~100:发卡方保留}" : null,
"{F125:addtnlData125:3~256:附加信息}" : null,
"{F126:addtnlData126:3~256:附加信息}" : null,
"{F128:msgAuthnCode:8:报文鉴别码}" : null
}
针对注解配置,使用POJO
作为数据容器的场景,可以使用MessageHolder#fromPojo(Object)
方法,将POJO
转换为MessageHolder
,然后再格式化输出。
alatka-messages
及其相关制品已上传至阿里云仓库,如需下载可进行如下配置:
1.设置仓库凭证
在 settings.xml 文件中设置以下仓库的访问凭证。
<servers>
<server>
<id>2448467-release-d4LMO3</id>
<username>661f7b16a0522beff388bd5c</username>
<password>R06ilmt)Ii=j</password>
</server>
</servers>
2.配置仓库和包信息
在settings.xml文件节点中加入对应的仓库使用地址。
<repositories>
<repository>
<id>2448467-release-d4LMO3</id>
<url>https://packages.aliyun.com/maven/repository/2448467-release-d4LMO3</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
报文配置信息(MessageDefinition
和FieldDefinition
)在MessageDefinitionBuilder#build()
方法执行后全部加载到jvm内存中,供后续报文打包解包使用;
每个报文域对应一个FieldDefinition对象,随着报文接口的增多,jvm内存开销线性增加;在接口较多的场景下,内存开销问题不容忽视。
TODO
- 报文域类型不支持java原始类型(int/byte/long/short/boolean...):原始类型有默认值,会影响报文域取值和赋值;
- TODO