1027102810051006-->packagecom.sumavision.connector.iso8583.parse;importjava.io.*;importjava.util.*;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springfra" />
搜档网
当前位置:搜档网 › 打包与解包

打包与解包

j8583_boss.xml




"C:/tvpay/config/j8583.dtd">



1027

1028

1005

1006





































































package com.sumavision.connector.iso8583.parse;

import java.io.*;
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;

import com.sumavision.connector.iso8583.util.ConfigParser;
import com.sumavision.connector.iso8583.util.IsoValue;
import com.sumavision.connector.iso8583.util.Message

Factory;
import com.sumavision.connector.iso8583.util.SimpleTraceGenerator;
import com.sumavision.connector.iso8583.util.IsoMessage;
import com.sumavision.connector.iso8583.util.IsoType;
import com.sumavision.connector.util.DesEncrypt;
import com.sumavision.connector.util.Hex2GBKStringUtil;
import com.sumavision.connector.util.PacketIdGenerator;
import com.sumavision.connector.util.RequestIdGenerator;
import com.sumavision.crpt.MessageDigestMD5;

/**
*

数据打包解包服务


* @author Administrator
*/
public class PacketDataOperateService {

private final Logger log = LoggerFactory.getLogger(this.getClass());
//模板文件配置路径
private final String OPERATE_TEMPLATE_PATH = "com/sumavision/connector/iso8583/parse/j8583_boss.xml";

private Resource templatePath = null;

//获取用户信息(终端号) 支付平台传来的交易代码
private final String GET_TERMINALNO_TRANSCODE = "BT000201";
//获取用户缴费账单(BOSS缴费单) 支付平台传来的交易代码
private final String GET_USERFEE_TRANSCODE = "BT000202";
//获取用户信息(终端号) 功能码
private final int GET_TERMINALNO_FUNCNO = 1027;
//获取用户信息(终端号) 返回响应功能码
private final int GET_TERMINALNO_RESPONSE_FUNCNO =1028;
//获取用户缴费账单(BOSS缴费单) 功能码
private final int GET_USERFEE_FUNCNO = 1005;
//获取用户缴费账单(BOSS缴费单) 返回响应功能码
private final int GET_USERFEE_RESPONSE_FUNCNO = 1006;

//机顶盒内部编码
private final String STB_INSIDE_CODE = "STB_INSIDE_CODE";
//厂商编号
private final String MANUFACTURERS_NO = "MANUFACTURERS_NO";
//硬件版本号
private final String HARDWARE_VERSION_NO = "HARDWARE_VERSION_NO";
//客户编码
private final String CUSTOMER_NO = "CUSTOMER_NO";
//账户编码
private final String ACCOUNT_NO = "ACCOUNT_NO";
//业务编码
private final String SERVICE_TYPE = "SERVICE_TYPE";
//服务号码
private final String SUBSCRIBER_NO = "SUBSCRIBER_NO";
//账务周期
private final String BILLING_CYCLE = "BILLING_CYCLE";

//开始标识+包长度+包体+校验字段+结束标识
//报文开始标识
private final String PACKET_HEADER = "|*!#";
//报文结束标识
private final String PACKET_TAILER = "#@&^";

private static final Map retCodeMsgMap = new HashMap();

/*初始化错误代码表*/
static{
retCodeMsgMap.put("0000", "交易成功");
retCodeMsgMap.put("0001", "服务器忙");
retCodeMsgMap.put("0002", "无法解析字符串");
retCodeMsgMap.put("0003", "SMS系统内部错误");
retCodeMsgMap.put("0004", "版本号不支持");
retCodeMsgMap.put("0005", "数据库没有该银行的记录");
retCodeMsgMap.put("0006", "银行代码与银行认证码不符");
retCodeMsgMap.put("0007", "客户编码不存在");
retCodeMsgMap.put("0008", "帐户编码不存在");

retCodeMsgMap.put("0009", "业务编码不存在");
retCodeMsgMap.put("0010", "服务号码不存在");
retCodeMsgMap.put("0011", "账务周期不存在");
retCodeMsgMap.put("0012", "银行流水号不存在");
retCodeMsgMap.put("0013", "余额账本不存在");
retCodeMsgMap.put("0014", "存在多个余额账本,请按余额账本编号查询");
retCodeMsgMap.put("0015", "存在一个服务号码由多个客户的帐户付费");
retCodeMsgMap.put("0016", "已缴费");
retCodeMsgMap.put("0017", "已签订代扣协议");
retCodeMsgMap.put("0018", "此帐户未使用该流水号签订代扣协议");
retCodeMsgMap.put("0019", "此客户有多个帐户,请使用帐户编号");
retCodeMsgMap.put("0020", "预存失败,预存超过余额上限");
retCodeMsgMap.put("0021", "实缴金额不等于实际费用加滞纳金");
retCodeMsgMap.put("0022", "冲正失败");
retCodeMsgMap.put("0023", "已经对账,不能进行冲正");
retCodeMsgMap.put("0024", "已经冲正,不能再次冲正");
retCodeMsgMap.put("0025", "必填数据未填充");
retCodeMsgMap.put("0026", "代扣失败");
retCodeMsgMap.put("0027", "发票号码不存在");
retCodeMsgMap.put("0028", "发票号码不可使用");
retCodeMsgMap.put("0029", "附加信息域格式错误");
retCodeMsgMap.put("0030", "产品信息域格式错误");
retCodeMsgMap.put("0032", "找不到对应用户");
}

/**
*

打包数据


* @param map
* @return
* @throws Exception
*/
public String packetData(Map map) throws Exception{

https://www.sodocs.net/doc/5416337043.html,("打包数据准备...Map >>{}",map);
if(null==map || map.size()<1){
log.error("请求参数域为空,打包失败");
return null;
}

if (!map.containsKey("STB_ID")) {
log.error("请求参数STB_ID域为空,打包失败");
return null;
}
String stb = map.get("STB_ID").toString();
map.put("MANUFACTURERS_NO", stb.substring(0, 3));
map.put("HARDWARE_VERSION_NO", stb.substring(3, 18));
map.put("STB_INSIDE_CODE", stb.substring(18, 25));

MessageFactory mfact = ConfigParser.createFromStream(templatePath.getInputStream());
// MessageFactory mfact = ConfigParser.createFromClasspathConfig(templatePath.);
// mfact.setAssignDate(true);
// mfact.setTraceNumberGenerator(new SimpleTraceGenerator((int)(System.currentTimeMillis() % 100000)));

String transcode = (String)map.get("TRANSCODE");
IsoMessage m = null;
if(null!=transcode && transcode.equals(GET_TERMINALNO_TRANSCODE)){
m= _cardNumberForMachinePacket(map,mfact);
}else if(null!=transcode && transcode.equals(GET_USERFEE_TRANSCODE)){
m= _accessToUserFeesBillPacket(map,mfact);
}else{
log.error("交易代码错误,打包失败");
return null;
}
String packetStr = new String(m.writeData());
String packetLenStr = String.valueOf(packetStr.length()+32);
StringBuffer sbuff = new StringBuffer();
sbuff.append(PACKET_

HEADER);
if(packetLenStr.length()<8){
sbuff.append("00000000".substring(packetLenStr.length()));
}
sbuff.append(packetStr.length()+32);
sbuff.append(packetStr);
sbuff.append(generateValidateCode(packetStr).toLowerCase());
sbuff.append(PACKET_TAILER);
https://www.sodocs.net/doc/5416337043.html,("打包数据完成...报文 >>{}",sbuff.toString());
return sbuff.toString();
}

/**
*

解析报文字符串


* @param pstr 报文体
* @param vstr 校验字段
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
public Map parseData(String pstr,String vstr,int funcCode) throws Exception{
https://www.sodocs.net/doc/5416337043.html,("解包数据准备...报文体 >>{}",pstr);
https://www.sodocs.net/doc/5416337043.html,("解包数据准备...报文校验字段 >>{}",vstr);
MessageFactory mfact = ConfigParser.createFromStream(templatePath.getInputStream());
// MessageFactory mfact = ConfigParser.createFromClasspathConfig(templatePath);
// mfact.setAssignDate(true);
// mfact.setTraceNumberGenerator(new SimpleTraceGenerator((int)(System.currentTimeMillis() % 100000)));
mfact.setUseBinaryMessages(false);
//可能有中文
// String bstr = new String(bytes,"GBK");
// int functionCode = Integer.valueOf(pstr.substring(68, 72));
// String packetDataStr = bstr.substring(12, bstr.length()-4-32);
// String validateStr = bstr.substring(bstr.length()-4-32, bstr.length()-4);
Map map = null;
byte[] packetBytes = pstr.getBytes("GBK");
if(funcCode==GET_TERMINALNO_RESPONSE_FUNCNO){
if(!validateResponseData(pstr,vstr)){
throw new Exception("数据包校验失败,无效数据包");
}
map = cardNumberForMachinePacket_(mfact.parseMessage(packetBytes, 4136));
}else if(funcCode==GET_USERFEE_RESPONSE_FUNCNO){
//查询单用户余额账本的 返回报文中含有中文字符,返回的校验码与对报文做MD5生成的校验码不一致
//未找到原因: 暂时不做校验
map = accessToUserFeesBillPacket_(mfact.parseMessage(packetBytes, 4102));
}else{
log.error("无法识别的功能码,解包失败");
return null;
}

https://www.sodocs.net/doc/5416337043.html,("解包数据完成...Map >>{}",map);
return map;
}

/**
* 打包
* @param mf
* @param input
* @return
*/
@SuppressWarnings("rawtypes")
private IsoMessage _cardNumberForMachinePacket(Map input,MessageFactory mf){
// IsoMessage m = mf.newMessage(GET_TERMINALNO_FUNCNO);
IsoMessage m = new IsoMessage();
m.setBinary(false);
// m.setBinary(true);
//会话ID 对来自银行前置机接入SMS的请求数据,此处填写由银行前置机产生的会话ID,在传输过程中应保持一对请求/响应的数据中 SessionID 保持不变
m.setValue(2, RequestIdGenerator.genRequestId(), IsoType.LLVAR, 16);
//数据包序号 从 0 开始,顺序累加,步长为 1,循环使用
m.setValue(3, PacketIdGenerator.genPacketId(), IsoType.LLVAR, 32);
//银行代码 暂时不知道,先写1111
m.setValue(4, 2000, IsoType.NUMERIC, 4);
//功能

码 业务标识,用于标识请求/响应数据包代表的业务操作
m.setValue(5, GET_TERMINALNO_FUNCNO, IsoType.NUMERIC, 4);
//响应吗 标识业务处理结果
m.setValue(6, 0000, IsoType.NUMERIC, 4);
//重发标识 0 标识普通数据包;1:标识重发数据包
m.setValue(7, 0, IsoType.NUMERIC, 1);
//加密标识 0 标识包体数据为明文,1:标识包体数据为加密数据
m.setValue(8, 0, IsoType.NUMERIC, 1);
//机顶盒内部编码 StbInsideCode
m.setValue(43, input.get(STB_INSIDE_CODE), IsoType.LLVAR, 50);
//厂商编号 ManufacturersNo
m.setValue(44, input.get(MANUFACTURERS_NO), IsoType.LLVAR, 20);
//硬件版本号 HardwareVersionNo
m.setValue(45, input.get(HARDWARE_VERSION_NO), IsoType.LLVAR, 20);
return m;
}

/**
* 打包
* @param mf
* @param input
* @return
*/
@SuppressWarnings("rawtypes")
private IsoMessage _accessToUserFeesBillPacket(Map input,MessageFactory mf){
IsoMessage m = mf.newMessage(GET_USERFEE_FUNCNO);
m.setBinary(false);
//会话ID 对来自银行前置机接入SMS的请求数据,此处填写由银行前置机产生的会话ID,在传输过程中应保持一对请求/响应的数据中 SessionID 保持不变
m.setValue(2, RequestIdGenerator.genRequestId(), IsoType.LLVAR, 16);
//数据包序号 从 0 开始,顺序累加,步长为 1,循环使用
m.setValue(3, PacketIdGenerator.genPacketId(), IsoType.LLVAR, 32);
//银行代码 暂时不知道,先写1111
m.setValue(4, 2000, IsoType.NUMERIC, 4);
//功能码 业务标识,用于标识请求/响应数据包代表的业务操作
m.setValue(5, GET_USERFEE_FUNCNO, IsoType.NUMERIC, 4);
//响应吗 标识业务处理结果
m.setValue(6, 0000, IsoType.NUMERIC, 4);
//重发标识 0 标识普通数据包;1:标识重发数据包
m.setValue(7, 0, IsoType.NUMERIC, 1);
//加密标识 0 标识包体数据为明文,1:标识包体数据为加密数据
m.setValue(8, 0, IsoType.NUMERIC, 1);
//客户编码 CustomerNo 广电客户的编码
m.setValue(19, input.get(CUSTOMER_NO), IsoType.LLVAR, 20);
//下面3项必填一项
if(null!=input.get(ACCOUNT_NO)){
//账户编码 AccountNo 广电客户的帐户编码
m.setValue(21, input.get(ACCOUNT_NO), IsoType.LLVAR, 20);
}
if(null!=input.get(SERVICE_TYPE)){
//业务编码 ServiceType 公共业务00 数字电视业务02
m.setValue(23, input.get(SERVICE_TYPE), IsoType.ALPHA, 2);
}
if(null!=input.get(SUBSCRIBER_NO)){
//服务号码 SubscriberNo 智能卡号、上网帐号等
m.setValue(24, input.get(SUBSCRIBER_NO), IsoType.LLVAR, 20);
}
//账务周期 BillingCycle 可选
// m.setValue(39, input.get(BILLING_CYCLE), IsoType.LLVAR, 20);
return m;
}


/**
* 解包
* @param im
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private Map cardNumberForMachinePacket_(IsoMessage im){
https://www.sodocs.net/doc/5416337043.html,("card

NumberForMachinePacket_ : receive Msg :"+printIsoMessage(im));
//银行代码
IsoValue bankCode = im.getAt(4);
//功能码
IsoValue functionCode = im.getAt(5);
//boss响应吗
IsoValue retCode = im.getAt(6);
//加密标识
IsoValue isEncrpt = im.getAt(8);
//机顶盒内部编码
IsoValue stbInsideCode = im.getAt(43);
//厂商编码
IsoValue manufacturersNo = im.getAt(44);
//硬件版本号
IsoValue hardwareVersionNo = im.getAt(45);
//附件信息 响应中的“附加信息”域经过加密处理,加密方式会通过其他方式告知。其中的内容如下:
//智能卡号/t 客户ID/t 用户ID/t 客户姓名/t 客户地址例如:
//1234567890 1521 1598 张三 天津市河西区气象台路卫星里
IsoValue additionalData = im.getAt(41);

if(!String.valueOf(functionCode.getValue()).equals(String.valueOf(GET_TERMINALNO_RESPONSE_FUNCNO))){
log.error("功能码不正确");
}

Map map = new HashMap();
map.put("RETCODE", retCode.getValue());
map.put("TRANSMSG", getTransMsg(paddingRetCode(String.valueOf(retCode.getValue()))));
// map.put("BANK_CODE", bankCode.getValue());
map.put("IS_ENCRPT", isEncrpt.getValue());
map.put("STB_INSIDE_CODE", stbInsideCode.getValue());
map.put("MANUFACTURERS_NO", manufacturersNo.getValue());
map.put("HARDWARE_VERSION_NO", hardwareVersionNo.getValue());
map.put("ADDITIONAL_DATA", additionalData.getValue());
Object addData = additionalData.getValue();
//additionalData解密
String additional_Str = null;
if(null!=addData){
String raw_additional_Str = decrptDesString(String.valueOf(addData));
if(null!=raw_additional_Str){
additional_Str = Hex2GBKStringUtil.toStringHex(raw_additional_Str);
https://www.sodocs.net/doc/5416337043.html,("HEX字符串转为GBK文本串为 /n {}",additional_Str);
}
}

try{
String[] infos = parseAdditionalInfo(additional_Str);
//智能卡号
map.put("ICCARD_ID", infos[0]);
//客户ID
map.put("CUSTOMER_ID", infos[1]);
//用户ID
map.put("USER_ID", infos[2]);
//客户姓名
map.put("CUSTOMER_NAME", infos[3]);
//客户地址
map.put("USER_ADDRESS", infos[4]);
}catch(Exception e){
log.error("解析附加信息失败 , 原因: {}",e);
//智能卡号
map.put("ICCARD_ID", null);
//客户ID
map.put("CUSTOMER_ID", null);
//用户ID
map.put("USER_ID", null);
//客户姓名
map.put("CUSTOMER_NAME", null);
//客户地址
map.put("USER_ADDRESS", null);
}
return map;
}

/**
* 解包
* @param im
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private Map accessToUserFeesBillPacket_(IsoMessage im){
https://www.sodocs.net/doc/5416337043.html,("accessToUserFeesBillPacket_ : receive Msg :"+printIsoMessage(im));
//银行代码
IsoValue bankCode = im.getAt(4);
//功能码
IsoValue functionCode = im.getAt(5);
//boss响应吗
IsoValue retCode = im.getAt(6);
//加密标识
IsoValue isEncrp

t = im.getAt(8);
//客户编码
IsoValue customerNo = im.getAt(19);
//客户名称
IsoValue customerName = im.getAt(20);
//账户编码
IsoValue accountNo = im.getAt(21);
//帐户名称
IsoValue accountName = im.getAt(22);
//业务编码
IsoValue serviceType = im.getAt(23);
//服务号码
IsoValue subscriNo = im.getAt(24);

//余额
IsoValue balance = im.getAt(29);

if(!String.valueOf(functionCode).equals(String.valueOf(GET_USERFEE_RESPONSE_FUNCNO))){
log.error("功能码不正确");
}

Map map = new HashMap();
map.put("RETCODE", retCode.getValue());
map.put("TRANSMSG", getTransMsg(paddingRetCode(String.valueOf(retCode.getValue()))));
// map.put("BANK_CODE", bankCode.getValue());
map.put("IS_ENCRPT", isEncrpt.getValue());
map.put("CUSTOMER_NO", customerNo.getValue());
map.put("CUSTOMER_NAME", customerName.getValue());
map.put("BALACNE", balance==null?null:balance.getValue());

return map;
}

/**
*

校验响应数据包的校验码是否正确


* @param rawData 待校验数据串
* @param validateCode 校验码
* @return
*/
private boolean validateResponseData(String rawData,String validateCode){
return validateCode.equals(MessageDigestMD5.keyedEncode(rawData, ""));
}

/**
*

获取返回码对应的消息


* @param code
* @return
*/
private String getTransMsg(String code){
if(retCodeMsgMap.containsKey(code)){
return retCodeMsgMap.get(code);
}else{
return "交易失败";
}
}

private String paddingRetCode(String rawcode){
if(rawcode.length()<4){
return "0000".substring(rawcode.length())+rawcode;
}else{
return rawcode;
}
}

/**
*

解密DES加密串


* @param rawData
* @return
* @throws Exception
*/
private String decrptDesString(String rawData) {
String rstr = null;
https://www.sodocs.net/doc/5416337043.html,("DES解密算法解密源字符串: /n {}",rawData);
if(null==rawData){
log.error("源加密字符串为空!");
return null;
}
try {
// 设置密钥 静态,设置一次即可 密钥是固定的,写死即可
DesEncrypt.setKey("A000000000000000");
rstr = DesEncrypt
.desDecrypt(rawData);
} catch (Exception e) {
log.error("DES解密算法 解密密码串失败, 原因: {}",e);
}
https://www.sodocs.net/doc/5416337043.html,("DES解密算法解密结果: /n {}",rstr);
return rstr;
}

private String printIsoMessage(IsoMessage m) {
StringBuffer sbuff = new StringBuffer();
sbuff.append("TYPE: " + Integer.toHexString(m.getType()) +" /n");
for (int i = 2; i < 128; i++) {
if (m.hasField(i)) {
sbuff.append("F " + i + "(" + m.getField(i).getType() + "): " + m.getObjectValue(i) + " -> '"
+ m.getField(i).toString() + "' /n");
}
}
return sbuff.toString();
}

/**
*

解密附加信息
* 用于 解析 根据机顶盒号查询用户响应
*


* @param s
* @return [0]

智能卡号
* [1] 客户ID
* [2] 用户ID
* [3] 客户姓名
* [4] 客户地址
* @throws Exception
*/
private String[] parseAdditionalInfo(String s) throws Exception{
if(null!=s && !"".equals(s)){
String[] ss = s.trim().split("//t");
if(ss.length!=5){
throw new Exception("解析附加信息失败,信息格式不正确!");
}else{
return new String[]{ss[0].trim(),ss[1].trim(),ss[2].trim(),ss[3].trim(),ss[4].trim()};
}
}else{
throw new Exception("解析附加信息失败,信息格式不正确!");
}
}

/**
*

发送报文时生成校验码


* @param rawData
* @return
*/
private String generateValidateCode(String rawData){
return MessageDigestMD5.keyedEncode(rawData, "");
}

public static void main(String[] strs) throws Exception{
PacketDataOperateService pd = new PacketDataOperateService();
// System.out.println(pd.generateValidateCode("7F003E28000000001613039575047501073200000000000000000000000000000006200010060000001210600001287906傅雪晶1200000301582511傅雪晶-帐户00120000030158250000067062"));
// System.out.println(pd.generateValidateCode("12345678901234567890").length());
String r = pd.decrptDesString("3EE1B1F40175DC92701588F6F40A7762B05859FACE94BA7CD7EC5513E4DBE3C519CD9BFF085642C765BDAD8F06D719F5A75161E54ACF5230BBD811E91E00A6A1C7FE957F19AEF1F6");
String additional_Str = Hex2GBKStringUtil.toStringHex(r);
String[] ss = pd.parseAdditionalInfo(additional_Str);
for(String s : ss){
System.out.println(s);
}
//System.out.println(pd.paddingRetCode("3"));
}

public Resource getTemplatePath() {
return templatePath;
}

public void setTemplatePath(Resource templatePath) {
this.templatePath = templatePath;
}

}