以下文章 所用证书为银联提供的测试证书,要真实在项目中使用需要向银联申请对应数据
进入银联网站https://open.unionpay.com 登录或注册用户 找到代付 下载对应测试证书 以及sdk操作工具类等等
集成springMVC 具体代码如下:
自定义springMVC的核心类继承 dispatcherServlet 重写 inits ... 我这里重写它是为了获取当前项目的所有url 所以就在这里顺便把证书初始化了,当前你也可以通过别的方式初始
上面sdkconfig.getconfig.loadProp 方法sdk里面应该 会有
然后接下来是 acp_sdk.properties 文件 这个也在你下载的 代付 dome 里面也有 具体改一下里面的类容如下:
##########################入网测试环境交易发送地址(线上测试需要使用生产环境交易请求地址)############################# ##交易请求地址 acpsdk.frontTransUrl=https://101.231.204.80:5000/gateway/api/frontTransReq.do acpsdk.backTransUrl=https://101.231.204.80:5000/gateway/api/backTransReq.do acpsdk.singleQueryUrl=https://101.231.204.80:5000/gateway/api/queryTrans.do acpsdk.batchTransUrl=https://101.231.204.80:5000/gateway/api/batchTrans.do acpsdk.fileTransUrl=https://101.231.204.80:9080/ acpsdk.appTransUrl=https://101.231.204.80:5000/gateway/api/appTransReq.do acpsdk.cardTransUrl=https://101.231.204.80:5000/gateway/api/cardTransReq.do #########################入网测试环境签名证书配置 ################################ ##签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到 #windows下 acpsdk.signCert.path=D:/certs/acp_test_sign.pfx #linux下(注意:在linux下读取证书需要保证证书有被应用读的权限) #acpsdk.signCert.path=/SERVICE01/usr/ac_frnas/conf/ACPtest/acp700000000000001.pfx ##签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败 acpsdk.signCert.pwd=000000 ##签名证书类型,固定不需要修改 acpsdk.signCert.type=PKCS12 ##########################验签证书配置################################ ##验证签名证书目录,只配置到目录即可,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试验证证书,生产环境所有商户共用开发包中的生产验签证书 #windows下 acpsdk.validateCert.dir=D:/certs/ #linux下(注意:在linux下读取证书需要保证证书有被应用读的权限) #acpsdk.validateCert.dir=/SERVICE01/usr/ac_frnas/conf/ACPtest/ ##########################加密证书配置################################ ##敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用) acpsdk.encryptCert.path=d:/certs/acp_test_enc.cer ##是否启用多证书模式(true:单证书|false:多证书---没有配置此项时,默认为单证书模式) acpsdk.singleMode=true
还有就是别忘了把dome里面 lib文件下的 jar 也拷贝到你的项目里面
bcprov-jdk15on-1.54.jar upacp_sdk-1.1.0-20151216.jar 这两个比较重要
然后随便来写一个 springmvc 的控制层类
package com.hnust.controller; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.jfinal.kit.HttpKit; import com.unionpay.acp.sdk.LogUtil; import com.upacp.yn.pay.AcpService; import com.upacp.yn.pay.DemoBase; import com.upacp.yn.pay.SDKConfig; @Controller @RequestMapping(value = "/unpay") public class UnPayController { @SuppressWarnings("unused") @RequestMapping(value = "/toDf", method = RequestMethod.GET) public void toDf(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //其实这四行就没用了 我懒得删除 String merId = req.getParameter("merId"); String txnAmt = req.getParameter("txnAmt"); String orderId = req.getParameter("orderId"); String txnTime = req.getParameter("txnTime"); Map<String, String> data = new HashMap<String, String>(); /*** 银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改 ***/ data.put("version", DemoBase.version); // 版本号 全渠道默认值 data.put("encoding", DemoBase.encoding_UTF8); // 字符集编码 可以使用UTF-8,GBK两种方式 data.put("signMethod", "01"); // 签名方法 data.put("txnType", "12"); // 交易类型 12:代付 data.put("txnSubType", "00"); // 默认填写00 data.put("bizType", "000401"); // 000401:代付 data.put("channelType", "07"); // 渠道类型 /*** 商户接入参数 ***/ data.put("merId", "自己的测试商户号"); // 商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试 data.put("accessType", "0"); // 接入类型,商户接入填0 ,不需修改(0:直连商户, 1: 收单机构 // 2:平台商户) data.put("orderId", "4001602001111611291184672731"); // 商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则 data.put("txnTime", "20170310110952"); // 订单发送时间,取系统时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效 data.put("accType", "01"); // 账号类型 01:银行卡02:存折03:IC卡帐号类型(卡介质) // 如果商户号开通了 商户对敏感信息加密的权限那么,需要对 卡号accNo加密使用: data.put("encryptCertId", AcpService.getEncryptCertId()); // 上送敏感信息加密域的加密证书序列号 String accNo = AcpService.encryptData("6216261000000000018", DemoBase.encoding_UTF8); // 这里测试的时候使用的是测试卡号,正式环境请使用真实卡号 data.put("accNo", accNo); // 代收交易的上送的卡验证要素为:姓名或者证件类型+证件号码 Map<String, String> customerInfoMap = new HashMap<String, String>(); customerInfoMap.put("certifTp", "01"); // 证件类型 customerInfoMap.put("certifId", "341126197709218366"); // 证件号码 // customerInfoMap.put("customerNm", "全渠道"); //姓名 String customerInfoStr = AcpService.getCustomerInfo(customerInfoMap, "6216261000000000018", DemoBase.encoding_UTF8); data.put("customerInfo", customerInfoStr); data.put("txnAmt", "10"); // 交易金额 单位为分,不能带小数点 data.put("currencyCode", "156"); // 境内商户固定 156 人民币 // data.put("billNo", "保险"); // 后台通知地址 data.put("backUrl", "这里加上域名/unpay/un_notify.do"); /** 对请求参数进行签名并发送http post请求,接收同步应答报文 **/ Map<String, String> reqData = AcpService.sign(data, DemoBase.encoding_UTF8); // 报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。 String requestBackUrl = SDKConfig.getConfig().getBackRequestUrl(); // 交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 // acpsdk.backTransUrl Map<String, String> rspData = AcpService.post(reqData, requestBackUrl, DemoBase.encoding_UTF8); // 发送请求报文并接受同步应答(默认连接超时时间30秒,读取返回结果超时时间30秒);这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过 /** 对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考-------------> **/ // 应答码规范参考open.unionpay.com帮助中心 下载 产品接口规范 《平台接入接口规范-第5部分-附录》 if (!rspData.isEmpty()) { if (AcpService.validate(rspData, DemoBase.encoding_UTF8)) { LogUtil.writeLog("验证签名成功"); String respCode = rspData.get("respCode"); if (("00").equals(respCode)) { // 交易已受理(不代表交易已成功),等待接收后台通知确定交易成功,也可以主动发起 查询交易确定交易状态。 // TODO // 如果返回卡号且配置了敏感信息加密,解密卡号方法: // String accNo1 = resmap.get("accNo"); // String accNo2 = AcpService.decryptPan(accNo1, "UTF-8"); // //解密卡号使用的证书是商户签名私钥证书acpsdk.signCert.path // LogUtil.writeLog("解密后的卡号:"+accNo2); } else if (("03").equals(respCode) || ("04").equals(respCode) || ("05").equals(respCode) || ("01").equals(respCode) || ("12").equals(respCode) || ("34").equals(respCode) || ("60").equals(respCode)) { // 后续需发起交易状态查询交易确定交易状态。 // TODO } else { // 其他应答码为失败请排查原因 // TODO } } else { LogUtil.writeErrorLog("验证签名失败"); // TODO 检查验证签名失败的原因 } } else { // 未返回正确的http状态 LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200"); } String reqMessage = DemoBase.genHtmlResult(reqData); String rspMessage = DemoBase.genHtmlResult(rspData); System.err.println(reqMessage); System.err.println(rspMessage); resp.getWriter().write( "代付交易</br>请求报文:<br/>" + reqMessage + "<br/>" + "应答报文:</br>" + rspMessage + ""); } // 回调 @RequestMapping(value = "/un_notify", method = RequestMethod.POST) public void un_notify(HttpServletRequest request, HttpServletResponse response) throws IOException { // 支付结果通用通知文档: String xmlMsg = HttpKit.readData(request); System.out.println("支付通知=" + xmlMsg); } } 下面截图 全部执行过程 以及打印:这是程序启动 加载证书的过程
直接以get的方式 访问测试打款 接口
执行接口 当中打印签名的过程
执行的 结果转账成功
开始走回调 然后你在处理 后台业务流程
新手发帖大神 勿喷 觉得可以的可以相互交流学习 wb_90@foxmail.com 微信支付 红包 退款 支付宝 支付退款 银联支付 等等 我都有封装好的现成的代码 大家可以一起交流
