java微信支付v3系列——3.订单创建准备操作

news2024/11/18 7:26:27

微信支付的下单操作分为了5种,分别是JSAPI、APP、H5以及Native支付及小程序支付,之所以将支付放在单独一个章节,而不是按照支付类型划分一个章节,是因为支付所传递的数据都是相似的,方便我们更好的封装。

本章节是支付编写支付前的准备操作,发送请求需要请求地址,用户支付成功后微信会通过我们传入的回调地址进行回调,这两个地址都通过枚举进行管理。

然后就是方法的封装,如果都写在一个方法里面,代码冗余,毕竟发送请求的代码都很相似。

1. 请求地址枚举类

为了防止微信支付的请求地址前缀发生变化,因此请求前缀存储在application.yml中,请求时进行拼接即可。

@AllArgsConstructor
@Getter
public enum WxApiType {

	/**
	 * Native下单
	 */
	NATIVE_PAY("/v3/pay/transactions/native"),


	/**
	 * jsapi下单
	 */
	JSAPI_PAY("/v3/pay/transactions/jsapi"),

	/**
	 * jsapi下单
	 */
	H5_PAY("/v3/pay/transactions/h5"),

	/**
	 * APP下单
	 */
	APP_PAY("/v3/pay/transactions/app"),

	/**
	 * 查询订单
	 */
	ORDER_QUERY_BY_NO("/v3/pay/transactions/out-trade-no/%s"),

	/**
	 * 关闭订单
	 */
	CLOSE_ORDER_BY_NO("/v3/pay/transactions/out-trade-no/%s/close"),

	/**
	 * 申请退款
	 */
	DOMESTIC_REFUNDS("/v3/refund/domestic/refunds"),

	/**
	 * 查询单笔退款
	 */
	DOMESTIC_REFUNDS_QUERY("/v3/refund/domestic/refunds/%s"),

	/**
	 * 申请交易账单
	 */
	TRADE_BILLS("/v3/bill/tradebill"),

	/**
	 * 申请资金账单
	 */
	FUND_FLOW_BILLS("/v3/bill/fundflowbill");


	/**
	 * 类型
	 */
	private final String type;
}

2. 回调地址枚举类

发生请求后微信官方会回调我们传递的地址,这里通过枚举统一管理我们的回调地址,回调地址由application.yml中的 weixin.notify-domain拼接组成。

/**
 * @author cv大魔王
 * @version 1.0
 * @description 微信支付基础请求数据对象
 * @date 2022/8/4
 */
@Data
public class WeChatBasePayData {

    /**
     * 商品描述
     */
    private String title;

    /**
     * 商家订单号,对应 out_trade_no
     */
    private String orderId;

    /**
     * 订单金额
     */
    private BigDecimal price;

    /**
     * 回调地址
     */
    private WxNotifyType notify;
}

3. 微信支付基础请求数据对象

如下图所示的请求参数,各类支付方式的请求数据基本相似,我们提取出来公共的部分,整理成一个对象,方便后续调用。

image-20220804145220906

/**
 * @author cv大魔王
 * @version 1.0
 * @description 微信支付基础请求数据对象
 * @date 2022/8/4
 */
@Data
public class WeChatBasePayData {

    /**
     * 商品描述
     */
    private String title;

    /**
     * 商家订单号,对应 out_trade_no
     */
    private String orderId;

    /**
     * 订单金额
     */
    private BigDecimal price;

    /**
     * 回调地址
     */
    private WxNotifyType notify;
}

4. 将请求参数封装成Map集合

封装完枚举类后,首先就是请求参数的封装,支付类请求参数都非常相近,我们将都需要的参数提取出来以map的方式进行返回。这里的参数,指每个支付类请求都用到的参数,个别支付需要额外添加数据

/**
  * 封装基础通用请求数据
  * @param wxPayConfig 微信的配置文件
  * @param basePayData 微信支付基础请求数据
  * @return 封装后的map对象
  */
private static Map<String, Object> getBasePayParams(WxPayConfig wxPayConfig, WeChatBasePayData basePayData) {
    Map<String, Object> paramsMap = new HashMap<>();
    paramsMap.put("appid", wxPayConfig.getAppid());
    paramsMap.put("mchid", wxPayConfig.getMchId());
    // 如果商品名称过长则截取
    String title = basePayData.getTitle().length() > 62 ? basePayData.getTitle().substring(0, 62) : basePayData.getTitle();
    paramsMap.put("description",title);
    paramsMap.put("out_trade_no", basePayData.getOrderId());
    paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(basePayData.getNotify().getType()));
    Map<String, Integer> amountMap = new HashMap<>();
    amountMap.put("total", basePayData.getPrice().multiply(new BigDecimal("100")).intValue());
    paramsMap.put("amount", amountMap);
    return paramsMap;
}

5. 获取请求对象

获取请求对象,用来发送请求,这里也单独封装成一个方法了,毕竟设置发送请求的类型、编码格式、请求头等信息都是一样的,没有必要每种请求都写一次。

/**
  * 获取请求对象(Post请求)
  * @param wxPayConfig 微信配置类
  * @param apiType 接口请求地址
  * @param paramsMap 请求参数
  * @return Post请求对象
  */
private static HttpPost getHttpPost(WxPayConfig wxPayConfig, WxApiType apiType, Map<String, Object> paramsMap) {
    // 1.设置请求地址
    HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(apiType.getType()));

    // 2.设置请求数据
    Gson gson = new Gson();
    String jsonParams = gson.toJson(paramsMap);

    // 3.设置请求信息
    StringEntity entity = new StringEntity(jsonParams, "utf-8");
    entity.setContentType("application/json");
    httpPost.setEntity(entity);
    httpPost.setHeader("Accept", "application/json");
    return httpPost;
}

6. 解析响应数据

请求发送后会有响应数据,不同的支付方式,返回的数据也不一样,那么我们封装的方法统一返回map,剩下的交给调用方自行处理。除此之外,最为重要的便是错误处理,例如系统错误、签名错误等,我们需要解析微信的错误数据并作出处理。

/**
  * 解析响应数据
  * @param response 发送请求成功后,返回的数据
  * @return 微信返回的参数
  */
private static HashMap<String, String> resolverResponse(CloseableHttpResponse response) {
    try {
        // 1.获取请求码
        int statusCode = response.getStatusLine().getStatusCode();
        // 2.获取返回值 String 格式
        final String bodyAsString = EntityUtils.toString(response.getEntity());

        Gson gson = new Gson();
        if (statusCode == 200) {
            // 3.如果请求成功则解析成Map对象返回
            HashMap<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
            return resultMap;
        } else {
            if (StringUtils.isNoneBlank(bodyAsString)) {
                log.error("微信支付请求失败,提示信息:{}", bodyAsString);
                // 4.请求码显示失败,则尝试获取提示信息
                HashMap<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
                throw new DefaultException(resultMap.get("message"));
            }
            log.error("微信支付请求失败,未查询到原因,提示信息:{}", response);
            // 其他异常,微信也没有返回数据,这就需要具体排查了
            throw new IOException("request failed");
        }
    } catch (Exception e) {
        e.printStackTrace();
        throw new DefaultException(e.getMessage());
    } finally {
        try {
            response.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/107315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

20221222英语学习

托福词汇 sociology n.社会学 given adj.规定的&#xff0c;特定的&#xff1b;假定的 narrative n.叙述&#xff1b;记叙体&#xff0c;叙述技巧 deplore vt.悲叹&#xff0c;哀叹&#xff0c;公开谴责 despoil vt.夺取&#xff0c;掠夺&#xff1b;毁坏&#xff0c;破坏…

Kubernetes:环境搭建

文章目录1、k8s 概念1.1、基本概念1.2、基本术语2、k8s 架构2.1、k8s 节点2.2、k8s 组件2.2.1、master 组件2.2.2、node 组件3、k8s 集群安装配置3.1、docker3.2、主机环境调整3.3、安装 kube 工具3.4、Master 节点初始化3.5、node 节点初始化3.6、重置节点4、k8s 集群升级4.1、…

基于node.js网上蛋糕店系统的设计与实现(论文+项目源码)

随着互联网应用技术的突飞猛进。信息化广泛使用&#xff0c;已渗透到各行各业。作为代表的以网上购物商城为例。它极大地改变了人们的出行方式以及线上购物发生的转变。网上购物的需求也随着人们的个性化定制而变得相对复杂。用户量以及需求量在网上商城也带来了很多商家的考验…

c++primer第2章 变量和基本类型

文章目录第2章 变量和基本类型2.1 基本内置类型2.1.1 算术类型2.1.2 类型转换2.1.3 字面值常量2.2 变量2.2.1 变量定义2.2.2 变量声明与定义的关系2.2.3 标识符2.2.4 名字的作用域第Ⅰ部分 c基础 语法特征 类型 变量 语句 控制结构 函数补充&#xff1a;自定义数据类型(语言扩展…

Elasticsearch:如何减少 Elasticsearch 集群中的分片数量

在我之前的文章 “Elasticsearch&#xff1a;我的 Elasticsearch 集群中应该有多少个分片&#xff1f;” &#xff0c; 它描述了在我们实际操作中的分片数量的准则。在文章 “Elasticsearch&#xff1a;如何部署 Elasticsearch 来满足自己的要求” 讲述了如何部署 Elasticsearc…

Prometheus系列之Grafana 版本9.0.0 设置Email邮件报警实战

目录1. 配置文件conf/defaults.ini修改2. Grafana Web页面配置报警邮箱接收者3. 创建Dashboard4. 创建Alert的文件夹5. 设置Notification policies6. 添加Alert7. Alert Rule测试1. 配置文件conf/defaults.ini修改 将conf/defaults.ini的如下内容 ##########################…

变量提升,函数提升,暂时性死区,详细解析

变量的提升 JavaScript 在执行之前 会进行预解析 函数声明 函数体会被提升到当前作用域顶部 var的声明会提升 并赋值undefined 因为var会有一个变量提升&#xff0c;他的声明初始化会被提升&#xff0c;但是值不会被提升&#xff0c;所以控制台返回undefined 函数提升 这是…

CSS -- CSS3基础动画讲解

文章目录CSS 3动画1 动画的基本使用2 动画序列3 动画常用属性4 动画简写属性5 速度曲线细节CSS 3动画 动画(animation) 是CSS3中具有颠覆性的特征之一&#xff0c;可通过设置多个节点来精确控制一个或一组动画常用来实现复杂的动画效果。 相比较过渡&#xff0c;动画可以实现…

白银票据的原理和使用

白银票据的原理和使用白银票据(Silver Ticket)原理白银票据的使用服务账号是计算机名字$用来管理服务的账号 白银票据(Silver Ticket)原理 白银票据是伪造本该由TGS返回的ST(服务票据)&#xff0c;从而访问对应的服务 有server用户的hash就可以伪造出ST&#xff0c;且不经过K…

自重启伪遗传改良算法解决TSP问题(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 旅行商问题&#xff0c;即TSP问题&#xff08;Traveling Salesman Problem&#xff09;又译为旅行推销员问题、货郎担问题&…

Spark 3.0 - 14.ML 高斯混合聚类理论与实战

目录 一.引言 二.高斯混合模型理论 1.高斯模型 GM 2.高斯混合模型 GMM 三.高斯混合模型实践 1.数据准备 2.模型训练 3.获取多个 GM 四.总结 一.引言 前面提到的 K-means 是发现数据对应簇的硬聚类方法&#xff0c;即分配一个点其固定分配到某个簇&#xff0c;而高斯混…

三方系统集成SF(SuccessFactors),实现单点登录要点

在笔者先前的文章——《基于saml2.0的平台&#xff08;适用多种平台&#xff09;单点登录配置&#xff0c;以okta为例》中&#xff0c;详细介绍了如何把一个自开发的三方系统&#xff0c;集成到okta或者IAS平台。 经过笔者的实际工作经验&#xff0c;发现SF自己本身其实也可以…

MCU-51:初识单片机,从点亮一个灯开始

题目一、什么是单片机二、点亮一个LED灯2.1 LED原理和知识2.2 方法一2.3 方法二一、什么是单片机 单片机又称单片微控制器&#xff0c;把一整个计算机系统集成到一个芯片上&#xff0c;当于一个微型的计算机&#xff0c;和计算机相比&#xff0c;单片机只缺少了I/O设备。一块芯…

文字语义纠错技术探索与实践-张健

背景 文本语义纠错的使用场景非常广泛&#xff0c;基本上只要涉及到写作就有文本纠错的需求。书籍面市前就有独立的校对的环节来保障出版之后不出现明显的问题。在新闻中我们也时不时看到因为文字审核没到位造成大乌龙的情况&#xff0c;包括上市公司在公开文书上把“临时…

并行计算(MPI + OpenMP)

文章目录并行计算MPI&#xff08;进程级并行&#xff09;基本结构数据类型点对点通信阻塞非阻塞非连续数据打包聚合通信Communicator & Cartisen GridOpenMP&#xff08;线程级并行&#xff09;简介基本制导语句worksharing constructSectionsSingleFor临界区 & 原子操…

React 学习笔记总结(三)

文章目录1. React( v16.8 版本) 生命周期2. React( v16.8 版本) 生命周期 更新流程2.1 三个更新流程2.2 setState()的生命周期流程(对应上图2号线)2.3 forceUpdate()的生命周期流程(对应上图3号线)2.4 父组件render()渲染的生命周期流程(对应上图1号线)2.5 React( v16.8 版本)生…

“学了一个我不感兴趣的专业,要不要转行IT?”

“这个专业太无聊了&#xff0c;我想转行……” “你想转去干什么&#xff1f;” “我对金融感兴趣&#xff0c;听说金融很赚钱&#xff0c;我想学金融……” “你感兴趣为什么课后不去钻研&#xff0c;而要选择打游戏&#xff1f;” “以后再慢慢来嘛……” “可是你已经…

报表工具-FineReport JS实现参数面板显示对应数据

1. 概述 1.1 版本 报表服务器版本 功能变更 11.0 -- 1.2 预期效果 1.3 实现思路 对照填报界面的章节&#xff0c;在参数界面也用 SQL 语句实现对应数据的展示 &#xff0c;当第一次打开模板时&#xff0c;标签不显示可以通过JS 控制实现。 2. 示例 2.1 新建模板 新建普通…

设计模式-牛刀小试01

前言 本文为datawhale2022年12月组队学习《大话设计模式》task4打卡学习&#xff0c;本次完成homework1。 【教程地址】https://github.com/datawhalechina/sweetalk-design-pattern 一、任务描述 1.1 背景 小李已经是一个工作一年的初级工程师了&#xff0c;他所在的公司是…