此前,已設計過多應用多平模塊的基礎開篇。
本篇,準備對接微信V2JsApi支付基礎模塊,并基于此模塊實現具體的業務功能邏輯。
開發思路如下
微信下單網絡請求配置
定義微信統一下單網絡請求配置,提供實現類進行調用獲取下單數據。
package com.threeox.biz.order.config;
import com.threeox.biz.order.entity.wx.WxOrderInfo;
import com.threeox.drivenlibrary.engine.annotation.base.ParamConfig;
import com.threeox.drivenlibrary.engine.annotation.request.NETWorkRequestConfig;
import com.threeox.drivenlibrary.engine.annotation.request.RequestConfig;
import com.threeox.drivenlibrary.engine.annotation.scan.RequestScanConfig;
import com.threeox.drivenlibrary.enums.dictionary.DataType;
import com.threeox.drivenlibrary.enums.dictionary.RequestMethod;
/**
* 支付請求配置
*
* @author 趙屈犇
* @version 1.0
* @date 創建時間: 2022/4/23 16:54
*/
@RequestScanConfig
public class PayRequestConfig {
/**
* 微信統一下單
*/
@RequestConfig(requestName = "統一下單", netWorkConfig = @NetWorkRequestConfig(rootUrl = "https://api.mch.weixin.qq.com/", serverUrl = "pay/unifiedorder",
parsingRespDataType = DataType.XML, responseClass = WxOrderInfo.class, methodType = RequestMethod.POST_XML, body = {
@ParamConfig(paramCode = "Appid", valueCode = "appid"),
@ParamConfig(paramCode = "mch_id", valueCode = "mch_id"),
@ParamConfig(paramCode = "nonce_str", valueCode = "nonce_str"),
@ParamConfig(paramCode = "sign", valueCode = "sign"),
@ParamConfig(paramCode = "sign_type", valueCode = "sign_type"),
@ParamConfig(paramCode = "body", valueCode = "body"),
@ParamConfig(paramCode = "detail", valueCode = "detail"),
@ParamConfig(paramCode = "out_trade_no", valueCode = "out_trade_no"),
@ParamConfig(paramCode = "fee_type", valueCode = "fee_type"),
@ParamConfig(paramCode = "openid", valueCode = "openid"),
@ParamConfig(paramCode = "total_fee", valueCode = "total_fee"),
@ParamConfig(paramCode = "notify_url", valueCode = "notify_url"),
@ParamConfig(paramCode = "trade_type", valueCode = "trade_type"),
@ParamConfig(paramCode = "product_id", valueCode = "product_id"),
@ParamConfig(paramCode = "spbill_create_ip", valueCode = "spbill_create_ip"),
}))
public static final String WX_API_PLACE_ORDER = "COM.THREEOX.BIZ.ORDER.CONFIG.PAYREQUESTCONFIG.WX_API_PLACE_ORDER";
}
支付方式工廠實現
此工廠繼承基礎實現類,并實現下單子類函數。
- 調用微信統一下單接口
- 處理下單返回數據,并返回至前端調用
package com.threeox.biz.order.factory.impl.wx;
import com.alibaba.fastjson.JSONObject;
import com.threeox.biz.order.config.OrderDictConstants;
import com.threeox.biz.order.config.PayRequestConfig;
import com.threeox.biz.order.config.extend.PaymentExtend;
import com.threeox.biz.order.entity.OrderInfo;
import com.threeox.biz.order.entity.wx.WxOrderInfo;
import com.threeox.biz.order.enums.PayWay;
import com.threeox.biz.order.factory.impl.base.BasePaymentFactory;
import com.threeox.biz.order.utils.PayUtils;
import com.threeox.biz.order.utils.wx.WXPayConstants;
import com.threeox.biz.order.utils.wx.WXPayUtil;
import com.threeox.drivenlibrary.engine.constants.config.DrivenModelDBConstants;
import com.threeox.drivenlibrary.engine.entity.driven.config.OpenPlatformConfigMessage;
import com.threeox.drivenlibrary.engine.request.execute.ExecuteRequestFactory;
import com.threeox.drivenlibrary.enums.ResponseResult;
import com.threeox.drivenlibrary.exception.ResponseException;
import com.threeox.drivenlibrary.manage.entity.UserInfoMessage;
import com.threeox.drivenlibrary.manage.factory.user.UserFactory;
import com.threeox.httplibrary.entity.HttpResponseInfo;
import com.threeox.utillibrary.date.TimeUtils;
import com.threeox.utillibrary.JAVA.IDGenerate;
import java.math.BigDecimal;
/**
* 微信JSApi支付
*
* @author 趙屈犇
* @version 1.0
* @date 創建時間: 2022/4/23 17:38
*/
@PaymentExtend(OrderDictConstants.PayWay.WX_JS_API_V2)
public class WxJsApiV2PaymentFactory extends BasePaymentFactory {
@Override
protected JSONObject placeOrder(OrderInfo orderInfo, OpenPlatformConfigMessage openPlatform) throws Exception {
UserInfoMessage userInfo = UserFactory.builder().getUser();
JSONObject params = new JSONObject();
params.put("fee_type", "CNY");
params.put("openid", userInfo.getWxOpenId());
params.put("body", orderInfo.getOrderName());
params.put("nonce_str", IDGenerate.getUUId());
params.put("appid", openPlatform.getWxAppId());
params.put("mch_id", openPlatform.getWxMchId());
params.put("detail", orderInfo.getBizSnapshot());
params.put("product_id", orderInfo.getOrderId());
params.put("out_trade_no", orderInfo.getOrderNum());
params.put("trade_type", PayWay.WX_JS_API_V2.getCode());
params.put("spbill_create_ip", orderInfo.getIpAddress());
params.put("sign_type", WXPayConstants.SignType.MD5.name());
params.put("total_fee", orderInfo.getPayMoney().multiply(new BigDecimal(100)).toBigInteger());
params.put("notify_url", PayUtils.getNotifyUrl(PayWay.WX_JS_API_V2));
params.put("sign", WXPayUtil.generateSignature(params, openPlatform.getWxMchSecret(), WXPayConstants.SignType.MD5));
// 執行請求
HttpResponseInfo responseInfo = ExecuteRequestFactory.builder().initConfig(DrivenModelDBConstants.DRIVEN_MANAGE_MODEL_DB_CODE, PayRequestConfig.WX_API_PLACE_ORDER)
.requestParam(params).execute();
if (responseInfo != null && responseInfo.isSuccess()) {
WxOrderInfo wxOrderInfo = responseInfo.getResult();
if ("SUCCESS".equals(wxOrderInfo.getReturn_code()) && wxOrderInfo.getReturn_code().equals(wxOrderInfo.getResult_code())) {
JSONObject payResult = new JSONObject();
payResult.put("appId", openPlatform.getWxAppId());
payResult.put("nonceStr", IDGenerate.getUUId());
payResult.put("package", "prepay_id=" + wxOrderInfo.getPrepay_id());
payResult.put("timeStamp", String.valueOf(TimeUtils.getNowTimeMills()));
payResult.put("signType", WXPayConstants.SignType.MD5.name());
payResult.put("paySign", WXPayUtil.generateSignature(payResult, openPlatform.getWxMchSecret(), WXPayConstants.SignType.MD5));
return payResult;
}
}
throw new ResponseException(ResponseResult.PLACE_ORDER_FAILURE);
}
}
回調接口
此接口繼承基礎回調實現類,并實現是否支付成功函數。
并,在其內部拼接簽名驗證是否正確。從而保證錯誤回調請求。
package com.threeox.biz.order.api.notify;
import com.alibaba.fastjson.JSONObject;
import com.threeox.biz.order.api.notify.base.BasePayNotifyExtend;
import com.threeox.biz.order.config.OrderResponseConfig;
import com.threeox.biz.order.entity.OrderInfo;
import com.threeox.biz.order.entity.wx.WxNotifyInfo;
import com.threeox.biz.order.utils.wx.WXPayConstants;
import com.threeox.biz.order.utils.wx.WXPayUtil;
import com.threeox.drivenlibrary.engine.annotation.api.Api;
import com.threeox.drivenlibrary.engine.entity.driven.config.OpenPlatformConfigMessage;
import com.threeox.drivenlibrary.enums.dictionary.ContentType;
import com.threeox.drivenlibrary.enums.dictionary.ResponseType;
/**
* 微信JSApi支付回調通知
*
* @author 趙屈犇
* @version 1.0
* @date 創建時間: 2022/4/28 23:38
*/
@Api(apiUrl = "notify", apiName = "支付回調", moduleUrl = "pay/wxJsApi/v2", isVerifyToken = false, isVerifyLogin = false,
isEncryptedResult = false, isDecryptParams = false, isStartAuth = false, requestContentType = ContentType.TEXT_XML,
responseCode = OrderResponseConfig.WX_NOTIFY_RESPONSE, responseType = ResponseType.XML
)
public class WxJsV2PayNotifyExtend extends BasePayNotifyExtend<WxNotifyInfo> {
@Override
protected boolean isPaySuccess(OrderInfo orderInfo, OpenPlatformConfigMessage openPlatform) throws Exception {
String returnCode = getRequestParams().getReturn_code();
if ("SUCCESS".equals(returnCode)) {
//驗證簽名是否正確
// 回調驗簽時需要去除sign和空值參數
JSONObject validParams = WXPayUtil.paraFilter(getParams());
// 拼裝生成服務器端驗證的簽名
String sign = WXPayUtil.generateSignature(validParams, openPlatform.getWxMchSecret(), WXPayConstants.SignType.MD5);
// 因為微信回調會有八次之多,所以當第一次回調成功了,那么我們就不再執行邏輯了
// 根據微信官網的介紹,此處不僅對回調的參數進行驗簽,還需要對返回的金額與系統訂單的金額進行比對等
if (sign.equals(getParamValue("sign"))) {
return true;
}
}
return false;
}
}
至此的話,微信V2JsApi業已完成開發。后期會逐漸完善更多三方支付功能。