由于微信支付费率是千分之六,在得知道建行龙支付可以做到千分之二,公司在成本这块就果断采取接建行,废话不说了直接贴代码
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;
}
}
来源:oschina
链接:https://my.oschina.net/u/4413367/blog/4450280