微信api发送微信红包

一、准备工作

微信红包文档:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_3&index=2

1.开通现金红包权限

注意: 根据监管要求,新申请商户号使用现金红包需要满足两个条件:

◆ 商户号已入驻90日且截止今日回推30天商户号保持连续不间的交易;
◆ 保持正常健康交易:

在使用现金红包之前,请前往开通现金红包功能。操作路径:【登录微信支付商户平台——>产品中心——>现金红包——>开通】
在这里插入图片描述

注意⚠️:在开通时请如实选择你的使用场景,且在红包的发放过程中如实上报你的场景,如有作假,微信支付将有权根据《微信支付商户平台使用协议》对你的商户号做出处理。

2.下载API证书

商户调用微信红包接口时,微信支付服务器会进行证书验证,请现在商户平台下载证书

3.充值

在发放现金红包之前,请确保你的资金充足。如若不足,请充值。操作路径:【登录商户平台——>交易中心——>资金管理——>充值】

4.获取openid

目前支持向指定微信用户的openid发放指定金额红包。(获取openid参见微信公众平台开发者文档:网页授权获取用户基本信息)

5.相关参数设置

和红包相关的参数,你可以在页面上自主设置和更改。操作路径如下:【登录商户平台——>产品中心——>现金红包——>产品设置】

注:“产品设置”操作按钮仅当你开通现金红包功能之后才会出现。

说明

    ◆ 调用IP地址:设置之后,仅有已设置的IP地址可以调用,其余的IP调用会报错,最多支持10个
    ◆ 单日发送金额上限:该商户一天允许发放的红包总金额上限;
    ◆ 单用户单日领取上限:限制同一openid同一日领取该商户的个数上限;
    ◆ 单用户单日领取金额上限:限制同一openid同一日领取该商户的红包金额上限
    ◆ 防刷等级:防刷是指微信风控针对微信小号、僵尸号、机器号等的拦截,你可以通过更改防刷等级控制防刷的强度(0级为关闭,1到3逐级递增安全等级);
    ◆ 同时,你也可以申请更改红包额度。若超过所选使用场景的默认额度,则需要经过审核,审核通过之后才会生效;

二、开始开发

WxpayConfig.java以及实体类Entity.java文件请查看博主【微信支付】springboot-java接入微信支付-JSAPI支付/查单/退款/发送红包(一)—JSAPI支付

发送红包接口 同样在QuickStart.java文件中继续编写
完整接口代码:

	@PostMapping("/send_redPack")
    public Map<String, String> send_redPack(@RequestBody OrderDao orderDao,@RequestParam Integer rebate_price) throws Exception {
        Map<String, String> map = new HashMap<>();
        String noncestr = WXPayUtil.generateNonceStr(); // 生成随机字符串
        SortedMap<String, String> requestMap = new TreeMap();
        requestMap.put("mch_billno", orderDao.getOrder_no()); // 商户订单号
        requestMap.put("mch_id", wxPayConfig.getMchId());// 商户号
        requestMap.put("wxappid", wxPayConfig.getAppid());// appid
        requestMap.put("send_name", "*****");// 商户名称
        requestMap.put("re_openid", orderDao.getOpenid()); // 发送红包给用户,用户的openid
        requestMap.put("total_amount", rebate_price.toString()); // 发送金额,这里接口传入的是单位为分的整数,需转化为string类型存入
        requestMap.put("total_num", "1"); //红包发送总人数
        requestMap.put("wishing", orderDao.getDescription()); // 红包祝福语
        requestMap.put("client_ip", "127.0.0.1"); // Ip地址,填写在商户平台设置的IP白名单中的ip
        requestMap.put("act_name", orderDao.getActivity_name()); // 活动名称
        requestMap.put("nonce_str", noncestr); //随机字符串

        String s = WXPayUtil.generateSignature(requestMap, wxPayConfig.getApiV2Key()); // 这里注意,发送红包接口使用的是V2版本的密钥
        //这里使用最简单的构建请求参数的方式,直接拼接
        String postXml = "<xml>\n" +
                "<sign><![CDATA[" + s + "]]></sign>\n" +
                "<mch_billno><![CDATA[" + orderDao.getOrder_no() + "]]></mch_billno>\n" +
                "<mch_id><![CDATA[" + wxPayConfig.getMchId() + "]]></mch_id>\n" +
                "<wxappid><![CDATA[" + wxPayConfig.getAppid() + "]]></wxappid>\n" +
                "<send_name><![CDATA[" + "*****" + "]]></send_name>\n" +
                "<re_openid><![CDATA[" + orderDao.getOpenid() + "]]></re_openid>\n" +
                "<total_amount><![CDATA[" + rebate_price + "]]></total_amount>\n" +
                "<total_num><![CDATA[" + "1" + "]]></total_num>\n" +
                "<wishing><![CDATA[" + orderDao.getDescription() + "]]></wishing>\n" +
                "<client_ip><![CDATA[" + "127.0.0.1" + "]]></client_ip>\n" +
                "<act_name><![CDATA[" + orderDao.getActivity_name() + "]]></act_name>\n" +
                "<nonce_str><![CDATA[" + noncestr + "]]></nonce_str>\n" +
                "</xml>";

        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack");

        httpPost.setHeader("Accept", "application/json;charset=utf-8");
        
        String result = SSLUtil.ssl("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack",postXml); // 请求发送红包接口需要证书,所以利用SSL发送请求并获取结果
        
        String info  = WXPayUtil.xmlToMap(result).get("return_msg"); //微信支付系统返回的应答参数是xml,使用微信sdk自带的泪转化并提取内容
        map.put("code","200"); // 返回状态这里直接写了200,大家需要的话自行修改
        map.put("data",result);
        map.put("info",info);

        return map;
    }

SSLUtil.java:

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.core.io.ClassPathResource;
import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
@Slf4j
public class SSLUtil {
    // 微信支付的商户id
    private static final String mch_id = "********";
    public static String ssl(String url,String data){
        StringBuffer message = new StringBuffer();
        try {
            KeyStore keyStore  = KeyStore.getInstance("PKCS12");
            /**
             *
             *重要:将API证书 apiclient_cert.p12 放到resource目录下
             *
             */
            ClassPathResource cl = new ClassPathResource("apiclient_cert.p12");
            //证书,商户号
            keyStore.load(cl.getInputStream(),mch_id.toCharArray());
            // 信任自己的 CA 和所有自签名证书
            SSLContext sslcontext = SSLContexts.custom()
                    .loadKeyMaterial(keyStore, mch_id.toCharArray())
                    .build();
            // 仅允许 TLSv1 协议
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext, new String[] { "TLSv1" }, null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();
            HttpPost httpost = new HttpPost(url);
            httpost.addHeader("Connection", "keep-alive");
            httpost.addHeader("Accept", "*/*");
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpost.addHeader("Host", "api.mch.weixin.qq.com");
            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpost.addHeader("Cache-Control", "max-age=0");
            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            System.out.println("executing request" + httpost.getRequestLine());
            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                HttpEntity entity = response.getEntity();

                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                if (entity != null) {
                    System.out.println("Response content length: " + entity.getContentLength());
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
                    String text;
                    while ((text = bufferedReader.readLine()) != null) {
                        message.append(text);
                    }
                }
                EntityUtils.consume(entity);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                response.close();
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return message.toString();
    }
}

三、测试结果

在这里插入图片描述在这里插入图片描述在这里插入图片描述

data内是微信支付系统返回的xml类型的返回参数,info中是使用微信工具类将xml转化为map后提取的return_msg中的内容

四、附:

各种失败的场景解释

  • 证书错误
    ![证书错误](https://img-blog.csdnimg.cn/direct/9c661c3e8fc542e48d6615e0c1e09c9f.png

一般证书未读取到证书会抛出异常,而不会返回200;这种情况是因为发起请求时,没有携带证书发送。微信支付文档中明确表示,接口调用需要证书。
使用SSLUtil工具类发起请求携带证书

  • 订单号过长
    订单号过长

  • xml参数格式错误

xml参数错误

  • 签名错误(这个应该是最常出现的错误)
    签名错误开发文档中还有很多错误,都一一对应,返回参数对照文档可以快速定位问题所在,具体请查看现金红包开发者文档

至此,整个微信支付的教程基本结束了,如果有小伙伴有其他问题,欢迎留言或者私信。

相关文章

【Vue3】使用ref与reactive创建响应式对象

先来简单介绍一下ref,它可以定义响应式的变量let xxx = ref(初始值)。**返回值:**一个RefImpl的实例对象,简称ref对象或refref对象的value属性是响应式的。JSxxx.value,但模板中不需要.value,直接使用即可。对于let name = ref('张三')来说,name不是响应式的,name.value是响应式的。下面我们看一看上图红框中代表的意思是,我们哪里需要响应就在哪个里面导入上述代码即可。

如何设置页面恢复运行事件触发回调

由于 Android 原生的 resume 和 pause 事件不能区分是压后台导致还是页面切换导致,所以 pageResume 和 pagePause 事件是通过 JSAPI 调用记录回调的,仅适用于同一个 session 内 Window 之间的互相切换。当一个 WebView 界面重新回到栈顶时,例如从后台被唤起、锁屏界面恢复、从下个页面回退,会触发页面恢复运行(resume)事件。如果这个界面是通过 popWindow 或 popTo 到达,且传递了 data 参数,则此页可以获取到这些参数。

日常遇到Maven出现依赖版本/缓存问题通用思路。

如果怀疑是本地仓库中缓存的依赖有问题,可以手动删除本地仓库(默认位置在用户的.m2/repository目录下),但这是一个较为极端的做法,因为这会删除所有项目的所有本地依赖,之后Maven将不得不重新下载这些依赖。针对于这样的问题 首先我们的第一思路 就是怀疑到是缓存的问题,那么我在这里去描述一下 我们遇到这类通用类的问题如何解决。检查项目的pom.xml文件,确认依赖声明正确无误,没有冲突的版本号或不正确的依赖范围。版本问题导致的,但是我确认过了一下的一些操作 依然没有解决我的问题。

什么是tomcat?tomcat是干什么用的?

Tomcat是一个开源的、轻量级的应用服务器,是Apache软件基金会的一个项目。它实现了Java Servlet、JavaServer Pages(JSP)和Java Expression Language(EL)等Java技术,用于支持在Java平台上运行的动态Web应用程序。AJP是用于Apache服务器与Tomcat之间进行通信的协议,通常用于将动态生成的内容传递给Apache服务器进行处理。它能够运行Servlet和JSP,提供了一个环境,使得开发者能够构建和运行基于Java的Web应用。

C# winfrom中excel文件导入导出

在C#交流群里,看到很多小伙伴在excel数据导入导出到C#界面上存在疑惑,所以今天专门做了这个主题,希望大家有所收获!环境:win10+vs2017界面:主要以演示为主,所以没有做优化,然后主界面上添加两个按钮,分别命名为ExportExcel和ImportExcel,添加两个dataGridView,分别是dataGridView1和dataGridView2然后在窗体加载程序中给dataGr...

Java 与 JavaScript 的区别与联系

Java 和 JavaScript 两种编程语言在软件开发中扮演着重要的角色。尽管它们都以“Java”命名,但实际上它们是完全不同的语言,各有其独特的特点和用途。本文将深入探讨 Java 和 JavaScript 的区别与联系,帮助大家更好地理解它们在编程世界中的作用。

C语言中的作用域与生命周期

但是全局变量被 static 修饰之后,外部链接属性就变成了内部链接属性,只能在自己所在的源文件内部使用了,其他源文件,即使声明了,也是无法正常使用的。结论:static修饰局部变量改变了变量的生命周期,生命周期改变的本质是改变了变量的存储类型,本来一个局部变量是存储在内存的栈区的,但是被 static 修饰后存储到了静态区。extern 是用来声明外部符号的,如果一个全局的符号在A文件中定义的,在B文件中想使用,就可以使用extern进行声明,然后使用。全局变量的生命周期是:整个程序的生命周期。

Python和Java的区别(不断更新)

运行效率:一般来说,Java的运行效率要高于Python,这主要是因为Java是编译型语言,其代码在执行前会进行预编译,而Python是解释型语言,边解释边执行。而Python没有类似的强大虚拟机,但它的核心是可以很方便地使用C语言函数或C++库,这使得Python可以轻松地与底层硬件进行交互。**类型系统:**Java是一种静态类型语言,所有变量需要先声明(类型)才能使用,且类型在编译时就已经确定。总的来说,Python和Java各有其优势和特点,选择哪种语言取决于具体的项目需求、开发环境以及个人偏好。

服务器与电脑的区别?

服务器是指一种专门提供计算和存储资源、运行特定软件服务的物理或虚拟计算机。服务器主要用于接受和处理来自客户端(如个人电脑、手机等)的请求,并向客户端提供所需的服务或数据。服务器在网络环境中扮演着中心节点的角色,负责存储和管理数据、提供网络服务、处理计算任务等。

windows下ngnix自启动(借助工具winSw)

在windows下安装nginx后,不想每次都手动启动。本文记录下windows下ngnix自启动(借助工具winSw)的操作流程提示:以下是本篇文章正文内容,下面案例可供参考本文记录下windows下ngnix自启动(借助工具winSw)的操作流程。

C# 实现微信自定义分享

在实际的应用中,我们可能不是简单的将该网页的链接直接分享出去,而是生成符合实际需要的URL,微信称其为自定义分享。

synchronized 和 Lock 有什么区别?synchronized 和 ReentrantLock 区别是什么?说一下 atomic 的原理?

例如,AtomicInteger 的 incrementAndGet() 方法就是通过 CAS 操作实现的,它首先尝试原子地将共享变量加 1,如果操作成功,则返回新的值,否则重试直到操作成功为止。CAS 操作的原理是,当 V 的值等于 A 时,将 V 的值更新为 B,否则什么也不做。synchronized 和 Lock 都是 Java 中用于实现线程同步的关键字/类库,它们都能够提供对共享资源的安全访问和防止数据竞争的功能,但是在实现方式、特性、适用场景等方面存在一些差异。

SpringBoot security 安全认证(二)——登录拦截器

本节内容:实现登录拦截器,除了登录接口之外所有接口访问都要携带Token,并且对Token合法性进行验证,实现登录状态的保持。核心内容:1、要实现登录拦截器,从Request请求中获取token,从缓存中获取Token并验证登录是否过期,若验证通过则放行;2、实现对拦截器配置,SpringBoot 安全模块使用HttpSecurity 来完成请求安全管理。

Kafka常见生产问题详解

比如,在原有Topic下,可以调整Producer的分区策略,让Producer将后续的消息更多的发送到新增的Partition里,这样可以让各个Partition上的消息能够趋于平衡。思路是可行的,但是重试的次数,发送消息的数量等都是需要考虑的问题。PageCache缓存中的消息是断电即丢失的。因为如果业务逻辑异步进行,而消费者已经同步提交了Offset,那么如果业务逻辑执行过程中出现了异常,失败了,那么Broker端已经接收到了消费者的应答,后续就不会再重新推送消息,这样就造成了业务层面的消息丢失。

深入理解 Java 变量类型、声明及应用

Java 变量 变量是用于存储数据值的容器。在 Java 中,有不同类型的变量,例如: String - 存储文本,例如 &amp;quot;你好&amp;quot;。字符串值用双引号引起来。 int - 存储整数(全数字),没有小数,例如 123 或 -123。 float - 存储浮点数,带有小数,例如 19.

Zookeeper分布式队列实战

ZooKeeper实现队列步骤1.创建队列根节点:在Zookeeper中创建一个持久节点,用作队列的根节点。所有队列元素的节点将放在这个根节点下。2.实现入队操作:当需要将一个元素添加到队列时,可以在队列的根节点下创建一个临时有序节点。节点的数据可以包含队列元素的信息。3.实现出队操作:当需要从队列中取出一个元素时,先获取根节点下的所有子节点。再找到具有最小序号的子节点,获取该节点的数据,删除该节点,然后返回节点的数据。

SpringMVC校验注解不生效

用来实现参数校验功能。Spring使用hibernate-validator作为它的默认实现,我们只需要进行一些简单的注解声明,就可以达到参数校验的功能。但是在实际使用场景中,经常会出现校验没生效的问题。

为什么Java中的String类被设计为final类?

String类作为Java中不可或缺的类之一,被设计成final类带来了不可变性、安全性、可靠性和性能优势。不可变的特性使得String对象在多线程环境下安全共享,提高了应用程序的并发性和性能。此外,String类的设计还符合Java类库的一致性和规范,确保了整个语言的稳定性和可靠性。因此,String类被设计成final类是出于多方面的考虑,以提供最佳的使用体验和编程效率。

bat脚本打开多个黑窗口并执行不同的命令

在使用java -jar运行jar包之前,需要先启动redis,而redis的安装目录与jar包不在同一目录下,所以每次启动项目的时候都需要来回的切换目录。现写了一个bat脚本,用来一键启动redis和jar包。start cmd /k &quot;cd /d redis安装目录 &amp;&amp; redis-server redis.windows.conf&quot;其中,cmd /k命令是不关闭黑窗口的命令,timeout /T 3表示等待3秒,/NOBREAK表示键盘输入不会中断等待。

鸿蒙(ArkUI)开发:实现二级联动

列表的二级联动(Cascading List)是指根据一个列表(一级列表)的选择结果,来更新另一个列表(二级列表)的选项。这种联动可以使用户根据实际需求,快速定位到想要的选项,提高交互体验。例如,短视频中拍摄风格的选择、照片编辑时的场景的选择,本文即为大家介绍如何开发二级联动。

微信小程序之全局配置-window和tabBar

一、全局配置1、全局配置文件及常用的配置项二、全局配置 - window1、小程序窗口的组成部分2、了解 window 节点常用的配置项3、设置导航栏的标题4、设置导航栏的背景色5、设置导航栏的标题颜色6、全局开启下拉刷新功能7、设置下拉刷新时窗口的背景色8、设置下拉刷新时 loading 的样式9、设置上拉触底的距离三、全局配置 - tabBar1、什么是 tabBar2、tabBar 的 6 个组成部分3、tabBar 节点的配置项。

Vue和React的区别 | | React函数式写法和类写法的区别

React 更多的是一个库而不是框架,它更专注于视图层的管理,通过社区和第三方库来进行补充和扩展。类式组件: 类式组件是 ES6 中引入的 class 类的一种用法,它继承自 React.Component,拥有完整的生命周期和内部状态管理能力。它是无状态的,没有生命周期和内部状态。而在 React 中,我们使用 JSX 语法,它是一种 JavaScript 的扩展语法,可以在 JavaScript 中直接编写类似 HTML 的结构。在 React 中,我们可以定义组件的两种方式,即函数式组件和类式组件。
返回
顶部