微信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参数错误

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

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

相关文章

ElasticSearch 集群搭建与状态监控cerebro

在单机上利用docker容器运行多个es实例来模拟es集群。部署es集群可以直接使用docker-compose来完成,但要求Linux虚拟机至少有4GI的内存空间。&quot;number_of_replicas&quot;: 1 // 副本数。&quot;number_of_shards&quot;: 3,// 分片款量。kibana可以监控es集群,不过新版本需要依赖es的x-pack 功能,配置比较复杂。第一种方式:利用kibana的DevTools创建索引库 ,在DevTools中输入指令。第二种方式:利用cerebro创建索引库。

深入理解Mysql事务隔离级别与锁机制

我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增删改查操作,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。这些问题的本质都是数据库的多事务并发问题,为了解决多事务并发问题,数据库设计了事务隔离机制、锁机制、MVCC多版本并发控制隔离机制,用一整套机制来解决多事务并发问题。接下来,我们会深入讲解这些机制,让大家彻底理解数据库内部的执行原理。

如何搭建Tomcat服务并结合内网穿透实现公网访问本地站点

Tomcat作为一个轻量级的服务器,不仅名字很有趣(让人想起童年),也拥有强大功能,由于其可以实现JavaWeb程序的装载,就成为配置JSP和Java系统必备的环境软件,也是开发调试JSP程序的首选。Tomcat运行稳定且开源免费,加上apache和Sun的加持即免费和开源的特性,使其广泛应用在中小型系统及并发访问用户较少的场景中。但想要让Tomcat网页能在公共互联网环境下被访问到,就需要cpolar内网穿透的协助。现在。笔者就为大家介绍,如何使用cpolar内网穿透。

如何在Spring Boot中优雅地进行参数校验

在Java中,注解(Annotation)是一种代码标记,通常用于提供元数据,这些元数据可以被编译器或运行时环境使用。这些注解通常用于框架和库中,以实现更加灵活和可配置的代码。

AI时代架构设计新模式

本书是一本旨在帮助架构师在人工智能时代展翅高飞的实用指南。全书以ChatGPT为核心工具,揭示了人工智能技术对架构师的角色和职责进行颠覆和重塑的关键点。本书通过共计 13 章的系统内容,深入探讨AI技术在架构设计中的应用,以及AI对传统架构师工作方式的影响。通过学习,读者将了解如何利用ChatGPT这一强大的智能辅助工具,提升架构师的工作效率和创造力。本书的读者主要是架构师及相关从业人员。

复杂 SQL 实现分组分情况分页查询

在处理数据库查询时,分页是一个常见的需求。尤其是在处理大量数据时,一次性返回所有结果可能会导致性能问题。因此,我们需要使用分页查询来限制返回的结果数量。同时,根据特定的条件筛选数据也是非常常见的需求。在本博客中,我们将探讨如何根据 camp_status 字段分为 6 种情况进行分页查询,并根据 camp_type 字段区分活动类型,返回不同的字段。我们将使用 SQL 变量来实现这一功能,并通过示例进行详细解释。

JVM垃圾回收算法

上面这张图代表的是程序运行期间所有对象的状态,它们的标志位全部是0(也就是未标记,以下默认0就是未标记,1为已标记),假设这会儿有效内存空间耗尽了,JVM将会停止应用程序的运行并开启GC线程,然后开始进行标记工作,按照根搜索算法,标记完以后,所有从root对象可达的对象就被标记为了存活的对象,此时已经完成了第一阶段标记。和标记清除算法一样,也是从根节点开始,对对象的引用进行标记,在清理阶段,并不是简单的清理未标记的对象,而是将存活的对象压缩到内存的一端,然后清理边界以外的垃圾,从而解决了碎片化的问题。

【Java 基础篇】Java TCP通信详解

本文介绍了Java中如何使用TCP协议进行网络通信,包括TCP的基础知识、TCP编程的基本步骤、创建TCP服务器和客户端、数据传输等内容。通过学习本文,您可以开始使用TCP协议来构建自己的网络应用程序,实现可靠的数据传输。希望本文能够帮助您更好地理解和应用Java中的TCP通信。

【Java 基础篇】Java多线程实现文件上传详解

本文介绍了如何使用Java多线程实现文件上传功能。通过将文件切割为多个块并使用多线程同时上传,可以提高文件上传的效率。同时,服务器端需要接收和重组这些块数据以还原原始文件。希望本文对您理解文件上传的原理以及如何实现多线程文件上传有所帮助。如果您有任何问题或疑问,请随时提出。

【Java 基础篇】Java网络编程:实现远程文件访问与管理

通过本文,我们深入探讨了如何使用Java实现远程文件访问与管理。我们讨论了建立与远程服务器的连接、文件上传与下载、列出远程目录、文件管理操作以及异常处理等关键方面。这些知识对于构建网络文件系统、文件共享应用程序以及需要进行远程文件操作的应用程序非常重要。希望本文对您理解和应用Java网络编程提供了有价值的信息。通过继续学习和实践,您可以更深入地探索这个领域,从而构建出更加复杂和功能丰富的网络应用程序。祝您编程愉快!

【Java 基础篇】Java网络编程实战:P2P文件共享详解

P2P(Peer-to-Peer)文件共享是一种分布式计算模型,其中每个计算机或设备都可以充当客户端和服务器。这意味着每台计算机都可以上传和下载文件,而不仅仅是从一个中心服务器获取文件。P2P文件共享有许多优势,包括更快的下载速度、更高的可用性和更好的容错性。P2P文件共享是一种强大的分布式文件共享模型,可以提供更快的下载速度和更好的可用性。通过使用Java网络编程,我们可以实现P2P文件共享,让不同的客户端之间可以方便地共享文件。

【Java 基础篇】Java网络编程实时数据流处理

实时数据流是一连串持续不断到达的数据,需要及时处理以获取有用的信息。这些数据可以是传感器读数、用户输入、网络流量、设备状态等等。数据的读取:从数据源(如传感器、网络、文件)读取数据。数据的处理:对读取的数据进行处理、分析或转换。数据的响应:根据处理结果,执行相应的操作或生成响应。Java提供了一些工具和库,使得处理实时数据流变得更加容易。接下来,我们将介绍Java网络编程的基础知识,以及如何使用Java处理实时数据流。本文介绍了如何使用Java进行实时数据流处理。

【Java 基础篇】Java实现文件搜索详解

本文介绍了如何使用Java实现文件搜索功能。我们讨论了文件搜索的基本概念,以及使用递归和广度优先搜索两种常见的搜索方法。此外,还介绍了一些进阶功能,如搜索文件内容和过滤文件类型。在实际应用中,您可以根据需要定制和扩展文件搜索功能,以满足特定的要求。希望本文对您在Java文件搜索方面的工作和学习有所帮助。

【Java 基础篇】Java网络编程:文件下载详解

文件下载是指从一个网络服务器或远程位置传输文件到本地计算机或设备的过程。这些文件可以是文本文件、图像、音频、视频或任何其他类型的数据文件。文件下载在Web浏览器、移动应用程序和桌面应用程序中都是常见的操作。在Java中,您可以使用各种网络协议(如HTTP、FTP、SFTP等)来执行文件下载操作。下面我们将以HTTP协议为例,介绍如何使用Java进行文件下载。本文介绍了如何使用Java进行文件下载,以及文件下载的一些进阶功能和注意事项。

【Java 基础篇】Java网络编程:实现文件断点续传功能

断点续传是一种文件下载技术,允许用户在下载文件时,如果下载中断或失败,可以从上次中断的地方继续下载,而无需重新开始下载整个文件。这提高了下载效率,节省了时间和带宽。实现断点续传的核心思想是将文件分成多个块,然后在下载时只请求未下载的块,最后将这些块合并成完整的文件。文件断点续传是一个有用的功能,可以提高文件下载的效率并节省时间。通过合理设置Range头部请求,您可以轻松实现断点续传功能。在实际应用中,可以将这些代码封装成一个可重用的工具类,以便在多个项目中使用。

【Java 基础篇】Java网络编程:下载进度监控实现详解

下载进度监控是一种用户界面元素或功能,用于显示文件下载的实时进度。通常以百分比的形式显示已下载的数据量与总数据量的比例,让用户知道下载的进展情况。实现下载进度监控的关键是获取已下载数据的大小并将其与总数据大小进行比较,然后将结果以可视化的方式呈现给用户。下载进度监控是提高文件下载体验的重要组成部分。通过合理设置Range头部请求,并在用户界面上显示下载进度,您可以实现有效的下载进度监控功能。此外,要注意异常处理和性能,以提供更好的用户体验。

【Java 基础篇】Java Lambda表达式详解

Lambda表达式,也称为闭包,是一种匿名函数,它可以传递到方法作为参数,并且可以在方法中使用。它是Java 8引入的一个新特性,用于简化代码的编写,特别是在使用函数式接口时。匿名性:Lambda表达式没有显式的名称,因此可以被当做一种匿名函数使用。简洁性:Lambda表达式可以大大减少代码的冗余,使代码更加简洁。传递性:Lambda表达式可以作为参数传递给方法,从而实现更灵活的代码组织。除了Java标准库中的函数式接口,您还可以定义自己的函数式接口,以适应特定的需求。// 结果为8。

【Java 基础篇】Java方法引用详解

方法引用是一种强大的功能,使得代码更加简洁和可读。在Java中,您可以引用类方法、对象的实例方法、类的实例方法和构造器,以适应不同的用例和需求。方法引用与Lambda表达式一起,为函数式编程提供了更多的灵活性和表达能力。希望本文的介绍对您理解和使用方法引用有所帮助。

【Java 基础篇】Java 接口组成与更新详解

在Java编程中,接口(interface)是一种非常重要的概念。它允许类定义一组抽象方法,这些方法可以在不同的类中实现。接口在Java中起到了重要的角色,被广泛应用于代码的组织和设计中。本文将详细解释Java接口的组成和最新的更新,包括默认方法、静态方法、私有方法以及接口的使用场景。

【Java 基础篇】Java函数式接口详解

函数式接口是指仅包含一个抽象方法的接口。在Java中,函数式接口用注解来标识,这个注解不是强制性的,但建议使用它来确保接口符合函数式接口的定义。函数式接口的关键特点是可以被Lambda表达式所实现。Lambda表达式是一种紧凑的语法,用于创建匿名函数,从而更容易地传递函数行为作为参数。函数式接口与Lambda表达式结合使用,可以实现更简洁和可读性强的代码。在这个示例中,Calculator是一个函数式接口,因为它只包含一个抽象方法calculate。

【Java 基础篇】Java Supplier 接口详解

Supplier接口是Java中用于表示供应商的函数式接口,它通常用于延迟计算或生成值的场景。本文介绍了Supplier接口的基本用法,包括创建Supplier实例、使用方法引用、惰性计算和处理异常。使用Supplier接口可以使代码更加灵活和易于维护,特别是在需要生成值或进行惰性计算的情况下。希望本文能够帮助你更好地理解和应用Supplier接口,从而提高Java编程的效率和质量。如果你对Java函数式编程还有更多疑问,可以进一步深入学习,掌握更多高级特性和用法。

【Java 基础篇】Java Consumer 接口详解

Consumer是Java 8中的一个函数式接口,它位于包中。它定义了一个名为accept的抽象方法,该方法接受一个参数并且不返回任何结果。换句话说,Consumer接口表示一个消费者,它可以对给定的对象执行某些操作,但不产生任何结果。ConsumerT是Consumer接口的泛型类型参数,表示输入类型。Consumer接口是Java 8中引入的一个函数式接口,用于表示一个消费者,它接受一个输入并执行某些操作。它在集合操作、数据处理、对象配置和异常处理等场景中非常有用。通过学习Consumer。

MyBatis入门配置及CRUD实现

MyBatis的主要作用是简化Java应用程序与关系型数据库之间的交互。通过使用MyBatis,开发人员可以通过简单的配置和编写SQL语句,实现对数据库的增删改查操作。同时,MyBatis还提供了一些高级特性,如分页查询、批量操作等,使得数据库访问更加灵活和高效。总之,MyBatis是一个功能强大、易于使用的持久层框架,被广泛应用于Java开发中。
返回
顶部