之前也用PHP对接建行的H5龙之付,但建行的支付手册对于PHP版本仅支持windows2003的服务器环境,所以处理到建行支付回调时便搁浅了,这次Java开发的商品支付分期同样需要跟建行龙支付对接,换汤不换药
开发前准备
建行龙支付需要先下载E路护航软件,然后安装相应的证书文件,最后登陆建行网站支付设置后台,
登陆后设置建行支付网页回调和服务器回调
建行龙支付需要引入建行自带的第三方jar包用于支付回掉的签名认证
mvn install:install-file -Dfile=C:\Users\Administrator\Desktop\netpay.jar -DgroupId=CCBSign -DartifactId=RSASig -Dversion=1.0 -Dpackaging=jar
其中,-Dfile参数指你自定义JAR包文件所在的路径,并依次指定了自定义的GroupId、ArtifactId和Version信息
可以看到本地maven包路径中生成
pom.xml
CCBSign
RSASig
1.0
建行支付工具类
package com.shadmin.common.util;
public class CCBPayUtil {
private static String BANKURL = "https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain"; //龙支付url
//无论有无值都需要参与mac运算的参数
private static String MERCHANTID = "必填"; //商户代码 //注意,这里有坑,MERCHANTID需要传的值,文档写的是商户代码,网上找有demo也是传商户代码,找建行技术员咨询也是跟我说传商户代码,但经过多次测试,这里需要传递的却是商户编号
private static String POSID = "必填"; //商户柜台代码
private static String BRANCHID = "必填"; //分行代码
private static String ORDERID = "必填"; //支付编号
private static String PAYMENT = "必填"; //付款金额
private static String CURCODE = "01"; //币种01为人民币
private static String TXCODE = "520100"; //交易码 由建行统一分配为520100
private static String REMARK1 = "";
private static String REMARK2 = "";
private static String TYPE = "1"; //接口类型
private static String PUB = "必填"; //公钥后30位
private static String GATEWAY = ""; //网关类型
private static String CLIENTIP = "";//客户端IP
private static String REGINFO = ""; //客户注册信息
private static String PROINFO = ""; //客户注册信息
private static String REFERER = ""; //商品信息
//无论有无值都需要参与mac运算的参数-完
//有值时才参与mac运算的参数
private static String INSTALLNUM = null;//信用卡支付分期期数,必须为大于1的整数,当分期期数为空或无该字段上送时,则视为普通的网上支付
private static String TIMEOUT = "";//订单超时时间 格式:YYYYMMDDHHMMSS 银行系统时间> TIMEOUT时拒绝交易,若送空值则不判断超时。
private static String ISSINSCODE = ""; //银行代码 仅对PC跨行生效,手机跨行无需上送该字段
//二级商户信息,若上送二级商户信息则八个二级商户信息字段必须都送值
private static String SMERID = ""; //二级商户代码
private static String SMERNAME = ""; //二级商户名称
private static String SMERTYPEID = ""; //二级商户类别代码
private static String SMERTYPE = ""; //二级商户类别名称
private static String TRADECODE = ""; //交易类型代码
private static String TRADENAME = ""; //交易类型名称
private static String SMEPROTYPE = ""; //商品类别代码
private static String PRONAME = ""; //商品类别名称
private String THIRDAPPINFO = "android时必需填,可以是任意字符串,获取支付结果时会用到";//当该字段有值时,则会优先启动建行APP支付,否则优先启动h5页面支付。
//有值时才参与mac运算的参数-完
/**
* 类初始化函数
*/
public CCBPayUtil(String merchant_id,String post_id, String branch_id, String pub){
MERCHANTID = merchant_id; //商户代码(由建行统一分配)
POSID = post_id; //商户柜台代码(由建行统一分配)
BRANCHID = branch_id; //分行代码(由建行统一分配)
PUB = pub.substring(pub.length()-30); //公钥后30位(仅作为源串参加MD5摘要,不作为参数传递)
}
/**
* 参数校验生成MAC
* @return string 生成的MAC码
*/
private static String makeMAC(){
String param = "MERCHANTID="+MERCHANTID+"&POSID="+POSID+"&BRANCHID="+BRANCHID+"&ORDERID="+ORDERID
+"&PAYMENT="+PAYMENT+"&CURCODE="+CURCODE+"&TXCODE="+TXCODE+"&REMARK1="+REMARK1+"&REMARK2="+REMARK2
+"&TYPE="+TYPE+"&PUB="+PUB+"&GATEWAY="+GATEWAY+"&CLIENTIP="+CLIENTIP+"®INFO="+REGINFO+"&PROINFO="+PROINFO
+"&REFERER="+REFERER;
//选填参数,分期
if(INSTALLNUM != null && !INSTALLNUM.equals("")){
param += "&INSTALLNUM="+INSTALLNUM;
}
return Md5Util.md5(param);
}
/**
* 参数校验拼接url
* @param mac 编码
* @return [type] [description]
*/
private static String buildUrlParam(String mac){
String param = "MERCHANTID="+MERCHANTID+"&POSID="+POSID+"&BRANCHID="+BRANCHID+"&ORDERID="+ORDERID
+"&PAYMENT="+PAYMENT+"&CURCODE="+CURCODE+"&TXCODE="+TXCODE+"&REMARK1="+REMARK1+"&REMARK2="+REMARK2
+"&TYPE="+TYPE+"&GATEWAY="+GATEWAY+"&CLIENTIP="+CLIENTIP+"®INFO="+REGINFO+"&PROINFO="+PROINFO
+"&REFERER="+REFERER;
//选填参数,分期
if(INSTALLNUM != null && !INSTALLNUM.equals("")){
param += "&INSTALLNUM="+INSTALLNUM;
}
param += "&MAC="+mac;
return param;
}
/**
*
* @param order_id 订单编号(由商户提供,最长30位)
* @param pay_ment 支付金额
* @param install_num 建行跳转到的url
* @return
*/
public static String CCBOrder(String order_id,String pay_ment, String install_num){
ORDERID = order_id;
PAYMENT = pay_ment;
INSTALLNUM = install_num;
//生成MAC
String mac = makeMAC();
//构建url参数
String urlParam = buildUrlParam(mac);
//建行H5跳转网址
String url = BANKURL+"?"+urlParam;
return url;
}
}
生成支付页面的H5链接
/**
* 添加分期订单
*/
@RequestMapping(value = "doAddStagingOrder.htm", method = RequestMethod.POST)
public @ResponseBody JSONObject doAddStagingOrder(HttpServletRequest request){
Map params = new HashMap();
String ext_code = request.getParameter("ext_code");
params.put("ext_code", ext_code);
String pro_info = request.getParameter("pro_info"); //订单信息
params.put("pro_info", pro_info);
String pay_ment = request.getParameter("pay_ment"); //分期金额
params.put("pay_ment", pay_ment);
String install_num = request.getParameter("install_num"); //分期期数
params.put("install_num", install_num);
String date = String.valueOf(new Date().getTime());
String random = String.valueOf((int)(Math.random()*10000000));
String order_no = date.concat(random);
params.put("order_no", order_no);
//写入到分期订单表
int res = jiangxiStagingOrderService.addStagingOrder(params);
JSONObject jsonObject = new JSONObject();
if(res>0){
new CCBPayUtil(你的Merchant_id, 你的getPost_id, 你的getBranch_id, 你的getPub_key);
String url = CCBPayUtil.CCBOrder(order_no, pay_ment, install_num);
jsonObject.put("code", 1);
jsonObject.put("message","生成订单成功");
jsonObject.put("data", url);
}else{
//生成订单失败
jsonObject.put("code", -1);
jsonObject.put("message", "生成订单失败");
}
return jsonObject;
}
建行龙支付服务器回调
package com.shadmin.web.jiangxi;
import CCBSign.RSASig;
import com.alibaba.fastjson.JSONObject;
import com.shadmin.common.util.CCBPayUtil;
import com.shadmin.common.util.Md5Util;
import com.shadmin.entity.JiangxiMerchant;
import com.shadmin.entity.JiangxiStagingOrder;
import com.shadmin.service.jiangxi.JiangxiMerchantService;
import com.shadmin.service.jiangxi.JiangxiStagingOrderService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;
@Controller
@RequestMapping("/jiangxi/")
public class MobileJiangxiController{
private static org.apache.log4j.Logger logger = Logger.getLogger(MobileJiangxiController.class);
/**
* 分期订单回调修改订单状态
*/
@RequestMapping("updateStagingOrder.htm")
public @ResponseBody JSONObject updateStagingOrder(HttpServletRequest request){
//枚举的形式打印所有的reques返回值,并记录日志
Enumeration parameterNames = request.getParameterNames();
StringBuffer stringBuffer = new StringBuffer();
while (parameterNames.hasMoreElements()){
String parameter = parameterNames.nextElement();
stringBuffer.append(parameter + "=" + request.getParameter(parameter)+"———");
}
logger.info("龙支付回调传参:"+stringBuffer);
//获取request龙支付传参POSID...参数和sign,并拼接校验的strSrc串
StringBuffer strSrc = new StringBuffer();
strSrc.append("POSID=" + request.getParameter("POSID"));
strSrc.append("&BRANCHID=" + request.getParameter("BRANCHID"));
strSrc.append("&ORDERID=" + request.getParameter("ORDERID"));
strSrc.append("&PAYMENT=" + request.getParameter("PAYMENT"));
strSrc.append("&CURCODE=" + request.getParameter("CURCODE"));
strSrc.append("&REMARK1=" + request.getParameter("REMARK1"));
strSrc.append("&REMARK2=" + request.getParameter("REMARK2"));
strSrc.append("&ACC_TYPE=" + request.getParameter("ACC_TYPE"));
strSrc.append("&SUCCESS=" + request.getParameter("SUCCESS"));
strSrc.append("&TYPE=" + request.getParameter("TYPE"));
strSrc.append("&REFERER=" + request.getParameter("REFERER"));
strSrc.append("&CLIENTIP=" + request.getParameter("CLIENTIP"));
strSrc.append("&ACCDATE=" + request.getParameter("ACCDATE"));
if (request.getParameter("INSTALLNUM") != null) {
strSrc.append("&INSTALLNUM=" + request.getParameter("INSTALLNUM"));
}
String strSign=request.getParameter("SIGN");
// //将龙支付的src(query string)转成map
// String[] strs = strSrc.split("&");
// Map map = new HashMap();
// for (String s : strs) {
// String[] ms = s.split("=");
// map.put(ms[0], ms[1]);
// }
//以下基于龙支付返回以上strSrc和strPubKey字符串数据处理
Map params = new HashMap();
String status = "0";
params.put("status", status);
String order_no = request.getParameter("ORDERID"); //获取strSrc中的ORDERID
params.put("order_no", order_no);
List orderList = jiangxiStagingOrderService.getStagingOrderList(params);
JSONObject jsonObject = new JSONObject();
if(orderList != null && orderList.size() > 0){
//第一步:订单有效,调用银行三方类校验签名
String ext_code = orderList.get(0).getExt_code(); //获取该订单的推广码
List merchant = jiangxiMerchantService.getMerchantListToJiangxi(new HashMap() {{
put("ext_code", ext_code);
}});
String pub_key = merchant.get(0).getPub_key(); //获取商户的龙支付密钥
//引入银行第三方类用来校验签名
RSASig rsa = new RSASig();
rsa.setPublicKey(pub_key);
if(rsa.verifySigature(strSign, strSrc.toString())&& request.getParameter("SUCCESS").equals("Y")){
//第二步:比较strSrc中的PAYMENT是否与数据库中的金额一致
if (Double.parseDouble(orderList.get(0).getPay_ment()) == Double.parseDouble(request.getParameter("PAYMENT"))) {
params.put("status", "1");
jiangxiStagingOrderService.updateStagingOrder(params);
jsonObject.put("code", 1);
jsonObject.put("message", "order_no:" + order_no + "龙支付成功");
logger.info("龙支付:成功修改订单order_no:" + order_no);
} else {
jsonObject.put("code", 0);
jsonObject.put("message", "订单价格被篡改:数据库价格pay_ment=" + orderList.get(0).getPay_ment() + ";龙支付回调价格PAYMENT:" + request.getParameter("PAYMENT") + ";或者订单回调SUCCESS=" + request.getParameter("SUCCESS"));
logger.info("龙支付:订单价格被篡改:数据库价格pay_ment=" + orderList.get(0).getPay_ment() + ";龙支付回调价格PAYMENT:" + request.getParameter("PAYMENT") + ";或者订单回调SUCCESS=" + request.getParameter("SUCCESS"));
}
}else {
jsonObject.put("code", 0);
jsonObject.put("message", "签名校验失败");
logger.info("龙支付:签名校验失败");
}
}else{
jsonObject.put("code", 0);
jsonObject.put("message", "无效订单或已完成订单");
logger.info("龙支付:无效订单或已完成订单");
}
return jsonObject;
}
}
参考路径
本来是由1,2,3的指导,目前只剩下3了
android 建行龙支付教程3:从建行app获取支付结果
maven怎么 引入(或引用/使用) 自定义(或本地/第三方) jar的三种方式 图文教程