此前,已设计过多应用多平模块的基础开篇。
本篇,准备对接微信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业已完成开发。后期会逐渐完善更多三方支付功能。