银联网关支付 java版
2018-01-22 14:30
120 查看
最近做一个PC端商城,需要添加银联网关支付,几经摸索,终于搞出来了,现将代码贴下,以供参考!
1.开发前的准备
1.1 去银联官网下载相关证书及配置文件
https://open.unionpay.com/ajweb/help/file/techFile?productId=1
1.2 申请测试账号
https://open.unionpay.com/ajweb/account/testPara
1.3 注意区分,生产环境还是测试环境,测试环境使用4个证书,生成环境使用3个证书,(我使用的是5.1.0版本,测试证书)
2.项目中的相关配置
2.1 项目中增加银联配置文件
其中,银联的版本视下载版本而定,密码和用户名均不需用修改;
将下载的证书按图链接的地址进行配置;
支付的两个回调接口,一个回调接口一般叫做frontUrl,这个地址是由用户点击返回商户的时候银联才会调用。另外一个回调接口叫做backUrl,这个地址是银联接到支付请求后异步回调的接口,一般网站的业务逻辑在此处处理。
2.2 导入银联所需要的相关工具类
2.2.1 AutoLoadServlet
package com.snow.core.pay.yl.config;
}
2.3 项目启动时加载配置文件
2.4 修改JDK及增加jar包
security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider 因为加入了jdk的第三方安全库,需要额外配置
2.5 演示流程
2.6 相关代码
/*银联支付/
public String goUnionpay(){
以上博文是自己参考别人的经验做完支付后的总结,有不正确的地方,还望各位路过的大牛批评指正。
1.开发前的准备
1.1 去银联官网下载相关证书及配置文件
https://open.unionpay.com/ajweb/help/file/techFile?productId=1
1.2 申请测试账号
https://open.unionpay.com/ajweb/account/testPara
1.3 注意区分,生产环境还是测试环境,测试环境使用4个证书,生成环境使用3个证书,(我使用的是5.1.0版本,测试证书)
2.项目中的相关配置
2.1 项目中增加银联配置文件
其中,银联的版本视下载版本而定,密码和用户名均不需用修改;
将下载的证书按图链接的地址进行配置;
支付的两个回调接口,一个回调接口一般叫做frontUrl,这个地址是由用户点击返回商户的时候银联才会调用。另外一个回调接口叫做backUrl,这个地址是银联接到支付请求后异步回调的接口,一般网站的业务逻辑在此处处理。
2.2 导入银联所需要的相关工具类
2.2.1 AutoLoadServlet
package com.snow.core.pay.yl.config;
import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import com.snow.core.pay.yl.sdk.SDKConfig; /** * 功能:从应用的classpath下加载acp_sdk.properties属性文件并将该属性文件中的键值对赋值到SDKConfig类中 <br> * 声明:以下代码只是为了方便接入方测试而提供的样例代码,商户可以根据自己需要,按照技术文档编写。该代码仅供参考,不提供编码,性能,规范性等方面的保障 */ public class AutoLoadServlet extends HttpServlet { @Override public void init(ServletConfig config) throws ServletException { SDKConfig.getConfig().loadPropertiesFromSrc(); super.init(); } } **2.2.2 ChinapayConfig** package com.snow.core.pay.yl.config; import com.snow.core.pay.yl.sdk.SDKConfig; import com.snow.core.pay.yl.sdk.SDKConstants; /** * 名称: demo中用到的方法<br> * 日期: 2015-09<br> * 版权: 中国银联<br> * 声明:以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己需要,按照技术文档编写。该代码仅供参考,不提供编码,性能,规范性等方面的保障<br> */ public class ChinapayConfig { //默认配置的是UTF-8 public static String encoding = "UTF-8"; //全渠道固定值 public static String version = SDKConfig.getConfig().getVersion(); //后台服务对应的写法参照 FrontRcvResponse.java public static String frontUrl = SDKConfig.getConfig().getFrontUrl(); //后台服务对应的写法参照 BackRcvResponse.java public static String backUrl = SDKConfig.getConfig().getBackUrl();//受理方和发卡方自选填写的域[O]--后台通知地址 // 商户发送交易时间 格式:YYYYMMDDhhmmss public static String getCurrentTime() { return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); } // AN8..40 商户订单号,不能含"-"或"_" public static String getOrderId() { return new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()); }
}
2.3 项目启动时加载配置文件
2.4 修改JDK及增加jar包
security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider 因为加入了jdk的第三方安全库,需要额外配置
2.5 演示流程
2.6 相关代码
/*银联支付/
public String goUnionpay(){
String basePath = getRequest().getScheme() + "://" + getRequest().getServerName() + ":" + getRequest().getServerPort(); if(StrUtils.objectIsNotNull(id)){ try { //订单ID order = microShopService.findEntityById(EcOrder.class, id); //参数配置 Map<String, String> requestData = new HashMap<String, String>(); requestData.put("version", ChinapayConfig.version); //版本号,全渠道默认值 requestData.put("encoding", ChinapayConfig.encoding); //字符集编码,可以使用UTF-8,GBK两种方式 requestData.put("signMethod", "01"); //签名方法,只支持 01:RSA方式证书加密 requestData.put("txnType", "01"); //交易类型 ,01:消费 4000 requestData.put("txnSubType", "01"); //交易子类型, 01:自助消费 requestData.put("bizType", "000201"); //业务类型,B2C网关支付,手机wap支付 requestData.put("channelType", "07"); //渠道类型,这个字段区分B2C网关支付和手机wap支付;07:PC,平板 08:手机 /***商户接入参数***/ requestData.put("merId", "777290058155070"); //商户号码,请改成自己申请的正式商户号或者open上注册得来的777测试商户号 requestData.put("accessType", "0"); //接入类型,0:直连商户 requestData.put("orderId", order.getCode()); //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则 requestData.put("txnTime", ChinapayConfig.getCurrentTime()); //订单发送时间,取系统时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效 requestData.put("currencyCode", "156"); //交易币种(境内商户一般是156 人民币) //查询支付金额 BigDecimal totPrice = null; totPrice = new BigDecimal(order.getTotalPrice());//查询金额 requestData.put("txnAmt", String.valueOf((totPrice.multiply(new BigDecimal(100))).longValue())); //交易金额,单位分,不要带小数点 /** 设置url 必填,不能修改 */ StringBuffer rn_url = getRequest().getRequestURL(); String contextUrl = rn_url.delete(rn_url.length() - getRequest().getRequestURI().length(), rn_url.length()).append(getRequest().getContextPath()).toString(); //地址配置 requestData.put("frontUrl", contextUrl +"/pc/ec/pay/tp002PcEcPaymentAction_goFrontUrl.action"); //前台请求地址 requestData.put("backUrl", contextUrl +"/pc/ec/pay/tp002PcEcPaymentAction_goBackUrl.action"); //后台请求地址 Map<String, String> submitFromData = AcpService.sign(requestData, ChinapayConfig.encoding); //签名 System.out.println(submitFromData.toString()); String requestFrontUrl = "https://gateway.test.95516.com/gateway/api/frontTransReq.do"; //获取请求银联的前台地址:对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrl String html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData, ChinapayConfig.encoding); //生成自动跳转的Html表单 //将生成的html写到浏览器中完成自动跳转打开银联支付页面;这里调用signData之后,将html写到浏览器跳转到银联页面之前均不能对html中的表单项的名称和值进行修改,如果修改会导致验签不通过 getResponse().getWriter().write(html); } catch (Exception e) { e.printStackTrace(); } } return null; } /**前台请求地址*/ public String goFrontUrl(){ String result = "orderNotExist"; try { logger.info("FrontRcvResponse前台接收报文返回开始"); String encoding = getRequest().getParameter(SDKConstants.param_encoding); logger.info("返回报文中encoding=[" + encoding + "]"); Map<String, String> respParam = getAllRequestParam();//获取银联回调的参数 // 打印请求报文 LogUtil.printRequestLog(respParam); Map<String, String> valideData = valideData();//验证签名 if (!AcpService.validate(valideData, encoding)) {//验证签名失败 logger.info("验证签名结果[失败]."); } else { String respCode = valideData.get("respCode");//验证成功后获取银联响应码 if ("00".equals(respCode)) {//响应码为00表示支付成功。 logger.info("验证签名结果[成功]"); //TODO:这个方法在用户支付成功后点击返回商户时,银联回调,这里写回调成功后的一些业务逻辑。 String orderCode = valideData.get("orderId"); order = microShopService.findEntityByAttribute(EcOrder.class, "code", orderCode); if(null != order){ EcOrderItemGroup eoig = microShopService.findEntityByAttribute(EcOrderItemGroup.class, "ecOrder.id", order.getId()); microShopId = eoig.getMicroShop().getId(); eoig.setPaymentStatus(PaymentStatusConstant.EO_PS_HASTOPAY); eoig.setDealStatus(DealStatusConstant.EO_DS_HASCONFIRMED); eoig = ecOrderItemGroupService.merge(eoig); } List<String> keyWordList = searchKeyWordService.findSearchKeyWordByCount(6, "desc",getPcCompanyCode()); if(null != keyWordList && keyWordList.size() > 0){ getRequest().setAttribute("keyWordList", keyWordList); } result = "home"; } else { logger.info("验证签名结果[失败]."); } } } catch (Exception e) { e.printStackTrace(); } return result; } /**后台请求地址*/ public void goBackUrl(){ try { logger.info("[进入银联支付回调方法]"); String encoding = getRequest().getParameter(SDKConstants.param_encoding); // 获取银联通知服务器发送的后台通知参数 Map<String, String> valideData = valideData(); //重要!验证签名前不要修改reqParam中的键值对的内容,否则会验签不过 if (!AcpService.validate(valideData, encoding)) { logger.info("验证签名结果[失败]."); } else { logger.info("验证签名结果[成功]."); //【注:为了安全验签成功才应该写商户的成功处理逻辑】交易成功,更新商户订单状态 String respCode = valideData.get("respCode"); if ("00".equals(respCode)) {//银联返回00代表支付成功 //:TODO:该方法在用户支付成功后银联自动异步回调。此处可以写订单支付成功后的业务逻辑 getResponse().getWriter().print("ok");//这里一定要写响应。否则银联会认为商户后台没有收到回调信息。 } } LogUtil.writeLog("BackRcvResponse接收后台通知结束"); } catch (Exception e) { e.printStackTrace(); } } /**验证银联签名*/ private static Map<String, String> valideData() throws IOException { String encoding = getRequest().getParameter(SDKConstants.param_encoding); // 获取银联通知服务器发送的后台通知参数 Map<String, String> reqParam = getAllRequestParam(); Map<String, String> valideData = null; if (null != reqParam && !reqParam.isEmpty()) { Iterator<Map.Entry<String, String>> it = reqParam.entrySet().iterator(); valideData = new HashMap<String, String>(reqParam.size()); while (it.hasNext()) { Map.Entry<String, String> e = it.next(); String key = (String) e.getKey(); String value = (String) e.getValue(); value = new String(value.getBytes(encoding), encoding); valideData.put(key, value); } } return valideData; } /**获取请求参数中所有的信息*/ public static Map<String, String> getAllRequestParam() { Map<String, String> res = new HashMap<String, String>(); Enumeration<?> temp = getRequest().getParameterNames(); if (null != temp) { while (temp.hasMoreElements()) { String en = (String) temp.nextElement(); String value = getRequest().getParameter(en); res.put(en, value); // 在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段> if (res.get(en) == null || "".equals(res.get(en))) { res.remove(en); } } } return res; }
以上博文是自己参考别人的经验做完支付后的总结,有不正确的地方,还望各位路过的大牛批评指正。
相关文章推荐
- 网关支付、银联代扣通道、快捷支付、银行卡支付等网上常见支付方式接口说明
- 网关支付、银联代扣通道、快捷支付、银行卡支付分别是怎么样进行支付的?
- java银联支付
- 移动App后台Java开发银联支付后台接口
- 网关支付、银联代扣通道、快捷支付、银行卡支付等网上常见支付方式接口说明
- 银联开发报 java.security.NoSuchProviderException: no such provider: BC
- java(服务端)-集成银联支付,含代码
- Java 银联支付官网demo测试及项目整合代码
- Java 银联支付官网demo测试及项目整合代码
- 银联在线 网关支付 (JAVA版)
- java 银联,支付宝接口
- JavaWEB后端支付银联,支付宝,微信对接
- 银联在线 网关支付 (JAVA版)
- 银联二维码支付java 实现
- 银联支付Java开发
- java 银联接口开发
- Idea-Java接入银联支付的Demo
- Idea-Java接入银联支付的Demo
- 银联全渠道平台接入B2C网关支付
- 网关支付、银联代扣通道、快捷支付、银行卡支付等网上常见支付方式接口说明