1)先开去银行申请,问银行要到demo 和证书;
2)根据demo的字段看看银行发的的开发接口文档;
3)将需要的字段可以创建到Modle中
package ytd.zhlv.util.pay;
public class ICBCModel {
//必输:1,选输:2
//
//private String orderPostUrl = "https://B2C.icbc.com.cn/servlet/ICBCINBSEBusinessServlet";
// 1接口版本号
private String interfaceName = "ICBC_PERBANK_B2C";
// 1交易日期时间
private String interfaceVersion = "1.0.0.11";
// 1交易数据
// 整合所有交易数据形成的xml明文串,并做BASE64编码;
// 具体格式定义见下文;
// 注意:
// 需有xml头属性;整个字段使用BASE64编码;
// xml明文中没有回车换行和多余空格;
private String tranData;
// 1订单签名数据
// 必输,
// 商户使用工行提供的签名API和商户证书将tranData的xml明文串进行签名,得到二进制签名数据,然后进行BASE64编码后得到可视的merSignMsg;
// 注意:签名时是针对tranData的xml明文,不是将tranData进行BASE64编码后的串;
private String merSignMsg;
// 1商城证书公钥
// 商户用二进制方式读取证书公钥文件后,进行BASE64编码后产生的字符串;
private String merCert;
private String orderDate;
// 1订单号:客户支付后商户网站产生的一个唯一的定单号,该订单号应该在相当长的时间内不重复。工行通过订单号加订单日期来唯一确认一笔订单的重复性。
private Long orderid;
// 1订单金额:客户支付订单的总金额,一笔订单一个,以分为单位。不可以为零,必需符合金额标准。
private Double amount;
// 1分期付款期数:取值:1、3、6、9、12、18、24;1代表全额付款,必须为以上数值,否则订单校验不通过。
private Integer installmentTimes = 1;
// TODO
// 1商户账号:商户入账账号,只能交易时指定。(商户付给银行手续费的账户,可以在开户的时候指定,也可以用交易指定方式;用交易指定方式则使用此商户账号)
private String merAcct="0200024109031548569";
// 2商品编号
private String goodsID = "";
// 1商品名称
private String goodsName = "";
// 2商品数量
private Integer goodsNum = 1;
// 2已含运费金额
private Double carriageAmt;
// 1检验联名标志:取值“1”:客户支付时,网银判断该客户是否与商户联名,是则按上送金额扣帐,否则展现未联名错误;取值“0”:不检验客户是否与商户联名,按上送金额扣帐。
private Integer verifyJoinFlag = 0;
// 2语言版本:默认为中文版 。取值:“EN_US”为英文版;取值:“ZH_CN”或其他为中文版。注意:大小写敏感。
private String language = "ZH_CN";
// 1支付币种:用来区分一笔支付的币种,目前工行只支持使用人民币(001)支付。 取值: “001”
private String curType = "001";
//TODO
// 1商户代码:唯一确定一个商户的代码,由商户在工行开户时,由工行告知商户。
private String merID="0200EC23335149";
// 1支持订单支付的银行卡种类:默认“2”。取值范围为0、1、2,其中0表示仅允许使用借记卡支付,1表示仅允许使用信用卡支付,2表示借记卡和信用卡都能对订单进行支付
private Integer creditType = 2;
// 1通知类型
// 在交易转账处理完成后把交易结果通知商户的处理模式。
// 取值“HS”:在交易完成后实时将通知信息以HTTP协议POST方式,主动发送给商户,发送地址为商户端随订单数据提交的接收工行支付结果的URL即表单中的merURL字段;
// 取值“AG”:在交易完成后不通知商户。商户需使用浏览器登录工行的B2C商户服务网站,或者使用工行提供的客户端程序API主动获取通知信息。
private String notifyType = "HS";
// 2结果发送类型
// 选输
// 取值“0”:无论支付成功或者失败,银行都向商户发送交易通知信息;
// 取值“1”,银行只向商户发送交易成功的通知信息。
// 只有通知方式为HS时此值有效,如果使用AG方式,可不上送此项,但签名数据中必须包含此项,取值可为空。
private Integer resultType = 1;
// 2商户reference:上送商户网站域名(支持通配符,例如“*.某B2C商城.com”),如果上送,工行会在客户支付订单时,校验商户上送域名与客户跳转工行支付页面之前网站域名的一致性。
private String merReference = "";
//TODO
// 2客户端IP:选输,工行在支付页面显示该信息。 注意: 1、 使用IPV4格式。 2、 上送的是客户端的公网IP。 3、 当商户reference项送空时,该项必输。
private String merCustomIp = "";
//TODO
// 2虚拟商品/实物商品标志位:选输,取值“0”:虚拟商品; 取值“1”,实物商品。
private Integer goodsType = 0;
// 2买家用户号:选输,工行在支付页面显示该信息。
private String merCustomID = "";
// 2买家联系电话:选输,工行在支付页面显示该信息。
private String merCustomPhone = "";
// 2收货地址:选输,工行在支付页面显示该信息。
private String goodsAddress = "";
// 2订单备注:选输,工行在支付页面显示该信息。
private String merOrderRemark = "";
// 2商城提示
private String merHint = "";
// 2备注字段1
private String remark1 = "";
// 2备注字段2
private String remark2 = "";
// 1返回商户URL
// 必须合法的URL,交易结束,将客户引导到商户的此url,即通过客户浏览器post交易结果信息到商户的此URL
// 注意:该URL应使用http协议(不能使用https协议),端口号应为80或不指定。
private String merURL = "";
// 2返回商户变量:商户自定义,当返回银行结果时,作为一个隐藏域变量,商户可以用此变量维护session等等。由客户端浏览器支付完成后提交通知结果时是明文传输,建议商户对此变量使用额外安全防范措施,如签名、base64
private String merVAR = "";
// 2工银e支付注册标志:工银e支付注册标志,标识客户在支付该笔订单时,是否使用订单指定的下述信息注册工银e支付。 0-否,1-是
private String e_isMerFlag = "";
// 2客户姓名
private String e_Name = "";
// 2客户手机号:如果工银e支付注册标志e_isMerFlag上送1,则此字段必输
private String e_TelNum = "";
// 2客户证件类型:0:身份证 1:护照 2:军官证 3:士兵证 4:回乡证(港澳台往来通行证) 5:临时身份证 6:户口本 7:其他 9:警官证 12:外国人永久居住证 21:边民证
private String e_CredType = "";
// 2客户证件号
private String e_CredNum = "";
public String getTranData() {
return tranData;
}
public void setTranData(String tranData) {
this.tranData = tranData;
}
public String getMerSignMsg() {
return merSignMsg;
}
public void setMerSignMsg(String merSignMsg) {
this.merSignMsg = merSignMsg;
}
public String getMerCert() {
return merCert;
}
public void setMerCert(String merCert) {
this.merCert = merCert;
}
public String getInterfaceName() {
return interfaceName;
}
public void setInterfaceName(String interfaceName) {
this.interfaceName = interfaceName;
}
public String getInterfaceVersion() {
return interfaceVersion;
}
public void setInterfaceVersion(String interfaceVersion) {
this.interfaceVersion = interfaceVersion;
}
public String getOrderDate() {
return orderDate;
}
public void setOrderDate(String orderDate) {
this.orderDate = orderDate;
}
public Long getOrderid() {
return orderid;
}
public void setOrderid(Long orderid) {
this.orderid = orderid;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public Integer getInstallmentTimes() {
return installmentTimes;
}
public void setInstallmentTimes(Integer installmentTimes) {
this.installmentTimes = installmentTimes;
}
public String getMerAcct() {
return merAcct;
}
public void setMerAcct(String merAcct) {
this.merAcct = merAcct;
}
public String getGoodsID() {
return goodsID;
}
public void setGoodsID(String goodsID) {
this.goodsID = goodsID;
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public Integer getGoodsNum() {
return goodsNum;
}
public void setGoodsNum(Integer goodsNum) {
this.goodsNum = goodsNum;
}
public Double getCarriageAmt() {
return carriageAmt;
}
public void setCarriageAmt(Double carriageAmt) {
this.carriageAmt = carriageAmt;
}
public Integer getVerifyJoinFlag() {
return verifyJoinFlag;
}
public void setVerifyJoinFlag(Integer verifyJoinFlag) {
this.verifyJoinFlag = verifyJoinFlag;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getCurType() {
return curType;
}
public void setCurType(String curType) {
this.curType = curType;
}
public String getMerID() {
return merID;
}
public void setMerID(String merID) {
this.merID = merID;
}
public Integer getCreditType() {
return creditType;
}
public void setCreditType(Integer creditType) {
this.creditType = creditType;
}
public String getNotifyType() {
return notifyType;
}
public void setNotifyType(String notifyType) {
this.notifyType = notifyType;
}
public Integer getResultType() {
return resultType;
}
public void setResultType(Integer resultType) {
this.resultType = resultType;
}
public String getMerReference() {
return merReference;
}
public void setMerReference(String merReference) {
this.merReference = merReference;
}
public String getMerCustomIp() {
return merCustomIp;
}
public void setMerCustomIp(String merCustomIp) {
this.merCustomIp = merCustomIp;
}
public Integer getGoodsType() {
return goodsType;
}
public void setGoodsType(Integer goodsType) {
this.goodsType = goodsType;
}
public String getMerCustomID() {
return merCustomID;
}
public void setMerCustomID(String merCustomID) {
this.merCustomID = merCustomID;
}
public String getMerCustomPhone() {
return merCustomPhone;
}
public void setMerCustomPhone(String merCustomPhone) {
this.merCustomPhone = merCustomPhone;
}
public String getGoodsAddress() {
return goodsAddress;
}
public void setGoodsAddress(String goodsAddress) {
this.goodsAddress = goodsAddress;
}
public String getMerOrderRemark() {
return merOrderRemark;
}
public void setMerOrderRemark(String merOrderRemark) {
this.merOrderRemark = merOrderRemark;
}
public String getMerHint() {
return merHint;
}
public void setMerHint(String merHint) {
this.merHint = merHint;
}
public String getRemark1() {
return remark1;
}
public void setRemark1(String remark1) {
this.remark1 = remark1;
}
public String getRemark2() {
return remark2;
}
public void setRemark2(String remark2) {
this.remark2 = remark2;
}
public String getMerURL() {
return merURL;
}
public void setMerURL(String merURL) {
this.merURL = merURL;
}
public String getMerVAR() {
return merVAR;
}
public void setMerVAR(String merVAR) {
this.merVAR = merVAR;
}
public String getE_isMerFlag() {
return e_isMerFlag;
}
public void setE_isMerFlag(String e_isMerFlag) {
this.e_isMerFlag = e_isMerFlag;
}
public String getE_Name() {
return e_Name;
}
public void setE_Name(String e_Name) {
this.e_Name = e_Name;
}
public String getE_TelNum() {
return e_TelNum;
}
public void setE_TelNum(String e_TelNum) {
this.e_TelNum = e_TelNum;
}
public String getE_CredType() {
return e_CredType;
}
public void setE_CredType(String e_CredType) {
this.e_CredType = e_CredType;
}
public String getE_CredNum() {
return e_CredNum;
}
public void setE_CredNum(String e_CredNum) {
this.e_CredNum = e_CredNum;
}
}
4)执行 Control的 toPayOrder() 方法。(这里直接执行了,也可以通过页面提交一些参数在执行 方法)
package ytd.zhlv.util.pay;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import ytd.zhlv.util.base.BaseAction;
public class ICBCAction extends BaseAction {
public String toPayOrder()
{
/*Order order = orderManager.getByObjectId(orderId); //orderId 订单号
List<OrderItem> orderItems = orderItemManager.getOrderItemsByOrderId(orderId); */
String goodsID = "1";
String goodsName = "shanghai";
// for (OrderItem item : orderItems) {
// goodsID += item.getObjectId()+ ",";
// goodsName += item.getProduct().getName() + ",";
// }
// goodsID.substring(0, goodsID.length()-1);
// goodsName.substring(0, goodsID.length()-1);
// if (goodsID.length()>=30) {
// goodsID.substring(0, 25);
// goodsID += "等";
// }
// if (goodsName.length()>=60) {
// goodsName.substring(0, 55);
// goodsName += "等";
// }
String merURL = "http://localhost:8000/SmartCiry/icbcAction_getReturnValue.action";
ICBCModel icbcModel = new ICBCModel();
// icbcModel icbcModel = new icbcModel();
SimpleDateFormat myFmt=new SimpleDateFormat("yyyyMMddHHmmss");
icbcModel.setOrderDate(myFmt.format(new Date()));
icbcModel.setOrderid(2017121121221L);
icbcModel.setAmount((0.1));
icbcModel.setGoodsName("50jin订单");
icbcModel.setGoodsID("1");
icbcModel.setGoodsName("测试订单");
icbcModel.setMerReference("localhost");
icbcModel.setMerCustomIp("127.0.0.1");
// TODO 商户账号
// icbcModel.setMerAcct("10011********017989");
// TODO 商户代码
// icbcModel.setMerID("1001******4821");
// TODO 返回商户URL
icbcModel.setMerURL(merURL);
StringBuilder strXml = new StringBuilder();
strXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
strXml.append("<B2CReq>");
//接口名称
strXml.append("<interfaceName>" + icbcModel.getInterfaceName() + "</interfaceName>");
//接口版本号
strXml.append("<interfaceVersion>" + icbcModel.getInterfaceVersion() + "</interfaceVersion>");
//订单信息
strXml.append("<orderInfo>");
//交易日期时间
strXml.append("<orderDate>20171230144920</orderDate>");
//支付币种
strXml.append("<curType>" + icbcModel.getCurType() + "</curType>");
//商户代码
strXml.append("<merID>" + icbcModel.getMerID() + "</merID>");
//订单信息列表
strXml.append("<subOrderInfoList>");
//订单信息
strXml.append("<subOrderInfo>");
//订单编号
strXml.append("<orderid>" +2017121121221L+ "</orderid>");
//订单金额
strXml.append("<amount>" + icbcModel.getAmount().intValue() + "</amount> ");
//分期付款期数 1代表全额付款
strXml.append("<installmentTimes>" + icbcModel.getInstallmentTimes() + "</installmentTimes>");
//商户账号
strXml.append("<merAcct>0200024109031548569</merAcct>");
//商品编号
strXml.append("<goodsID>" + icbcModel.getGoodsID() + "</goodsID>");
//商品名称
strXml.append("<goodsName>" + icbcModel.getGoodsName() + "</goodsName>");
//商品数量
strXml.append("<goodsNum>" + 1 + "</goodsNum>");
//已含运费金额
strXml.append("<carriageAmt></carriageAmt>");
strXml.append("</subOrderInfo>");
strXml.append("</subOrderInfoList>");
strXml.append("</orderInfo>");
strXml.append("<custom>");
//检验联名标志 取值“1”:客户支付时,网银判断该客户是否与商户联名
strXml.append("<verifyJoinFlag>" + icbcModel.getVerifyJoinFlag() + "</verifyJoinFlag>");
//语言版本 取值:“EN_US”为英文版;取值:“ZH_CN”或其他为中文版
strXml.append("<Language>" + icbcModel.getLanguage() + "</Language>");
strXml.append("</custom>");
strXml.append("<message>");
//支持订单支付的银行卡种类
strXml.append("<creditType>" + icbcModel.getCreditType() + "</creditType>");
//通知类型
strXml.append("<notifyType>" + icbcModel.getNotifyType() + "</notifyType>");
//结果发送类型
strXml.append("<resultType>" + icbcModel.getResultType() + "</resultType>");
//商户reference
strXml.append("<merReference>" + icbcModel.getMerReference() + "</merReference>");
//客户端IP 当商户reference项送空时,该项必输
strXml.append("<merCustomIp>" + icbcModel.getMerCustomIp() + "</merCustomIp>");
//虚拟商品/实物商品标志位 取值“0”:虚拟商品 取值“1”,实物商品
strXml.append("<goodsType>" + icbcModel.getGoodsType() + "</goodsType>");
//买家用户号
strXml.append("<merCustomID></merCustomID>");
//买家联系电话
strXml.append("<merCustomPhone></merCustomPhone>");
//收货地址
strXml.append("<goodsAddress></goodsAddress>");
//订单备注
strXml.append("<merOrderRemark></merOrderRemark>");
//商城提示
strXml.append("<merHint></merHint>");
//备注字段1
strXml.append("<remark1></remark1>");
//备注字段2
strXml.append("<remark2></remark2>");
//返回商户URL
strXml.append("<merURL>" + icbcModel.getMerURL() + "</merURL>");
//返回商户变量
strXml.append("<merVAR>" + icbcModel.getMerVAR() + "</merVAR>");
strXml.append("</message>");
strXml.append("<extend>");
strXml.append("<e_isMerFlag>" + icbcModel.getE_isMerFlag() + "</e_isMerFlag>");
strXml.append("<e_Name>" + icbcModel.getE_Name() + "</e_Name>");
strXml.append("<e_TelNum>" + icbcModel.getE_TelNum() + "</e_TelNum>");
strXml.append("<e_CredType>" + icbcModel.getE_CredType() + "</e_CredType>");
strXml.append("<e_CredNum>" + icbcModel.getE_CredNum() + "</e_CredNum>");
strXml.append("</extend>");
strXml.append("</B2CReq>");
//获取工商银行验证
// CBCPayOnline.getCheckInfo(icbcModel);
// byte[] temp = ReturnValue.base64enc(strXml.toString().getBytes());
icbcModel.setTranData(strXml.toString());
ICBCOPayOnline cbcPayOnline = new ICBCOPayOnline();
cbcPayOnline.getBase64ICBC(icbcModel);
// icbcModel.seticbcModel(returnValue);
//将订单数据送往页面提交
put("ICBC",icbcModel);
put("order",1);
// request.setAttribute("icbcModel", icbcModel);
//request.setAttribute("order", 1);
// return getFileBasePath() + "javaApiDemo";
return "list";
}
}
5)验证证书(很重要,需要银行给的证书 在Control中调用此类的方法)工行base64加密:我们需要加密的有三个字段:tranData,merSignMsg,merCert
package ytd.zhlv.util.pay;
import java.io.FileInputStream;
import java.util.Properties;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import cn.com.infosec.icbc.ReturnValue;
public class ICBCOPayOnline {
private static Logger LOGGER=LogManager.getLogger(ICBCOPayOnline.class);
public static final String ICBC_PROPERTIES = "icbc.properties";
private static String propFileName = "icbc.properties"; // 指定资源文件保存的位置
private static Properties prop = new Properties(); // 创建并实例化Properties对象的实例
private static String groupName;// 集团名称
private static String groupNo;// 集团编号
private static String account;// 基本账号
private static String shopName;// 商城中文名
private static String shopCode;// 商城代码
private static String crtName;// 证书名称
private static String crtPasswd;// 证书密码
private static String icbcUrl;// B2C商户支付页面连接地址
static {
// 相关参数定义
ICBCOPayOnline _client = new ICBCOPayOnline();
try {
prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(ICBC_PROPERTIES));
groupName = prop.getProperty("groupName");
groupNo = prop.getProperty("groupNo");
account = prop.getProperty("account");
shopName = prop.getProperty("shopName");
shopCode = prop.getProperty("shopCode");
crtName = prop.getProperty("crtName");
crtPasswd = prop.getProperty("crtPasswd");
} catch (Exception e) {
e.printStackTrace();
}
}
public ICBCModel getBase64ICBC(ICBCModel icbcModel) {
String tranData = icbcModel.getTranData();
System.out.println("明文:" + tranData);
String password = "11111111";
String returnTransData = "";
String returnSignMsg = "";
String returnCert = "";
try {
byte[] byteSrc = tranData.getBytes();
char[] keyPass = password.toCharArray();
FileInputStream in1 = new FileInputStream("e:\\user.crt");
byte[] bcert = new byte[in1.available()];
in1.read(bcert);
in1.close();
FileInputStream in2 = new FileInputStream("e:\\user.key");
byte[] bkey = new byte[in2.available()];
in2.read(bkey);
in2.close();
byte[] sign = ReturnValue.sign(byteSrc, byteSrc.length, bkey, keyPass);
if (sign == null) {
System.out.println("签名失败,签名返回为空。请检查证书私钥和私钥保护口令是否正确。");
} else {
System.out.println("签名成功");
byte[] transDataByte = ReturnValue.base64enc(tranData.getBytes());
String transDataBase64 = new String(transDataByte).toString();
System.out.println("XML明文BASE64编码:" + transDataBase64);
byte[] EncSign = ReturnValue.base64enc(sign);
String SignMsgBase64 = new String(EncSign).toString();
System.out.println("签名信息BASE64编码:" + SignMsgBase64);
byte[] EncCert = ReturnValue.base64enc(bcert);
String CertBase64 = new String(EncCert).toString();
System.out.println("证书公钥BASE64编码:" + CertBase64);
byte[] DecSign = ReturnValue.base64dec(EncSign);
if (DecSign != null) {
System.out.println("签名信息BASE64解码成功");
byte[] DecCert = ReturnValue.base64dec(EncCert);
if (DecCert != null) {
System.out.println("证书公钥BASE64解码成功");
int a = ReturnValue.verifySign(byteSrc, byteSrc.length, DecCert, DecSign);
if (a == 0)
System.out.println("验签成功");
else
System.out.println("验签失败<br>验证返回码:" + a);
} else
System.out.println("证书BASE64解码失败");
} else
System.out.println("签名信息BASE64解码失败");
returnTransData = transDataBase64;
returnSignMsg = SignMsgBase64;
returnCert = CertBase64;
}
} catch (Exception e) {
System.out.println(e);
}
icbcModel.setTranData(returnTransData);
icbcModel.setMerSignMsg(returnSignMsg);
icbcModel.setMerCert(returnCert);
return icbcModel;
}
}
6) 实现页面 在4)中执行到return 返回的 list是前台页面 对应页面地址 我这里是SSH struts 对应 list <result name="list">xxxxx</result>(注意 form 中action对于的地址是银行提供的接口 地址)
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'icbcList.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<div class="box border">
<div class="box-title">
<h2><span class="glyphicon glyphicon-user"></span><jdf:message code="跳转到支付页面"/></h2>
</div>
<div class="box-body">
<form id="order" name="order" action="https://B2C.icbc.com.cn/servlet/ICBCINBSEBusinessServlet" method="post">
<input type="hidden" name="interfaceName" value="${ICBC.interfaceName}" />
<input type="hidden" name="interfaceVersion" value="${ICBC.interfaceVersion}" />
<input type="hidden" name="tranData" value="${ ICBC.tranData}" />
<input type="hidden" name="merSignMsg" value="${ ICBC.merSignMsg}" />
<input type="hidden" name="merCert" value="${ICBC.merCert } " />
</form>
<script type="text/javascript">
document.getElementById("order").submit();
</script>
</div>
</div>
</body>
</html>
如果测试的话可能还有 96112025错误 这里是因为工行测试环境的时间和本地时间!不!一!样!
知道原因了,打电话找银行吧。问问测试环境的时间是多少。