小程序红包相关配置

# 小程序红包前期准备  

对于小程序红包坑是真的多。看官网的文档,对商户号的要求就一堆了,本身的接口也是坑巨多。  

## 小程序发红包的方式比较顺利的有两种方式  

1.使用企业付款到零钱(常用)              2.使用公众号付款     

千万不要使用小程序红包功能,对应的支付接口是现金红包接口,这个接口中,有个字段是红包类型字段,  

我在商户设置这个红包类型字段根本设置不成功,它要设置一个支付调用的IP地址,然后你会发现这个IP根本设置不成功。  

## 小程序发红包-企业付款到零钱

申请一个小程序,然后申请一个可用的商户号,且该商户号如果要使用支付功能还要满足以下要求:  

      

然后在商户号的产品中心-企业付款到零钱-开通 ,设置好秘钥证书和appKey  

# 小程序红包后台开发      

开发就直接按照文档的来写就可以了,<https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2>    

因为微信的接口要求使用HTTPS协议,所以需要引用okHttp3,而okHttp3要用到okoi,项目引入以下两个jar包,使用lib形式导入   

         

代码如下:  

```

import com.tecsun.access.modules.common.config.WechatConfig;
import com.tecsun.access.modules.common.enums.SignTypeEnum;
import com.tecsun.access.modules.dto.redpack.my.MyRedPack;
import com.tecsun.access.modules.dto.redpack.my.RedPackStatusDTO;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okhttp3.internal.platform.Platform;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.*;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.*;

/**
 * @Author echo
 * @Date 2020/7/30 14:51
 * @Description 红包工具类
 */
@Component
@Slf4j
public class MyRedPackUtil {

    @Autowired
    private WechatConfig wechatConfig;

    /**
     * @Author echo
     * @Description //红包发送
     * @Date 10:21 2020/7/31
    **/
    public String sendRedPack(MyRedPack redPack)throws Exception{
        //配置公共参数
        redPack.setNonce_str(getRandomString(32));
        redPack.setMch_appid(wechatConfig.appid());
        redPack.setMchid(wechatConfig.mchId());
        redPack.setCheck_name("NO_CHECK");

        //微信要求按照参数名ASCII字典序排序,这里巧用treeMap进行字典排序
        TreeMap treeMap = new TreeMap(toMap(redPack));
        String urlParamsByMap = getUrlParamsByMap(treeMap);//将实体类转换为url形式
        urlParamsByMap += "&key="+wechatConfig.apiKey();//拼接API密钥
        //进行签名,需要说明的是,如果内容包含中文的话,要使用utf-8进行md5签名,不然会签名错误
        String sign = parseStrToMd5L32(urlParamsByMap).toUpperCase();
        redPack.setSign(sign);
        treeMap.put("sign",redPack.getSign());
        //转换成xml格式
        String soapRequestData = getSoapRequestData(treeMap);

        log.info("微信发放红包发送报文:"+soapRequestData);
        //发起请求前准备
        RequestBody body = RequestBody.create(MediaType.parse("text/xml;charset=UTF-8"), soapRequestData);
        Request request = new Request.Builder()
                .url("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers")
                .post(body)
                .build();

        //为http请求设置证书
        X509TrustManager x509TrustManager = getX509TrustManager();
        SSLSocketFactory socketFactory = getSSL2(x509TrustManager).getSocketFactory();

        OkHttpClient okHttpClient = new OkHttpClient.Builder().sslSocketFactory(socketFactory, x509TrustManager).build();
        //得到输出内容
        Response response = okHttpClient.newCall(request).execute();
        String content = response.body().string();
        log.info("微信发放红包返回报文:"+content);
        return content;
    }

    /**
     * @Author echo
     * @Description //红包状态查询
     * @Date 15:44 2020/8/3
    **/
    public String redPackStatus(String billNo)throws Exception{
        RedPackStatusDTO dto = new RedPackStatusDTO();
        //配置公共参数
        dto.setNonce_str(getRandomString(32));
        dto.setAppid(wechatConfig.appid());
        dto.setMch_id(wechatConfig.mchId());
        dto.setPartner_trade_no(billNo);

        //微信要求按照参数名ASCII字典序排序,这里巧用treeMap进行字典排序
        TreeMap treeMap = new TreeMap(toMap(dto));
        String urlParamsByMap = getUrlParamsByMap(treeMap);//将实体类转换为url形式
        urlParamsByMap += "&key="+wechatConfig.apiKey();//拼接API密钥
        //进行签名,需要说明的是,如果内容包含中文的话,要使用utf-8进行md5签名,不然会签名错误
        String sign = parseStrToMd5L32(urlParamsByMap).toUpperCase();
        dto.setSign(sign);
        treeMap.put("sign",dto.getSign());
        //转换成xml格式
        String soapRequestData = getSoapRequestData(treeMap);

        log.info("----------微信查询红包状态发送报文:"+soapRequestData);
        //发起请求前准备
        RequestBody body = RequestBody.create(MediaType.parse("text/xml;charset=UTF-8"), soapRequestData);
        Request request = new Request.Builder()
                .url("https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo")
                .post(body)
                .build();
        //为http请求设置证书
        X509TrustManager x509TrustManager = getX509TrustManager();
        SSLSocketFactory socketFactory = getSSL2(x509TrustManager).getSocketFactory();

        OkHttpClient okHttpClient = new OkHttpClient.Builder().sslSocketFactory(socketFactory, x509TrustManager).build();
        //得到输出内容
        Response response = okHttpClient.newCall(request).execute();
        String content = response.body().string();
        log.info("----------微信查询红包状态返回报文:"+content);
        return content;
    }

    //随机生成字符串 length用户要求产生字符串的长度
    public String getRandomString(int length){
        String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random=new Random();
        StringBuffer sb=new StringBuffer();
        for(int i=0;i<length;i++){
            int number=random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 将map转换成url
     * @param map
     * @return
     */
    private String getUrlParamsByMap(Map<String, String> map) {
        if (map == null) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        map = new TreeMap<String, String>(map);
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if(entry.getValue() == null){
                continue;
            }
            sb.append(entry.getKey() + "=" + entry.getValue());
            sb.append("&");
        }
        String s = sb.toString();
        if (s.endsWith("&")) {
            s = StringUtils.substringBeforeLast(s, "&");
        }
        return s;
    }

    private Map toMap(Object bean) {
        Class<? extends Object> clazz = bean.getClass();
        Map<Object, Object> returnMap = new HashMap<Object, Object>();
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(clazz);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (!propertyName.equals("class")) {
                    Method readMethod = descriptor.getReadMethod();
                    Object result = null;
                    result = readMethod.invoke(bean, new Object[0]);
                    if (null != propertyName) {
                        propertyName = propertyName.toString();
                    }
                    if (null != result) {
                        result = result.toString();
                        returnMap.put(propertyName, result);
                    }
                }
            }  //这个发生的异常被吃掉了,如果有要进行处理的应该往上一层抛出去进行处理,我在上一层懒得处理了就在这里吃掉了
        } catch (IntrospectionException e) {
            log.error("分析类属性失败"+e.getMessage(),e);
        } catch (IllegalAccessException e) {
            log.error("实例化 JavaBean 失败"+e.getMessage(),e);
        } catch (IllegalArgumentException e) {
            log.error("映射错误"+e.getMessage(),e);
        } catch (InvocationTargetException e) {
            log.error("调用属性的 setter 方法失败"+e.getMessage(),e);
        }
        return returnMap;
    }

    /**
     * 获取md5
     * @param str
     * @return
     */
    private String parseStrToMd5L32(String str) {
        return parseStrToMd5L32(str,"utf-8");
    }

    private String parseStrToMd5L32(String str,String charset) {
        String reStr = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] bytes = md5.digest(str.getBytes(charset));
            StringBuffer stringBuffer = new StringBuffer();
            for (byte b : bytes) {
                int bt = b & 0xff;
                if (bt < 16) {
                    stringBuffer.append(0);
                }
                stringBuffer.append(Integer.toHexString(bt));
            }
            reStr = stringBuffer.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return reStr;
    }

    /**
     * 凑成xml格式字符串
     *
     * @return
     */
    private String getSoapRequestData(Map<String, String> map) throws Exception {

        StringBuffer sb = new StringBuffer();

        sb.append("<xml>");

        for (Map.Entry<String, String> entry : map.entrySet()) {

            sb.append("<" + entry.getKey() + ">" + entry.getValue() + "</" + entry.getKey() + ">");
        }

        sb.append("</xml>");
        return sb.toString();
    }

    private X509TrustManager getX509TrustManager() throws NoSuchAlgorithmException,KeyStoreException{
        TrustManagerFactory trustManagerFactory = null;
        trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init((KeyStore) null);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers));
        }
        X509TrustManager trustManager = (X509TrustManager) trustManagers[0];

        return trustManager;
    }

    private SSLContext getSSL2(X509TrustManager trustManager)throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException{


        SSLContext wx_ssl_context = SSLContext.getInstance("TLS");
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        //证书位置自己定义
        FileInputStream instream = new FileInputStream(new File(wechatConfig.keyPath()));
        try {
            keyStore.load(instream, wechatConfig.keyMima().toCharArray());
        } finally {
            instream.close();
        }
        KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmfactory.init(keyStore, wechatConfig.keyMima().toCharArray());
        wx_ssl_context.init(kmfactory.getKeyManagers(), new TrustManager[]{trustManager}, new SecureRandom());
        return wx_ssl_context;
    }
    private String md5(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("md5");

            // 不可逆
            byte[] bytes = md.digest(password.getBytes());

            String str = Base64.getEncoder().encodeToString(bytes);

            return str;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

}```    

上面的代码只是对微信对接那部分的代码,但其实整个红包的流程应该如下的:  

 因为公司部署服务里,是通过前置机转发到服务的,而服务未开通对SSL协议的443接口,所以在前置机上部署对微信对接的网关,关于服务以及rabbitMQ部分代码就不展示了,具体业务具体分析。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值