Commit 5def62fe authored by jmdhappy's avatar jmdhappy
Browse files

微信支付SDK更换为weixin-java-pay,增加微信H5支付,优化一些异常情况的处理

parent dd9d81f9
package org.xxpay.service.channel.wechat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* User: rizenguo
* Date: 2014/10/29
* Time: 14:40
* 这里放置各种配置数据
*/
@RefreshScope
@Service
public class WxPayProperties {
@Value("${cert.root.path}")
private String certRootPath;
@Value("${wx.notify_url}")
private String notifyUrl;
public String getCertRootPath() {
return certRootPath;
}
public void setCertRootPath(String certRootPath) {
this.certRootPath = certRootPath;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
}
package org.xxpay.service.channel.wechat;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.config.WxPayConfig;
import java.io.File;
/**
* @author: dingzhiwei
* @date: 17/8/25
* @description:
*/
public class WxPayUtil {
/**
* 获取微信支付配置
* @param configParam
* @param tradeType
* @param certRootPath
* @param notifyUrl
* @return
*/
public static WxPayConfig getWxPayConfig(String configParam, String tradeType, String certRootPath, String notifyUrl) {
WxPayConfig wxPayConfig = new WxPayConfig();
JSONObject paramObj = JSON.parseObject(configParam);
wxPayConfig.setMchId(paramObj.getString("mchId"));
wxPayConfig.setAppId(paramObj.getString("appId"));
wxPayConfig.setKeyPath(certRootPath + File.separator + paramObj.getString("certLocalPath"));
wxPayConfig.setMchKey(paramObj.getString("key"));
wxPayConfig.setNotifyUrl(notifyUrl);
wxPayConfig.setTradeType(tradeType);
return wxPayConfig;
}
/**
* 获取微信支付配置
* @param configParam
* @return
*/
public static WxPayConfig getWxPayConfig(String configParam) {
WxPayConfig wxPayConfig = new WxPayConfig();
JSONObject paramObj = JSON.parseObject(configParam);
wxPayConfig.setMchId(paramObj.getString("mchId"));
wxPayConfig.setAppId(paramObj.getString("appId"));
wxPayConfig.setMchKey(paramObj.getString("key"));
return wxPayConfig;
}
}
......@@ -2,6 +2,7 @@ package org.xxpay.service.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
......@@ -34,8 +35,15 @@ public class MchInfoServiceController {
String mchId = paramObj.getString("mchId");
MchInfo mchInfo = mchInfoService.selectMchInfo(mchId);
JSONObject retObj = new JSONObject();
retObj.put("code", "0000");
if(StringUtils.isBlank(jsonParam)) {
retObj.put("code", "0001"); // 参数错误
retObj.put("msg", "缺少参数");
return retObj.toJSONString();
}
if(mchInfo == null) {
retObj.put("result", "");
retObj.put("code", "0002");
retObj.put("msg", "数据对象不存在");
return retObj.toJSONString();
}
retObj.put("result", JSON.toJSON(mchInfo));
......
......@@ -125,9 +125,9 @@ public class Notify4AliPayController extends Notify4BasePay {
_log.info("{}响应给支付宝结果:{}", logPrefix, PayConstant.RETURN_ALIPAY_VALUE_SUCCESS);
return PayConstant.RETURN_ALIPAY_VALUE_SUCCESS;
}
doNotify(payOrder, response, PayConstant.RETURN_ALIPAY_VALUE_SUCCESS);
doNotify(payOrder);
_log.info("====== 完成接收支付宝支付回调通知 ======");
return null;
return PayConstant.RETURN_ALIPAY_VALUE_SUCCESS;
}
/**
......
......@@ -102,7 +102,7 @@ public class Notify4BasePay {
/**
* 处理支付结果后台服务器通知
*/
public void doNotify(PayOrder payOrder, HttpServletResponse response, String message) {
public void doNotify(PayOrder payOrder) {
_log.info(">>>>>> PAY开始回调通知业务系统 <<<<<<");
// 发起后台通知业务系统
JSONObject object = createNotifyInfo(payOrder);
......@@ -111,7 +111,7 @@ public class Notify4BasePay {
} catch (Exception e) {
_log.error("payOrderId={},sendMessage error.", payOrder != null ? payOrder.getPayOrderId() : "", e);
}
// 响应给支付公司
/*// 响应给支付公司
_log.info("payOrderId={},channelId={},响应支付公司结果:{}", payOrder != null ? payOrder.getPayOrderId() : "", payOrder != null ? payOrder.getChannelId() : "", message);
response.setContentType("text/html");
PrintWriter pw;
......@@ -120,7 +120,7 @@ public class Notify4BasePay {
pw.print(message);
} catch (IOException e) {
_log.error("Pay response write exception.", e);
}
}*/
_log.info(">>>>>> PAY回调通知业务系统完成 <<<<<<");
}
......
package org.xxpay.service.controller;
import com.github.binarywang.wxpay.bean.WxPayOrderNotifyResponse;
import com.github.binarywang.wxpay.bean.result.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.xml.sax.SAXException;
import org.xxpay.common.constant.PayConstant;
import org.xxpay.common.util.MyLog;
import org.xxpay.dal.dao.model.PayChannel;
import org.xxpay.dal.dao.model.PayOrder;
import org.xxpay.service.channel.tencent.common.Configure;
import org.xxpay.service.channel.tencent.common.Signature;
import org.xxpay.service.channel.tencent.common.Util;
import org.xxpay.service.channel.tencent.protocol.notify_protocol.NotifyUnifiedOrderReqData;
import org.xxpay.service.channel.tencent.protocol.notify_protocol.NotifyUnifiedOrderResData;
import org.xxpay.service.channel.wechat.WxPayUtil;
import org.xxpay.service.service.PayChannelService;
import org.xxpay.service.service.PayOrderService;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
......@@ -45,9 +45,6 @@ public class Notify4WxPayController extends Notify4BasePay {
@Autowired
private PayChannelService payChannelService;
@Autowired
private Configure configure;
/**
* 微信支付(统一下单接口)后台通知响应
* @param request
......@@ -65,62 +62,47 @@ public class Notify4WxPayController extends Notify4BasePay {
public String doWxPayRes(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String logPrefix = "【微信支付回调通知】";
_log.info("====== 开始接收微信支付回调通知 ======");
String reqStr = Util.inputStreamToString(request.getInputStream());
_log.info("{}通知请求数据:reqStr={}", logPrefix, reqStr);
if(reqStr == null || "".equals(reqStr.trim())) {
_log.error("{}请求参数为空", logPrefix);
return makeRetData(PayConstant.RETURN_VALUE_FAIL, "请求参数解析错误");
}
NotifyUnifiedOrderReqData reqData = (NotifyUnifiedOrderReqData) Util.getObjectFromXML(reqStr, NotifyUnifiedOrderReqData.class);
if (reqData == null || reqData.getReturn_code() == null) {
_log.error("{}请求数据解析数据异常或return_code为空", logPrefix);
return makeRetData(PayConstant.RETURN_VALUE_FAIL, "请求参数解析错误");
}
Map<String, Object> payContext = new HashMap();
PayOrder payOrder = null;
payContext.put("parameters", reqData);
payContext.put("reqStr", reqStr);
if (PayConstant.RETURN_VALUE_FAIL.equals(reqData.getReturn_code())) {
_log.error("{}请求数据return_code=FAIL", logPrefix);
return makeRetData(PayConstant.RETURN_VALUE_SUCCESS);
} else {
_log.info("{}请求数据return_code=SUCCESS,开始验证请求数据", logPrefix);
//--------------------------------------------------------------------
//收到通知数据的时候得先验证一下数据有没有被第三方篡改,确保安全
//--------------------------------------------------------------------
try {
String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
WxPayService wxPayService = new WxPayServiceImpl();
WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlResult);
Map<String, Object> payContext = new HashMap();
payContext.put("parameters", result);
// 验证业务数据是否正确,验证通过后返回PayOrder和WxPayConfig对象
if(!verifyWxPayParams(payContext)) {
return makeRetData(PayConstant.RETURN_VALUE_FAIL, (String) payContext.get("retMsg"));
return WxPayOrderNotifyResponse.fail((String) payContext.get("retMsg"));
}
_log.info("{}验证请求数据及签名通过", logPrefix);
//获取错误码
String errorCode = reqData.getErr_code();
//获取错误描述
String errorCodeDes = reqData.getErr_code_des();
if (reqData.getResult_code().equals(PayConstant.RETURN_VALUE_SUCCESS)) {
int updatePayOrderRows;
payOrder = (PayOrder) payContext.get("payOrder");
byte payStatus = payOrder.getStatus(); // 0:订单生成,1:支付中,-1:支付失败,2:支付成功,3:业务处理完成,-2:订单过期
if (payStatus != PayConstant.PAY_STATUS_SUCCESS && payStatus != PayConstant.PAY_STATUS_COMPLETE) {
updatePayOrderRows = payOrderService.updateStatus4Success(payOrder.getPayOrderId());
if (updatePayOrderRows != 1) {
_log.error("{}更新支付状态失败,将payOrderId={},更新payStatus={}失败", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS);
return makeRetData(PayConstant.RETURN_VALUE_FAIL, "更新订单失败");
}
_log.error("{}更新支付状态成功,将payOrderId={},更新payStatus={}成功", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS);
payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS);
PayOrder payOrder = (PayOrder) payContext.get("payOrder");
WxPayConfig wxPayConfig = (WxPayConfig) payContext.get("wxPayConfig");
wxPayService.setConfig(wxPayConfig);
// 这里做了签名校验(这里又做了一次xml转换对象,可以考虑优化)
wxPayService.getOrderNotifyResult(xmlResult);
// 处理订单
byte payStatus = payOrder.getStatus(); // 0:订单生成,1:支付中,-1:支付失败,2:支付成功,3:业务处理完成,-2:订单过期
if (payStatus != PayConstant.PAY_STATUS_SUCCESS && payStatus != PayConstant.PAY_STATUS_COMPLETE) {
int updatePayOrderRows = payOrderService.updateStatus4Success(payOrder.getPayOrderId());
if (updatePayOrderRows != 1) {
_log.error("{}更新支付状态失败,将payOrderId={},更新payStatus={}失败", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS);
return WxPayOrderNotifyResponse.fail("处理订单失败");
}
}else{
//出现业务错误
_log.info("{}请求数据result_code=FAIL", logPrefix);
_log.info("err_code:", errorCode);
_log.info("err_code_des:", errorCodeDes);
return makeRetData(PayConstant.RETURN_VALUE_SUCCESS);
_log.error("{}更新支付状态成功,将payOrderId={},更新payStatus={}成功", logPrefix, payOrder.getPayOrderId(), PayConstant.PAY_STATUS_SUCCESS);
payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS);
}
// 业务系统后端通知
doNotify(payOrder);
_log.info("====== 完成接收微信支付回调通知 ======");
return WxPayOrderNotifyResponse.success("处理成功");
} catch (WxPayException e) {
//出现业务错误
_log.error(e, "微信回调结果异常,异常原因");
_log.info("{}请求数据result_code=FAIL", logPrefix);
_log.info("err_code:", e.getErrCode());
_log.info("err_code_des:", e.getErrCodeDes());
return WxPayOrderNotifyResponse.fail(e.getMessage());
} catch (Exception e) {
_log.error(e, "微信回调结果异常,异常原因");
return WxPayOrderNotifyResponse.fail(e.getMessage());
}
doNotify(payOrder, response, makeRetData(PayConstant.RETURN_VALUE_SUCCESS));
return null;
}
/**
......@@ -128,93 +110,19 @@ public class Notify4WxPayController extends Notify4BasePay {
* @return
*/
public boolean verifyWxPayParams(Map<String, Object> payContext) {
NotifyUnifiedOrderReqData params = (NotifyUnifiedOrderReqData)payContext.get("parameters");
String return_code = params.getReturn_code(); // 返回码
String appid = params.getAppid(); // 公众账号ID
String mch_id = params.getMch_id(); // 商户号
String sign = params.getSign(); // 签名
String result_code = params.getResult_code(); // 业务结果
String openid = params.getOpenid(); // 用户标识
String trade_type = params.getTrade_type(); // 交易类型
String bank_type = params.getBank_type(); // 付款银行
String total_fee = params.getTotal_fee(); // 总金额
String cash_fee = params.getCash_fee(); // 现金支付金额
String transaction_id = params.getTransaction_id(); // 微信支付订单号
String out_trade_no = params.getOut_trade_no(); // 商户系统订单号
String time_end = params.getTime_end(); // 支付完成时间
WxPayOrderNotifyResult params = (WxPayOrderNotifyResult)payContext.get("parameters");
if (StringUtils.isEmpty(return_code)) {
_log.error("WXPay parameter return_code is empty. return_code={}", result_code);
payContext.put("retMsg", "return_code is empty");
return false;
}
if (PayConstant.RETURN_VALUE_FAIL.equals(return_code)) {
_log.error("WXPay return_code is FAIL. return_code={}", result_code);
payContext.put("retMsg", "return_code is FAIL");
return false;
}
if (StringUtils.isEmpty(appid)) {
_log.error("WXPay parameter appid is empty. appid={}", appid);
payContext.put("retMsg", "appid is empty");
return false;
}
if (StringUtils.isEmpty(mch_id)) {
_log.error("XWPay parameter mch_id is empty. mch_id={}", mch_id);
payContext.put("retMsg", "mch_id is empty");
return false;
}
if (StringUtils.isEmpty(sign)) {
_log.error("XWPay parameter sign is empty. sign={}", sign);
payContext.put("retMsg", "sign is empty");
return false;
}
if (StringUtils.isEmpty(result_code)) {
_log.error("XWPay parameter result_code is empty. result_code={}", result_code);
payContext.put("retMsg", "result_code is empty");
return false;
}
if (StringUtils.isEmpty(openid)) {
_log.error("XWPay parameter openid is empty. openid={}", openid);
payContext.put("retMsg", "openid is empty");
return false;
}
if (StringUtils.isEmpty(trade_type)) {
_log.error("XWPay parameter trade_type is empty. trade_type={}", trade_type);
payContext.put("retMsg", "trade_type is empty");
return false;
}
if (StringUtils.isEmpty(bank_type)) {
_log.error("XWPay parameter bank_type is empty. bank_type={}", bank_type);
payContext.put("retMsg", "bank_type is empty");
return false;
}
if (StringUtils.isEmpty(total_fee)) {
_log.error("XWPay parameter total_fee is empty. total_fee={}", total_fee);
payContext.put("retMsg", "total_fee is empty");
return false;
}
if (StringUtils.isEmpty(cash_fee)) {
_log.error("XWPay parameter cash_fee is empty. cash_fee={}", cash_fee);
payContext.put("retMsg", "cash_fee is empty");
return false;
}
if (StringUtils.isEmpty(transaction_id)) {
_log.error("XWPay parameter transaction_id is empty. transaction_id={}", transaction_id);
payContext.put("retMsg", "transaction_id is empty");
return false;
}
if (StringUtils.isEmpty(out_trade_no)) {
_log.error("XWPay parameter out_trade_no is empty. out_trade_no={}", out_trade_no);
payContext.put("retMsg", "out_trade_no is empty");
return false;
}
if (StringUtils.isEmpty(time_end)) {
_log.error("XWPay parameter time_end is empty. time_end={}", time_end);
payContext.put("retMsg", "time_end is empty");
//校验结果是否成功
if (!PayConstant.RETURN_VALUE_SUCCESS.equalsIgnoreCase(params.getResultCode())
|| !PayConstant.RETURN_VALUE_SUCCESS.equalsIgnoreCase(params.getResultCode())) {
_log.error("returnCode={},resultCode={},errCode={},errCodeDes={}", params.getReturnCode(), params.getResultCode(), params.getErrCode(), params.getErrCodeDes());
payContext.put("retMsg", "notify data failed");
return false;
}
Integer total_fee = params.getTotalFee(); // 总金额
String out_trade_no = params.getOutTradeNo(); // 商户系统订单号
// 查询payOrder记录
String payOrderId = out_trade_no;
PayOrder payOrder = payOrderService.selectPayOrder(payOrderId);
......@@ -229,47 +137,23 @@ public class Notify4WxPayController extends Notify4BasePay {
String channelId = payOrder.getChannelId();
PayChannel payChannel = payChannelService.selectPayChannel(channelId, mchId);
if(payChannel == null) {
_log.error("Can't found payChannel form db. mchId={} channelId={}, ", payOrderId, mch_id, channelId);
_log.error("Can't found payChannel form db. mchId={} channelId={}, ", payOrderId, mchId, channelId);
payContext.put("retMsg", "Can't found payChannel");
return false;
}
// 验证微信支付结果签名
try {
if(!Signature.checkIsSignValidFromResponseString((String)payContext.get("reqStr"), configure.init(payChannel.getParam()).getKey())) {
_log.error("WXPay parameter sign verified failed. sign={}", sign);
payContext.put("retMsg", "sign is verified failed");
return false;
}
} catch (ParserConfigurationException e) {
_log.error(e, "");
} catch (IOException e) {
_log.error(e, "");
} catch (SAXException e) {
_log.error(e, "");
}
payContext.put("wxPayConfig", WxPayUtil.getWxPayConfig(payChannel.getParam()));
// 核对金额
long wxPayAmt = new BigDecimal(total_fee).longValue();
long dbPayAmt = payOrder.getAmount().longValue();
if (dbPayAmt != wxPayAmt) {
_log.error("db payOrder record payPrice not equals total_fee. total_fee={},payOrderId={}", total_fee, payOrderId);
payContext.put("retMsg", "");
payContext.put("retMsg", "total_fee is not the same");
return false;
}
payContext.put("payOrder", payOrder);
return true;
}
String makeRetData(String retCode, String retMsg) {
NotifyUnifiedOrderResData data = new NotifyUnifiedOrderResData();
data.setReturn_code(retCode);
data.setReturn_msg(retMsg);
return Util.objectToXML(data);
}
String makeRetData(String retCode) {
return makeRetData(retCode, "");
}
}
......@@ -2,8 +2,14 @@ package org.xxpay.service.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.github.binarywang.wxpay.util.SignUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
......@@ -11,21 +17,17 @@ import org.xxpay.common.constant.PayConstant;
import org.xxpay.common.constant.PayEnum;
import org.xxpay.common.util.MyBase64;
import org.xxpay.common.util.MyLog;
import org.xxpay.common.util.PayDigestUtil;
import org.xxpay.common.util.XXPayUtil;
import org.xxpay.dal.dao.model.MchInfo;
import org.xxpay.dal.dao.model.PayChannel;
import org.xxpay.dal.dao.model.PayOrder;
import org.xxpay.service.channel.tencent.common.Configure;
import org.xxpay.service.channel.tencent.common.Signature;
import org.xxpay.service.channel.tencent.common.Util;
import org.xxpay.service.channel.tencent.protocol.order_protocol.UnifiedOrderReqData;
import org.xxpay.service.channel.tencent.protocol.order_protocol.UnifiedOrderResData;
import org.xxpay.service.channel.tencent.service.UnifiedOrderService;
import org.xxpay.service.channel.wechat.WxPayProperties;
import org.xxpay.service.channel.wechat.WxPayUtil;
import org.xxpay.service.service.MchInfoService;
import org.xxpay.service.service.PayChannelService;
import org.xxpay.service.service.PayOrderService;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
......@@ -37,13 +39,10 @@ import java.util.Map;
* @Copyright: www.xxpay.org
*/
@RestController
public class PayChannel4WxController {
public class PayChannel4WxController{
private final MyLog _log = MyLog.getLog(PayChannel4WxController.class);
@Autowired
private DiscoveryClient client;
@Autowired
private PayOrderService payOrderService;
......@@ -53,11 +52,8 @@ public class PayChannel4WxController {
@Autowired
private MchInfoService mchInfoService;
@Autowired
private UnifiedOrderService unifiedOrderService;
@Autowired
private Configure configure;
@Resource
private WxPayProperties wxPayProperties;
/**
* 发起微信支付(统一下单)
......@@ -66,136 +62,133 @@ public class PayChannel4WxController {
*/
@RequestMapping(value = "/pay/channel/wx")
public String doWxPayReq(@RequestParam String jsonParam) {
// TODO 参数校验
JSONObject paramObj = JSON.parseObject(new String(MyBase64.decode(jsonParam)));
PayOrder payOrder = paramObj.getObject("payOrder", PayOrder.class);
String tradeType = paramObj.getString("tradeType");
String logPrefix = "【微信支付统一下单】";
String mchId = payOrder.getMchId();
String channelId = payOrder.getChannelId();
MchInfo mchInfo = mchInfoService.selectMchInfo(mchId);
String resKey = mchInfo == null ? "" : mchInfo.getResKey();
if("".equals(resKey)) return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "", PayConstant.RETURN_VALUE_FAIL, PayEnum.ERR_0001));
PayChannel payChannel = payChannelService.selectPayChannel(channelId, mchId);
configure.init(payChannel.getParam());
String payOrderId = payOrder.getPayOrderId();
UnifiedOrderReqData unifiedOrderReqData = buildUnifiedOrderReqData(tradeType, payOrder, configure);
try {
_log.info("{}发起支付请求,请求数据:{}", logPrefix, unifiedOrderReqData.toMap());
// 设置CRT
unifiedOrderService.init(configure);
String responseStr = unifiedOrderService.request(unifiedOrderReqData);
// 打印回包数据
_log.info("{}发起支付请求,返回数据:{}", logPrefix, responseStr);
// 转换为返回数据类型
UnifiedOrderResData unifiedOrderResData = (UnifiedOrderResData) Util.getObjectFromXML(responseStr, UnifiedOrderResData.class);
if (unifiedOrderResData == null || unifiedOrderResData.getReturn_code() == null) {
_log.error("{}【支付失败】支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问", logPrefix);
return XXPayUtil.makeRetData(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_FAIL, PayEnum.ERR_0111), resKey);
}
if (unifiedOrderResData.getReturn_code().equals("FAIL")) {
//注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
_log.error("{}【支付失败】支付API系统返回失败,请检测Post给API的数据是否规范合法", logPrefix);
return XXPayUtil.makeRetData(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_FAIL, PayEnum.ERR_0111), resKey);
} else {
_log.info("{}支付API系统成功返回数据", logPrefix);
//--------------------------------------------------------------------
//收到API的返回数据的时候得先验证一下数据有没有被第三方篡改,确保安全
//--------------------------------------------------------------------
if (!Signature.checkIsSignValidFromResponseString(responseStr, configure.getKey())) {
_log.error("{}【支付失败】支付请求API返回的数据签名验证失败,有可能数据被篡改了", logPrefix);
return XXPayUtil.makeRetData(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_FAIL, PayEnum.ERR_0111), resKey);
}
_log.info("{}支付请求返回数据验签通过", logPrefix);
//获取错误码
String errorCode = unifiedOrderResData.getErr_code();
//获取错误描述
String errorCodeDes = unifiedOrderResData.getErr_code_des();
if (unifiedOrderResData.getResult_code().equals("SUCCESS")) {
_log.info("{} >>> 下单成功", logPrefix);
Map<String, Object> map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null);
map.put("payOrderId", payOrderId);
map.put("prepayId", unifiedOrderResData.getPrepay_id());
int result = payOrderService.updateStatus4Ing(payOrderId, unifiedOrderResData.getPrepay_id());
_log.info("更新第三方支付订单号:payOrderId={},prepayId={},result={}", payOrderId, unifiedOrderResData.getPrepay_id(), result);
//map.put("rechargeId", String.valueOf(rechargeId));
if(tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_NATIVE)) {
map.put("codeUrl", unifiedOrderResData.getCode_url());
}else if (tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_APP)) {
try{
JSONObject paramObj = JSON.parseObject(new String(MyBase64.decode(jsonParam)));
PayOrder payOrder = paramObj.getObject("payOrder", PayOrder.class);
String tradeType = paramObj.getString("tradeType");
String logPrefix = "【微信支付统一下单】";
String mchId = payOrder.getMchId();
String channelId = payOrder.getChannelId();
MchInfo mchInfo = mchInfoService.selectMchInfo(mchId);
String resKey = mchInfo == null ? "" : mchInfo.getResKey();
if("".equals(resKey)) return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "", PayConstant.RETURN_VALUE_FAIL, PayEnum.ERR_0001));
PayChannel payChannel = payChannelService.selectPayChannel(channelId, mchId);
WxPayConfig wxPayConfig = WxPayUtil.getWxPayConfig(payChannel.getParam(), tradeType, wxPayProperties.getCertRootPath(), wxPayProperties.getNotifyUrl());
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(wxPayConfig);
WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = buildUnifiedOrderRequest(payOrder, wxPayConfig);
String payOrderId = payOrder.getPayOrderId();
WxPayUnifiedOrderResult wxPayUnifiedOrderResult;
try {
wxPayUnifiedOrderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
_log.info("{} >>> 下单成功", logPrefix);
Map<String, Object> map = XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null);
map.put("payOrderId", payOrderId);
map.put("prepayId", wxPayUnifiedOrderResult.getPrepayId());
int result = payOrderService.updateStatus4Ing(payOrderId, wxPayUnifiedOrderResult.getPrepayId());
_log.info("更新第三方支付订单号:payOrderId={},prepayId={},result={}", payOrderId, wxPayUnifiedOrderResult.getPrepayId(), result);
switch (tradeType) {
case PayConstant.WxConstant.TRADE_TYPE_NATIVE : {
map.put("codeUrl", wxPayUnifiedOrderResult.getCodeURL()); // 二维码支付链接
break;
}
case PayConstant.WxConstant.TRADE_TYPE_APP : {
Map<String, Object> m = new HashMap<>();
m.put("appid", unifiedOrderReqData.getAppid());
m.put("partnerid", unifiedOrderReqData.getMch_id());
m.put("prepayid", unifiedOrderResData.getPrepay_id());
m.put("appid", wxPayUnifiedOrderResult.getAppid());
m.put("partnerid", wxPayUnifiedOrderResult.getMchId());
m.put("prepayid", wxPayUnifiedOrderResult.getPrepayId());
m.put("package", "Sign=WXPay");
m.put("noncestr", unifiedOrderReqData.getNonce_str());
m.put("noncestr", wxPayUnifiedOrderResult.getNonceStr());
m.put("timestamp", System.currentTimeMillis()/1000);
String wxSign = Signature.getSign(m, configure.getKey());
String wxSign = SignUtils.createSign(m, wxPayConfig.getMchKey());
m.put("sign", wxSign);
map.put("payParams", m);
map.put("payPrice", payOrder.getAmount());
}else if(tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_JSPAI)) {
break;
}
case PayConstant.WxConstant.TRADE_TYPE_JSPAI : {
Map<String, Object> m = new HashMap<>();
m.put("appId", unifiedOrderReqData.getAppid());
m.put("appId", wxPayConfig.getAppId());
m.put("timeStamp", System.currentTimeMillis()/1000);
m.put("nonceStr", unifiedOrderReqData.getNonce_str());
m.put("package", "prepay_id=" + unifiedOrderResData.getPrepay_id());
m.put("nonceStr", wxPayUnifiedOrderResult.getNonceStr());
m.put("package", "prepay_id=" + wxPayUnifiedOrderResult.getPrepayId());
m.put("signType", "MD5");
String wxSign = Signature.getSign(m, configure.getKey());
String wxSign = SignUtils.createSign(m, wxPayConfig.getMchKey());
m.put("paySign", wxSign);
map.put("payParams", m);
map.put("payPrice", payOrder.getAmount());
break;
}
case PayConstant.WxConstant.TRADE_TYPE_MWEB : {
Map<String, Object> m = new HashMap<>();
map.put("payUrl", wxPayUnifiedOrderResult.getMwebUrl()); // h5支付链接地址
map.put("payPrice", payOrder.getAmount());
break;
}
return XXPayUtil.makeRetData(map, resKey);
}else{
//出现业务错误
_log.info("{}下单返回失败", logPrefix);
_log.info("err_code:{}", errorCode);
_log.info("err_code_des:{}", errorCodeDes);
return XXPayUtil.makeRetData(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_FAIL, "0111", "调用微信支付失败," + errorCode + ":" + errorCodeDes), resKey);
}
return XXPayUtil.makeRetData(map, resKey);
} catch (WxPayException e) {
_log.error(e, "下单失败");
//出现业务错误
_log.info("{}下单返回失败", logPrefix);
_log.info("err_code:{}", e.getErrCode());
_log.info("err_code_des:{}", e.getErrCodeDes());
return XXPayUtil.makeRetData(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_FAIL, "0111", "调用微信支付失败," + e.getErrCode() + ":" + e.getErrCodeDes()), resKey);
}
} catch (Exception e) {
_log.error(e, "请求异常,%s", e.getMessage());
}catch (Exception e) {
_log.error(e, "微信支付统一下单异常");
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "", PayConstant.RETURN_VALUE_FAIL, PayEnum.ERR_0001));
}
_log.info("###### 商户统一下单处理完成 ######");
return XXPayUtil.makeRetData(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_SUCCESS, "", PayConstant.RETURN_VALUE_SUCCESS, null), resKey);
}
/**
* 构建统一下单请求数据
* @param tradeType
* 构建微信统一下单请求数据
* @param payOrder
* @param configure
* @param wxPayConfig
* @return
*/
UnifiedOrderReqData buildUnifiedOrderReqData(String tradeType, PayOrder payOrder, Configure configure) {
WxPayUnifiedOrderRequest buildUnifiedOrderRequest(PayOrder payOrder, WxPayConfig wxPayConfig) {
String tradeType = wxPayConfig.getTradeType();
String payOrderId = payOrder.getPayOrderId();
String payPrice = payOrder.getAmount()+"";
Integer totalFee = payOrder.getAmount().intValue();// 支付金额,单位分
String deviceInfo = payOrder.getDevice();
String body = payOrder.getBody();
String detail = null;
String attach = null;
String outTradeNo = payOrderId;
String feeType = "CNY";
String totalFee = payPrice; // 支付金额,单位分
String spBillCreateIP = payOrder.getClientIp();
String timeStart = null;
String timeExpire = null;
String goodsTag = null;
String notifyUrl = configure.getNotify_url();
String notifyUrl = wxPayConfig.getNotifyUrl();
String productId = null;
if(tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_NATIVE)) productId = JSON.parseObject(payOrder.getExtra()).getString("productId");
String limitPay = null;
String openId = null;
if(tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_JSPAI)) openId = JSON.parseObject(payOrder.getExtra()).getString("openId");
UnifiedOrderReqData unifiedOrderReqData = new UnifiedOrderReqData(configure, deviceInfo, body, detail, attach,
outTradeNo, feeType, totalFee, spBillCreateIP, timeStart, timeExpire, goodsTag, notifyUrl,
tradeType, productId, limitPay, openId);
return unifiedOrderReqData;
String sceneInfo = null;
if(tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_MWEB)) sceneInfo = JSON.parseObject(payOrder.getExtra()).getString("sceneInfo");
// 微信统一下单请求对象
WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
request.setDeviceInfo(deviceInfo);
request.setBody(body);
request.setDetail(detail);
request.setAttach(attach);
request.setOutTradeNo(outTradeNo);
request.setFeeType(feeType);
request.setTotalFee(totalFee);
request.setSpbillCreateIp(spBillCreateIP);
request.setTimeStart(timeStart);
request.setTimeExpire(timeExpire);
request.setGoodsTag(goodsTag);
request.setNotifyURL(notifyUrl);
request.setTradeType(tradeType);
request.setProductId(productId);
request.setLimitPay(limitPay);
request.setOpenid(openId);
request.setSceneInfo(sceneInfo);
return request;
}
}
......@@ -36,18 +36,19 @@ public class PayChannelServiceController {
retObj.put("code", "0000");
if(StringUtils.isBlank(jsonParam)) {
retObj.put("code", "0001"); // 参数错误
retObj.put("msg", "缺少参数");
return retObj.toJSONString();
}
JSONObject paramObj = JSON.parseObject(new String(MyBase64.decode(jsonParam)));
String channelId = paramObj.getString("channelId");
String mchId = paramObj.getString("mchId");
PayChannel payChannel = payChannelService.selectPayChannel(channelId, mchId);
if(payChannel == null) {
retObj.put("result", "");
}else {
retObj.put("result", JSON.toJSON(payChannel));
retObj.put("code", "0002");
retObj.put("msg", "数据对象不存在");
return retObj.toJSONString();
}
retObj.put("result", JSON.toJSON(payChannel));
_log.info("selectPayChannel >> {}", retObj);
return retObj.toJSONString();
}
......
......@@ -2,15 +2,14 @@ package org.xxpay.service.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.xxpay.common.util.MyBase64;
import org.xxpay.common.util.MyLog;
import org.xxpay.dal.dao.model.PayOrder;
import org.xxpay.service.channel.tencent.service.UnifiedOrderService;
import org.xxpay.service.service.PayOrderService;
/**
......@@ -25,22 +24,27 @@ public class PayOrderServiceController {
private final MyLog _log = MyLog.getLog(PayOrderServiceController.class);
@Autowired
private DiscoveryClient client;
@Autowired
private PayOrderService payOrderService;
@Autowired
UnifiedOrderService unifiedOrderService;
@RequestMapping(value = "/pay/create")
public String createPayOrder(@RequestParam String jsonParam) {
// TODO 参数校验
PayOrder payOrder = JSON.parseObject(new String(MyBase64.decode(jsonParam)), PayOrder.class);
int result = payOrderService.createPayOrder(payOrder);
_log.info("接收创建支付订单请求,jsonParam={}", jsonParam);
JSONObject retObj = new JSONObject();
retObj.put("result", result);
retObj.put("code", "0000");
if(StringUtils.isBlank(jsonParam)) {
retObj.put("code", "0001");
retObj.put("msg", "缺少参数");
return retObj.toJSONString();
}
try {
PayOrder payOrder = JSON.parseObject(new String(MyBase64.decode(jsonParam)), PayOrder.class);
int result = payOrderService.createPayOrder(payOrder);
retObj.put("result", result);
}catch (Exception e) {
retObj.put("code", "9999"); // 系统错误
retObj.put("msg", "系统错误");
}
return retObj.toJSONString();
}
......
......@@ -57,23 +57,28 @@ public class PayOrderController {
*/
@RequestMapping(value = "/pay/create_order")
public String payOrder(@RequestParam String params) {
ServiceInstance instance = client.getLocalServiceInstance();
_log.info("###### 开始接收商户统一下单请求 ######");
_log.info("/pay_order, host:" + instance.getHost() + ", service_id:" + instance.getServiceId() + ", params:" + params);
String logPrefix = "【商户统一下单】";
ServiceInstance instance = client.getLocalServiceInstance();
_log.info("{}/pay/create_order, host:{}, service_id:{}, params:{}", logPrefix, instance.getHost(), instance.getServiceId(), params);
JSONObject po = JSONObject.parseObject(params);
JSONObject payOrder = null;
try {
// 验证参数有效性
Object object = validateParams(po);
if (object instanceof String) {
// 参数错误
_log.info("请求参数错误:{}", object);
_log.info("{}参数校验不通过:{}", logPrefix, object);
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, object.toString(), null, null));
}
if (object instanceof JSONObject) payOrder = (JSONObject) object;
if(payOrder == null) return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "支付中心下单失败", null, null));
String result = payOrderServiceClient.createPayOrder(payOrder.toJSONString());
_log.info("插入支付订单数据,结果:{}", result);
_log.info("{}创建支付订单,结果:{}", logPrefix, result);
if(StringUtils.isEmpty(result)) {
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "创建支付订单失败", null, null));
}
JSONObject resObj = JSON.parseObject(result);
if(resObj == null || !"1".equals(resObj.getString("result"))) return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "创建支付订单失败", null, null));
String channelId = payOrder.getString("channelId");
switch (channelId) {
case PayConstant.PAY_CHANNEL_WX_APP :
......@@ -82,6 +87,8 @@ public class PayOrderController {
return payOrderServiceClient.doWxPayReq(getJsonParam(new String[]{"tradeType", "payOrder"}, new Object[]{PayConstant.WxConstant.TRADE_TYPE_JSPAI, payOrder}));
case PayConstant.PAY_CHANNEL_WX_NATIVE :
return payOrderServiceClient.doWxPayReq(getJsonParam(new String[]{"tradeType", "payOrder"}, new Object[]{PayConstant.WxConstant.TRADE_TYPE_NATIVE, payOrder}));
case PayConstant.PAY_CHANNEL_WX_MWEB :
return payOrderServiceClient.doWxPayReq(getJsonParam(new String[]{"tradeType", "payOrder"}, new Object[]{PayConstant.WxConstant.TRADE_TYPE_MWEB, payOrder}));
case PayConstant.PAY_CHANNEL_ALIPAY_MOBILE :
return payOrderServiceClient.doAliPayMobileReq(getJsonParam("payOrder", payOrder));
case PayConstant.PAY_CHANNEL_ALIPAY_PC :
......@@ -89,13 +96,12 @@ public class PayOrderController {
case PayConstant.PAY_CHANNEL_ALIPAY_WAP :
return payOrderServiceClient.doAliPayWapReq(getJsonParam("payOrder", payOrder));
default:
break;
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "不支持的支付渠道类型[channelId="+channelId+"]", null, null));
}
}catch (Exception e) {
_log.error(e, "");
return XXPayUtil.makeRetFail(XXPayUtil.makeRetMap(PayConstant.RETURN_VALUE_FAIL, "支付中心系统异常", null, null));
}
return null;
}
/**
......@@ -177,6 +183,21 @@ public class PayOrderController {
errorMessage = "request params[extra.productId] error.";
return errorMessage;
}
}else if(PayConstant.PAY_CHANNEL_WX_MWEB.equalsIgnoreCase(channelId)) {
if(StringUtils.isEmpty(extra)) {
errorMessage = "request params[extra] error.";
return errorMessage;
}
JSONObject extraObject = JSON.parseObject(extra);
String productId = extraObject.getString("sceneInfo");
if(StringUtils.isBlank(productId)) {
errorMessage = "request params[extra.sceneInfo] error.";
return errorMessage;
}
if(StringUtils.isBlank(clientIp)) {
errorMessage = "request params[clientIp] error.";
return errorMessage;
}
}
// 签名信息
......@@ -186,15 +207,23 @@ public class PayOrderController {
}
// 查询商户信息
JSONObject mchInfo;
String retStr = mchInfoServiceClient.selectMchInfo(getJsonParam("mchId", mchId));
JSONObject retObj = JSON.parseObject(retStr);
JSONObject mchInfo = retObj.getJSONObject("result");
if (mchInfo == null) {
if("0000".equals(retObj.getString("code"))) {
mchInfo = retObj.getJSONObject("result");
if (mchInfo == null) {
errorMessage = "Can't found mchInfo[mchId="+mchId+"] record in db.";
return errorMessage;
}
if(mchInfo.getByte("state") != 1) {
errorMessage = "mchInfo not available [mchId="+mchId+"] record in db.";
return errorMessage;
}
}else {
errorMessage = "Can't found mchInfo[mchId="+mchId+"] record in db.";
return errorMessage;
}
if(mchInfo.getByte("state") != 1) {
errorMessage = "mchInfo not available [mchId="+mchId+"] record in db.";
_log.info("查询商户没有正常返回数据,code={},msg={}", retObj.getString("code"), retObj.getString("msg"));
return errorMessage;
}
......@@ -205,17 +234,25 @@ public class PayOrderController {
}
// 查询商户对应的支付渠道
JSONObject payChannel;
retStr = payChannelServiceClient.selectPayChannel(getJsonParam(new String[]{"channelId", "mchId"}, new String[]{channelId, mchId}));
retObj = JSON.parseObject(retStr);
JSONObject payChannel = retObj.getJSONObject("result");
if(payChannel == null) {
if("0000".equals(retObj.getString("code"))) {
payChannel = JSON.parseObject(retObj.getString("result"));
if(payChannel == null) {
errorMessage = "Can't found payChannel[channelId="+channelId+",mchId="+mchId+"] record in db.";
return errorMessage;
}
if(payChannel.getByte("state") != 1) {
errorMessage = "channel not available [channelId="+channelId+",mchId="+mchId+"]";
return errorMessage;
}
}else {
errorMessage = "Can't found payChannel[channelId="+channelId+",mchId="+mchId+"] record in db.";
_log.info("查询渠道没有正常返回数据,code={},msg={}", retObj.getString("code"), retObj.getString("msg"));
return errorMessage;
}
if(payChannel.getByte("state") != 1) {
errorMessage = "channel not available [channelId="+channelId+",mchId="+mchId+"]";
return errorMessage;
}
// 验证签名数据
boolean verifyFlag = XXPayUtil.verifyPaySign(params, reqKey);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment