微信小程序,调用建行支付。
转载声明:
本文为摘录自“博客园”,版权归原作者所有。
温馨提示:
为了更好的体验,请点击原文链接进行浏览
摘录时间:
2021-10-23 17:47:14
由于微信支付费率是千分之六,在得知道建行龙支付可以做到千分之二,公司在成本这块就果断采取接建行,废话不说了直接贴代码
Service 层
相关的参数要求还得细对建行的文档
@Service public class CCBPayServiceImpl implements CCBPayApi { private static final Logger LOGGER = LoggerFactory.getLogger(CCBPayServiceImpl.class); @Override public PayResult cCBPayment(PayRequestInfo payRequestInfo) throws BizException { BigDecimal orderPrice = TypeConversionUtil.getBigDecimal(payRequestInfo.getOrderPrice()); HashMap<String, String> map = new HashMap<String, String>(); map.put("MERCHANTID", CCBConstants.MERCHANTID); map.put("POSID", CCBConstants.POSID); map.put("BRANCHID", CCBConstants.BRANCHID); map.put("ORDERID", payRequestInfo.getOrderNo()); map.put("PAYMENT", orderPrice.toString()); map.put("CURCODE", CCBConstants.CURCODE); map.put("REMARK1", CCBConstants.REMARK1); map.put("REMARK2", CCBConstants.REMARK2); map.put("TXCODE", CCBConstants.TXCODE); map.put("TYPE", CCBConstants.TYPE); map.put("GATEWAY", CCBConstants.GATEWAY); map.put("CLIENTIP", payRequestInfo.getSpbillCreateIp()); map.put("REGINFO", CCBConstants.REGINFO); map.put("PROINFO", CCBConstants.PROINFO); map.put("REFERER", CCBConstants.REFERER); // map.put("TIMEOUT", null); map.put("TRADE_TYPE", payRequestInfo.getTradeType()); map.put("SUB_APPID", payRequestInfo.getAppId()); map.put("SUB_OPENID", payRequestInfo.getOpenId()); // MD5加密 StringBuilder sb = new StringBuilder(); sb.append("MERCHANTID=").append(CCBConstants.MERCHANTID).append("&POSID=").append(CCBConstants.POSID) .append("&BRANCHID=").append(CCBConstants.BRANCHID).append("&ORDERID=") .append(payRequestInfo.getOrderNo()).append("&PAYMENT=").append(orderPrice.toString()) .append("&CURCODE=").append(CCBConstants.CURCODE).append("&TXCODE=").append(CCBConstants.TXCODE) .append("&REMARK1=").append(CCBConstants.REMARK1).append("&REMARK2=").append(CCBConstants.REMARK2) .append("&TYPE=").append(CCBConstants.TYPE).append("&PUB=").append(CCBConstants.PUB).append("&GATEWAY=") .append(CCBConstants.GATEWAY).append("&CLIENTIP=").append(payRequestInfo.getSpbillCreateIp()) .append("®INFO=").append(CCBConstants.REGINFO).append("&PROINFO=").append(CCBConstants.PROINFO) .append("&REFERER=").append(CCBConstants.REFERER).append("&TRADE_TYPE=") .append(payRequestInfo.getTradeType()).append("&SUB_APPID=").append(payRequestInfo.getAppId()) .append("&SUB_OPENID=").append(payRequestInfo.getOpenId()); String sign = MD5Utils.MD5Encode(sb.toString(), "UTF-8").toLowerCase(); map.put("MAC", sign); String data = null; CCBPayResult cCBPayResult = null; try { data = HttpClientUtil.doPost(CCBConstants.CCB_CREATE_ORDER_URL, map); JSONObject parseObject = JSON.parseObject(data); LOGGER.info("cCBPayment data [{}]", data); cCBPayResult = createOrderUrl(parseObject.getString("PAYURL")); if (!"true".equals(cCBPayResult.getSuccess()) || !"000000".equals(cCBPayResult.getErrcode())) { throw new BizException(ErrorCode.BIZ_EXCEPTION.getErrcode(), "抱歉调用建行支付接口失败"); } } catch (Exception e) { LOGGER.info("cCBPayment Error [{}],{}", data, e); throw new BizException(ErrorCode.BIZ_EXCEPTION.getErrcode(), e.getMessage()); } return cCBPayResult; } public CCBPayResult createOrderUrl(String payUrl) { CCBPayResult ccbPayResult = new CCBPayResult(); String data = null; try { data = HttpClientUtil.doPost(payUrl, null); JSONObject parseObject = JSON.parseObject(data); ccbPayResult.setSuccess(parseObject.getString("SUCCESS")); ccbPayResult.setErrcode(parseObject.getString("ERRCODE")); ccbPayResult.setErrmsg(parseObject.getString("ERRMSG")); ccbPayResult.setTxcode(parseObject.getString("TXCODE")); ccbPayResult.setAppId(parseObject.getString("appId")); ccbPayResult.setTimeStamp(parseObject.getString("timeStamp")); ccbPayResult.setNonceStr(parseObject.getString("nonceStr")); ccbPayResult.setPackageValue(parseObject.getString("package")); ccbPayResult.setSignType(parseObject.getString("signType")); ccbPayResult.setPaySign(parseObject.getString("paySign")); ccbPayResult.setPartnerid(parseObject.getString("partnerid")); ccbPayResult.setPrepayid(parseObject.getString("prepayid")); ccbPayResult.setMwebUrl(parseObject.getString("mweb_url")); LOGGER.info("createOrderUrl data [{}]", data); } catch (Exception e) { LOGGER.info("createOrderUrl Error [{}],{}", data, e); e.printStackTrace(); } return ccbPayResult; } }
封装请求的基本参数PayRequestInfo
public class PayRequestInfo implements java.io.Serializable { private static final long serialVersionUID = -1249414762571339701L; /** * 订单号 */ private String orderNo; /** * 商品描述 */ private String body; /** * 支付类型 1:为原生态微信支付渠道 2:建议支付渠道 */ private Integer payType; /** * 支付金额,单位统一为分 */ private Integer orderPrice; /** * 公众号/小程序 用户唯一标识openId */ private String openId; /** * ip */ private String spbillCreateIp; /** * 微信支付时回调地址 */ private String notifyUrl; /** * 公众号/小程序的appid */ private String appId; /** * 交易类型 */ private String tradeType; public String getOrderNo() { return orderNo; } public void setOrderNo(String orderNo) { this.orderNo = orderNo; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } public Integer getPayType() { return payType; } public void setPayType(Integer payType) { this.payType = payType; } public Integer getOrderPrice() { return orderPrice; } public void setOrderPrice(Integer orderPrice) { this.orderPrice = orderPrice; } public String getOpenId() { return openId; } public void setOpenId(String openId) { this.openId = openId; } public String getSpbillCreateIp() { return spbillCreateIp; } public void setSpbillCreateIp(String spbillCreateIp) { this.spbillCreateIp = spbillCreateIp; } public String getNotifyUrl() { return notifyUrl; } public void setNotifyUrl(String notifyUrl) { this.notifyUrl = notifyUrl; } public String getTradeType() { return tradeType; } public void setTradeType(String tradeType) { this.tradeType = tradeType; } public String getAppId() { return appId; } public void setAppId(String appId) { this.appId = appId; } }
请求建行支付结构返回的结果集
public class CCBPayResult extends PayResult implements Serializable{ private static final long serialVersionUID = 8387757441935173456L; /** * 返回状态码 */ private String success; /** * 错误码 * 000000 表示交易成功,非 000000 表示交易失败 */ private String errcode; /** * 错误信 */ private String errmsg; /** * 交易码 */ private String txcode; /** * 微信分配的 APPID */ private String appId; /** * 时间戳 */ private String timeStamp; /** * 随机串 */ private String nonceStr; /** * 数据包 */ private String packageValue; /** * 签名方式 */ private String signType; /** * 签名数据 */ private String paySign; /** * 子商户的商户号 */ private String partnerid; /** * 预支付交易会话 ID */ private String prepayid; /** * 微信H5支付中间页面 URL */ private String mwebUrl; public String getSuccess() { return success; } public void setSuccess(String success) { this.success = success; } public String getErrcode() { return errcode; } public void setErrcode(String errcode) { this.errcode = errcode; } public String getErrmsg() { return errmsg; } public void setErrmsg(String errmsg) { this.errmsg = errmsg; } public String getTxcode() { return txcode; } public void setTxcode(String txcode) { this.txcode = txcode; } public String getAppId() { return appId; } public void setAppId(String appId) { this.appId = appId; } public String getTimeStamp() { return timeStamp; } public void setTimeStamp(String timeStamp) { this.timeStamp = timeStamp; } public String getNonceStr() { return nonceStr; } public void setNonceStr(String nonceStr) { this.nonceStr = nonceStr; } public String getPackageValue() { return packageValue; } public void setPackageValue(String packageValue) { this.packageValue = packageValue; } public String getSignType() { return signType; } public void setSignType(String signType) { this.signType = signType; } public String getPaySign() { return paySign; } public void setPaySign(String paySign) { this.paySign = paySign; } public String getPartnerid() { return partnerid; } public void setPartnerid(String partnerid) { this.partnerid = partnerid; } public String getPrepayid() { return prepayid; } public void setPrepayid(String prepayid) { this.prepayid = prepayid; } public String getMwebUrl() { return mwebUrl; } public void setMwebUrl(String mwebUrl) { this.mwebUrl = mwebUrl; } }
HttpClientUtil
public class HttpClientUtil { private static HttpClient httpClient = new DefaultHttpClient(); /** * 发送 get 请求 * * @param url * @return */ public static String get(String url) { String body = null; try { // get 请求 HttpGet httpGet = new HttpGet(url); // 发送请求 HttpResponse httpresponse = httpClient.execute(httpGet); // 获取返回数据 HttpEntity entity = httpresponse.getEntity(); body = EntityUtils.toString(entity, "UTF-8"); if (entity != null) { entity.consumeContent(); } } catch (Exception e) { e.printStackTrace(); } return body; } /** * 发送get 请求 * * @param url * @param params * @return */ public static String get(String url, List<NameValuePair> params) { String body = null; try { HttpGet httpGet = new HttpGet(url); String data = EntityUtils.toString(new UrlEncodedFormEntity(params)); httpGet.setURI(new URI(httpGet.getURI().toString() + "?" + data)); HttpResponse httpResponse = httpClient.execute(httpGet); HttpEntity entity = httpResponse.getEntity(); body = EntityUtils.toString(entity, "UTF-8"); if (entity != null) { entity.consumeContent(); } } catch (Exception e) { e.printStackTrace(); } return body; } /** * post * * @param url * @param params * @return */ public static String post(String url, List<NameValuePair> params) { String body = null; try { if (httpClient == null) { httpClient = new DefaultHttpClient(); } HttpPost httpPost = new HttpPost(url); httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); HttpResponse httpResponse = httpClient.execute(httpPost); HttpEntity entity = httpResponse.getEntity(); body = EntityUtils.toString(entity, "UTF-8"); if (entity != null) { entity.consumeContent(); } } catch (Exception e) { e.printStackTrace(); } return body; } /** * 以 closeableHttpClient方式 发送get 请求 * * @param uri * @return */ public static String getCloseableHttpResponse(String url) { String body = null; try { CloseableHttpClient client = HttpClients.custom().build(); HttpGet httpGet = new HttpGet(url); CloseableHttpResponse chr = client.execute(httpGet); String data = EntityUtils.toString(chr.getEntity(), "UTF-8"); JSONObject json = JSON.parseObject(data); body = json.toString(); } catch (Exception e) { e.printStackTrace(); } return body; } /** * post 请求 * @param url * @param param * @return */ public static String doPost(String url, Map<String, String> param) { CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null; String resultString = ""; try { HttpPost httpPost = new HttpPost(url); if (param != null) { List<NameValuePair> paramList = new ArrayList<>(); for (String key : param.keySet()) { paramList.add(new BasicNameValuePair(key, param.get(key))); } UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, "utf-8"); httpPost.setEntity(entity); } response = httpClient.execute(httpPost); resultString = EntityUtils.toString(response.getEntity(), "utf-8"); } catch (Exception e) { e.printStackTrace(); } finally { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } return resultString; } }
MD5Utils
public class MD5Utils { private static String byteArrayToHexString(byte b[]) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) resultSb.append(byteToHexString(b[i])); return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } public static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = new String(origin); MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) resultString = byteArrayToHexString(md.digest(resultString .getBytes())); else resultString = byteArrayToHexString(md.digest(resultString .getBytes(charsetname))); } catch (Exception exception) { } return resultString; } private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; }
之前忘记没贴上Controller 层 现在加上
@Autowired
private PayApi payApi;
/** * 统一添加订单 * * @param paymentOrder * @return */ @WeiXinLogin @RequestMapping("/addOrder") public ResponseModel addOrder(OrderVO orderVO) { LoginUserVO user = RequestContext.getContext().getUser(); String key = PAYMENT_ORDER_ADD_LOCK_KEY + user.getMemberId(); try { orderVO.setMemberId(user.getMemberId()); orderVO.setOrderNo(wechatOrderNo.nextId() + ""); orderVO.setPayType(PayType.CCBPAY);// 订单支付渠道为建行 if (redisLockUtil.tryLock(key, 10)) { Integer orderId = orderApi.addOrder(orderVO); return new ResponseModel(orderId); } else { return new ResponseModel(ErrorCode.BIZ_EXCEPTION.getErrcode(), "操作过于频繁", null); } } catch (BizException e) { LOGGER.error("addOrder error,{}", e); return new ResponseModel(e.getErrcode(), e.getErrm(), null); } finally { redisLockUtil.unlock(key); } } /** * 支付 * @param orderId * @param request * @return * @throws Exception */ @WeiXinLogin @RequestMapping("/prePay") public ResponseModel prePay(Integer orderId, HttpServletRequest request) throws Exception { String key = PAYMENT_ORDER_PREPAY_LOCK_KEY + orderId; try { LoginUserVO user = RequestContext.getContext().getUser(); PaymentOrderRecord orderRecord = orderApi.getOrderById(orderId); PayRequestInfo payRequestInfo = new PayRequestInfo(); payRequestInfo.setBody("xxx缴费"); payRequestInfo.setNotifyUrl(systemConfig.getPayNotifyUrl());//该回调地址只是微信支付,与建行支付没关系 如果是建行支付直接忽略这行代码 payRequestInfo.setOpenId(user.getAppOpenId()); payRequestInfo.setOrderNo(orderRecord.getOrderNo()); payRequestInfo.setOrderPrice(orderRecord.getOrderPrice()); payRequestInfo.setPayType(orderRecord.getPayType()); payRequestInfo.setSpbillCreateIp(getIpAddr(request)); payRequestInfo.setTradeType("MINIPRO"); payRequestInfo.setAppId(systemConfig.getAppletsAppId()); String randomNum = System.currentTimeMillis() + new Random().nextInt(10000) + ""; if (redisLockUtil.tryLock(key, randomNum, 5)) { PayResult payResult = payApi.pay(payRequestInfo); return new ResponseModel(payResult); } else { return new ResponseModel(ErrorCode.BIZ_EXCEPTION.getErrcode(), "操作过于频繁", null); } } catch (BizException e) { LOGGER.error("prePay error,{}", e); return new ResponseModel(e.getErrcode(), e.getErrm(), null); } finally { redisLockUtil.unlock(key); } } /** * 建行支付结果通知 * * @param request * @return */ @RequestMapping("/callBackCCB") public String callBackCCB(HttpServletRequest request) { LOGGER.info("callBackCCB start!"); try { Map<String, String> map = new HashMap<String, String>(); Enumeration<String> parameterNames = request.getParameterNames(); StringBuilder data = new StringBuilder(); while (parameterNames.hasMoreElements()) { String name = (String) parameterNames.nextElement(); String value = request.getParameter(name); map.put(name, value); data.append(name).append("=").append(value).append("&"); } LOGGER.info("callBackCCB source data :[{}]", data.toString());// 建行返回调原数据 StringBuilder sb = new StringBuilder(); sb.append("POSID=").append(map.get("POSID")).append("&BRANCHID=").append(map.get("BRANCHID")) .append("&ORDERID=").append(map.get("ORDERID")).append("&PAYMENT=").append(map.get("PAYMENT")) .append("&CURCODE=").append(map.get("CURCODE")).append("&REMARK1=").append(map.get("REMARK1")) .append("&REMARK2=").append(map.get("REMARK2")).append("&ACC_TYPE=").append(map.get("ACC_TYPE")) .append("&SUCCESS=").append(map.get("SUCCESS")).append("&TYPE=").append(map.get("TYPE")) .append("&REFERER=").append(map.get("REFERER")).append("&CLIENTIP=").append(map.get("CLIENTIP")) .append("&ACCDATE=").append(map.get("ACCDATE")); RSASig rsaSig = new RSASig(); rsaSig.setPublicKey(CCBConstants.PUBLICKEY);// 公钥 boolean flag = rsaSig.verifySigature(map.get("SIGN"), sb.toString()); LOGGER.info("callBackCCB Check :[{}]", flag); if ("Y".equals(map.get("SUCCESS")) && flag) {//表示支付成功 CallbackResult callbackResult = new CallbackResult(); callbackResult.setReturnCode("Y"); callbackResult.setReturnMsg("Ok"); callbackResult.setOrderNo(map.get("ORDERID"));// 订单号 payApi.callBack(callbackResult); } } catch (Exception e) { LOGGER.error("callBackCCB error,{}", e); } return null; }
//PayApi 接口的实现类
package com.qft.payment.service.pay; import java.util.Date; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.qft.payment.api.order.OrderApi; import com.qft.payment.api.order.constant.OrderConstant; import com.qft.payment.api.order.constant.PayType; import com.qft.payment.api.order.model.NotesOrder; import com.qft.payment.api.order.model.PaymentOrderRecord; import com.qft.payment.api.pay.CCBPayApi; import com.qft.payment.api.pay.PayApi; import com.qft.payment.api.pay.WechatPayApi; import com.qft.payment.api.pay.model.CallbackResult; import com.qft.payment.api.pay.model.PayRequestInfo; import com.qft.payment.api.pay.model.PayResult; import com.qft.payment.api.pay.model.RefundInfo; import com.qft.payment.api.pay.model.WechatRefundResutl; import com.qft.payment.api.payaccount.PayAccountApi; import com.qft.payment.common.constant.ErrorCode; import com.qft.payment.common.exception.BizException; import com.qft.payment.common.util.SimpleRedisLockUtil; /** * * @author ckj * */ @Service public class PayServiceImpl implements PayApi { private static final Logger LOGGER = LoggerFactory.getLogger(PayServiceImpl.class); @Autowired private WechatPayApi wechatPayApi; @Autowired private CCBPayApi cCBPayApi; private static final String ORDER_CALLBACK_LOCK_KEY = "order:lock:callback"; @Autowired private SimpleRedisLockUtil redisLockUtil; @Override public PayResult pay(PayRequestInfo payRequestInfo) throws BizException { PayResult payResult = new PayResult(); if (payRequestInfo.getPayType() == null) { throw new BizException(ErrorCode.BIZ_EXCEPTION.getErrcode(), "支付类型不能为null"); } try { if (payRequestInfo.getPayType() == PayType.WECHATPAY) {// 表示微信原生态支付渠道 payResult = wechatPayApi.jsApiPay(payRequestInfo); } else if (payRequestInfo.getPayType() == PayType.CCBPAY) {// 表示建行支付渠道 payResult = cCBPayApi.cCBPayment(payRequestInfo); } addNotesOrder(payRequestInfo); } catch (Exception e) { LOGGER.info("pay Error [{}],{}", payRequestInfo.getOrderNo(), e); throw new BizException(ErrorCode.BIZ_EXCEPTION.getErrcode(), e.getMessage()); } return payResult; } }