您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

多应用多平台支付模块-微信V2JsApi支付

时间:2022-09-10 15:54:15  来源:今日头条  作者:三牛爱编程

此前,已设计过多应用多平模块的基础开篇。

本篇,准备对接微信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业已完成开发。后期会逐渐完善更多三方支付功能。



Tags:支付模块   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
多应用多平台支付模块-微信V2JsApi支付
此前,已设计过多应用多平模块的基础开篇。本篇,准备对接微信V2JsApi支付基础模块,并基于此模块实现具体的业务功能逻辑。开发思路如下 微信下单网络请求配置定义微信统一下单网...【详细内容】
2022-09-10  Search: 支付模块  点击:(336)  评论:(0)  加入收藏
▌简易百科推荐
Netflix 是如何管理 2.38 亿会员的
作者 | Surabhi Diwan译者 | 明知山策划 | TinaNetflix 高级软件工程师 Surabhi Diwan 在 2023 年旧金山 QCon 大会上发表了题为管理 Netflix 的 2.38 亿会员 的演讲。她在...【详细内容】
2024-04-08    InfoQ  Tags:Netflix   点击:(2)  评论:(0)  加入收藏
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(7)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(13)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(9)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(11)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(9)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
相关文章
    无相关信息
站内最新
站内热门
站内头条