zoukankan      html  css  js  c++  java
  • 【微信公众号发红包转账】微信公众号上手机网页接收请求,通过公众号给用户发红包 开发流程

    有了微信支付 的开发做铺垫,相关的微信其他业务处理起来逻辑就能清晰很多。

    准备好这两个架包

    ---------------------------------------------------------------------------------------------------1.微信公众号发红包 开发流程图----------------------------------------------------------------------------------------------

    -----------------------------------------------------------------------------------------------2.红包实体-----------------------------------------------------------------------------------------------------

    package net.shopxx.wx.redPackage;
    
    /**
     * 微信公众号   发红包实体
     * @author SXD
     *
     */
    public class RedPack {
        
            /**
             * 随机字符串
             * 随机字符串,不长于32位
             */
             private String nonce_str;
             /**
              * 签名
              */
            private String sign;
            /**
             * 商户订单号
             * 商户订单号(每个订单号必须唯一。取值范围:0~9,a~z,A~Z)接口根据商户订单号支持重入,如出现超时可再调用。
             */
            private String mch_billno;
            /**
             * 商户号
             * 微信支付分配的商户号
             */
            private String mch_id;
            /**
             * 公众账号
             * 微信分配的公众账号ID(企业号corpid即为此appId)
             */
            private String wxappid;
            /**
             * 商户名称
             * 红包发送者名称
             */
            private String send_name;
            /**
             * 用户openid
             * 接受红包的用户
             * 用户在wxappid下的openid
             */
            private String re_openid;
            /**
             * 付款金额 单位:分
             * 100 == 1元钱 ,也就是说 这里的 1 相当于1分钱
             * 微信发送红包不少于1元钱
             */
            private int total_amount;
            /**
             * 红包发放总人数
             */
            private int total_num;
            /**
             * 红包祝福语
             */
            private String wishing;
            /**
             * Ip地址
             * 调用接口的机器Ip地址
             */
            private String client_ip;
            /**
             * 活动名称
             */
            private String act_name;
            /**
             * 备注
             */
            private String remark;
            public String getNonce_str() {
                return nonce_str;
            }
            public void setNonce_str(String nonce_str) {
                this.nonce_str = nonce_str;
            }
            public String getSign() {
                return sign;
            }
            public void setSign(String sign) {
                this.sign = sign;
            }
            public String getMch_billno() {
                return mch_billno;
            }
            public void setMch_billno(String mch_billno) {
                this.mch_billno = mch_billno;
            }
            public String getMch_id() {
                return mch_id;
            }
            public void setMch_id(String mch_id) {
                this.mch_id = mch_id;
            }
            public String getWxappid() {
                return wxappid;
            }
            public void setWxappid(String wxappid) {
                this.wxappid = wxappid;
            }
            public String getSend_name() {
                return send_name;
            }
            public void setSend_name(String send_name) {
                this.send_name = send_name;
            }
            public String getRe_openid() {
                return re_openid;
            }
            public void setRe_openid(String re_openid) {
                this.re_openid = re_openid;
            }
            public int getTotal_amount() {
                return total_amount;
            }
            public void setTotal_amount(int total_amount) {
                this.total_amount = total_amount;
            }
            public int getTotal_num() {
                return total_num;
            }
            public void setTotal_num(int total_num) {
                this.total_num = total_num;
            }
            public String getWishing() {
                return wishing;
            }
            public void setWishing(String wishing) {
                this.wishing = wishing;
            }
            public String getClient_ip() {
                return client_ip;
            }
            public void setClient_ip(String client_ip) {
                this.client_ip = client_ip;
            }
            public String getAct_name() {
                return act_name;
            }
            public void setAct_name(String act_name) {
                this.act_name = act_name;
            }
            public String getRemark() {
                return remark;
            }
            public void setRemark(String remark) {
                this.remark = remark;
            }
            
    }
    View Code

    -----------------------------------------------------------------------------------------------3.服务器端处理  逻辑---------------------------------------------------------------------------------------

    package net.shopxx.wx.redPackage;
    
    import java.util.Map;
    import java.util.UUID;
    
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.X509TrustManager;
    import javax.servlet.http.HttpServletRequest;
    
    import net.shopxx.wx.pay.HttpConnection;
    import net.shopxx.wx.pay.WeXinUtil;
    import net.shopxx.wx.pay.XmlUtil;
    import okhttp3.MediaType;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.RequestBody;
    import okhttp3.Response;
    import okhttp3.internal.platform.Platform;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    
    @Controller
    @RequestMapping("/wx/SendRedPack")
    public class SendRedPackController {
        
        
        /**
         * 公众账号ID
         */
        @Value("${member.appid}")
        private String APPID;
        /**
         * 商户号
         */
        private String MCHID;
        /**
         * key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
         */
        private String KEY;
        private XmlUtil xmlUtil = new XmlUtil();
        
        /**
         * ②接收请求
         * @param request
         * @param open_id
         * @throws Exception
         */
        @ResponseBody
        @RequestMapping("/sendRedPack")
        public void sendRedPack(HttpServletRequest request,String open_id) throws Exception{
            RedPack pack = new RedPack();
            pack.setAct_name("活动名称111");
            pack.setClient_ip(WeXinUtil.getIp(request));
            pack.setMch_billno("order_id");
            pack.setMch_id(MCHID);
             String nonce = UUID.randomUUID().toString().replaceAll("-", "");
            pack.setNonce_str(nonce);
            pack.setRe_openid(open_id);
            pack.setRemark("备注信息");
            pack.setSend_name("商户名称:谁发的红包");
            pack.setTotal_amount(1000);
            pack.setTotal_num(1);
            pack.setWishing("红包祝福语");
            pack.setWxappid(APPID);
            String sign = WeXinUtil.createUnifiedOrderSign(pack,KEY);
            pack.setSign(sign);
            
            
            /**
             * 转成XML格式 微信可接受的格式
             */
            xmlUtil.getXstreamInclueUnderline().alias("xml", pack.getClass());
            String xml = xmlUtil.getXstreamInclueUnderline().toXML(pack);
            
            //发起请求前准备
            RequestBody body = RequestBody.create(MediaType.parse("text/xml;charset=UTF-8"), xml);
            Request req = new Request.Builder()
                    .url("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack")
                    .post(body)
                    .build();
            //为http请求设置证书
            SSLSocketFactory socketFactory = WeXinUtil.getSSL().getSocketFactory();
            X509TrustManager x509TrustManager = Platform.get().trustManager(socketFactory);
            OkHttpClient okHttpClient = new OkHttpClient.Builder().sslSocketFactory(socketFactory, x509TrustManager).build();
            //得到输出内容
            /**
             *③ ④ 解析结果,判断是否红包发送成功 
             */
            Response response = okHttpClient.newCall(req).execute();
            String content = response.body().string();
            Map<String, String> responseMap = xmlUtil.parseXML(content);
            if("SUCCESS".equals(responseMap.get("return_code"))){
                System.out.println("红包发送成功");
                System.out.println("签名"+responseMap.get("sign")+"业务结果"+responseMap.get("result_code"));
                if("SUCCESS".equals(responseMap.get("result_code"))){
                    System.out.println("商户订单号"+responseMap.get("mch_billno")+
                            "商户号"+responseMap.get("mch_id")+
                            "公众账号appid"+responseMap.get("wxappid")+
                            "用户openid"+responseMap.get("re_openid")+
                            "付款金额"+responseMap.get("total_amount")+
                            "微信单号"+responseMap.get("send_listid"));
                }
            }else{
                System.out.println("红包发送失败");
            }
            
        }
        
        
    }
    View Code

    -----------------------------------------------------------------------------------------------4.XML工具类--------------------------------------------------------------------------------------------------

    package net.shopxx.wx.pay;
    
    import java.io.Writer;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.DocumentHelper;
    import org.dom4j.Element;
    
    import com.thoughtworks.xstream.XStream;
    import com.thoughtworks.xstream.core.util.QuickWriter;
    import com.thoughtworks.xstream.io.naming.NoNameCoder;
    import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
    import com.thoughtworks.xstream.io.xml.XppDriver;
    
    
    /**
     * 微信支付   微信公众号发红包
     * 封装/解析xml消息的工具类
     * @author SXD
     *
     */
    public class XmlUtil {
    
        
        public XStream getXstreamInclueUnderline(){
             XStream stream = new XStream(new XppDriver(new NoNameCoder()) {
    
                 @Override
                 public PrettyPrintWriter createWriter(Writer out) {
                     return new PrettyPrintWriter(out) {
                         // 对所有xml节点的转换都增加CDATA标记
                         boolean cdata = true;
    
                         @Override
                         @SuppressWarnings("rawtypes")
                         public void startNode(String name, Class clazz) {
                             super.startNode(name, clazz);
                         }
    
                         @Override
                         public String encodeNode(String name) {
                             return name;
                         }
    
    
                         @Override
                         protected void writeText(QuickWriter writer, String text) {
                             if (cdata) {
                                 writer.write("<![CDATA[");
                                 writer.write(text);
                                 writer.write("]]>");
                             } else {
                                 writer.write(text);
                             }
                         }
                     };
                 }
             });
             
             return stream;
        }
        
        /**
         * 根据字符串 解析XML map集合
         * @param xml
         * @return
         * @throws DocumentException
         */
        public Map<String, String> parseXML(String xml) throws DocumentException{
            Document document = DocumentHelper.parseText(xml);
            Element element =document.getRootElement();
            List<Element> childElements = element.elements();
            Map<String,String> map = new HashMap<String, String>();
            
            map = getAllElements(childElements,map);
            
            map.forEach((k,v)->{
                System.out.println(k+">>>>"+v);
            });
            
            return map;
        }
        /**
         * 获取 子节点的被迭代方法
         * @param childElements
         * @param mapEle
         * @return
         */
        private Map<String, String> getAllElements(List<Element> childElements,Map<String,String> mapEle) {
            for (Element ele : childElements) {
                if(ele.elements().size()>0){
                    mapEle = getAllElements(ele.elements(), mapEle);
                }else{
                    mapEle.put(ele.getName(), ele.getText());
                }
            }
            return mapEle;
        }
    
        
    }
    View Code

    -----------------------------------------------------------------------------------------------5.微信工具类---------------------------------------------------------------------------------------------------

    package net.shopxx.wx.pay;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.lang.reflect.Field;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.UnrecoverableKeyException;
    import java.util.Comparator;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.TreeMap;
    
    import javax.net.ssl.SSLContext;
    import javax.security.cert.CertificateException;
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.commons.codec.digest.DigestUtils;
    import org.apache.http.ssl.SSLContexts;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    
    
    /**
     * 微信支付  微信公众号发红包 
     * 工具类
     * @author SXD
     *
     */
    public class WeXinUtil {
        
        
        /**
         * 获取用户IP
         * @param request
         * @return
         */
        public static String getIp(HttpServletRequest request){
            String ipAddress = null;
             if (request.getHeader("x-forwarded-for") == null) {  
                 ipAddress = request.getRemoteAddr();
             }else{
                if(request.getHeader("x-forwarded-for").length()  > 15){
                    String [] aStr = request.getHeader("x-forwarded-for").split(",");
                    ipAddress = aStr[0];
                } else{
                    ipAddress = request.getHeader("x-forwarded-for");
                }
             } 
             return ipAddress;
        }
        
        /**
         * 签名算法,生成统一下单中 必填项签名
         * @param unifiedOrder  1.将统一下单实体中各个字段拼接  2.MD5加密  3.全部转化为大写
         * @return    返回经过签名算法生成的签名 sign
         * 第一步的规则
         *     ◆ 参数名ASCII码从小到大排序(字典序);
         *    ◆ 如果参数的值为空不参与签名;
         *    ◆ 参数名区分大小写;
         *    ◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
         *    ◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
         */
        
        /* 手动拼接方式
        public String createUnifiedOrderSign(Unifiedorder unifiedOrder){
            StringBuffer sign = new StringBuffer();
            sign.append("appid=").append(unifiedOrder.getAppid());
            sign.append("&body=").append(unifiedOrder.getBody());
            sign.append("&mch_id=").append(unifiedOrder.getMch_id());
            sign.append("&nonce_str=").append(unifiedOrder.getNonce_str());
            sign.append("&notify_url=").append(unifiedOrder.getNotify_url());
            sign.append("&openid=").append(unifiedOrder.getOpenid());
            sign.append("&out_trade_no=").append(unifiedOrder.getOut_trade_no());
            sign.append("&spbill_create_ip=").append(unifiedOrder.getSpbill_create_ip());
            sign.append("&total_fee=").append(unifiedOrder.getTotal_fee());
            sign.append("&trade_type=").append(unifiedOrder.getTrade_type());
            sign.append("&key=").append(KEY);
    
            return DigestUtils.md5Hex(sign.toString()).toUpperCase();
        }
        */
        
        /**
         * 拼接生成sign 签名
         * @param unifiedOrder
         * @param KEY
         * @return
         * @throws Exception
         */
         public static String createUnifiedOrderSign(Object object,String KEY) throws Exception{
                StringBuffer sign = new StringBuffer();
                Map<String, String> map = getSortMap(object);
    
                boolean isNotFirst = false;
    
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    if(isNotFirst == true){
                        sign.append("&");
                    }else{
                        isNotFirst = true;
                    }
    
                    sign.append(entry.getKey()).append("=").append(entry.getValue());
                }
                sign.append("&key=").append(KEY);
    
                return DigestUtils.md5Hex(sign.toString()).toUpperCase();
    
            }
         
         /**
          * 使用java反射机制,动态获取对象的属性和参数值,排除值为null的情况,并按字典序排序
          * @param object
          * @return
          * @throws Exception
          */
         private static Map<String, String> getSortMap(Object object) throws Exception{
                Field[] fields = object.getClass().getDeclaredFields();
                Map<String, String> map = new HashMap<String, String>();
    
                for(Field field : fields){
                     String name = field.getName();
                     String methodName = "get" + name.replaceFirst(name.substring(0, 1), name.substring(0, 1)
                             .toUpperCase());
                     // 调用getter方法获取属性值
    //                 Method getter = object.getClass().getMethod(methodName);
    //                 String value =  getter.invoke(object)+"";
                     field.setAccessible(true);
                     Object value = field.get(object);
                     if (value != null){
                         map.put(name, value.toString());
                     }
                }
    
                Map<String, String> sortMap = new TreeMap<String, String>(
                        new Comparator<String>() {
                            @Override
                            public int compare(String arg0, String arg1) {
                               
                                return arg0.compareTo(arg1);
                            }
                        });
                sortMap.putAll(map);
                return sortMap;
            }
         
         
         
         public static SSLContext getSSL() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException, java.security.cert.CertificateException {
                KeyStore keyStore = KeyStore.getInstance("PKCS12");
                //证书位置  放在自己的项目下面
                Resource resource = new ClassPathResource("apiclient_cert.p12");
                InputStream instream = resource.getInputStream();
                try {
                    keyStore.load(instream, "填写证书密码,默认为商户号".toCharArray());
                } finally {
                    instream.close();
                }
                SSLContext sslcontext = SSLContexts.custom()
                        .loadKeyMaterial(keyStore, "填写证书密码,默认为商户号".toCharArray())
                        .build();
                return sslcontext;
            }
         
    }
    View Code

    ----------------------------------------------------------------------------------------------至此,微信公众号 发送红包   【待完善】---------------------------------------------------------------

  • 相关阅读:
    ASP.NET中在一般处理程序中使用session的简单介绍
    oracle 11gR2安装图文教程
    ORACEL 创建表空间
    Echarts使用心得总结(二)
    SqlServer 2008无法远程连接到服务器
    浅谈HTTP中Get与Post的区别
    java设计模式-观察者模式学习
    读牛人博客有感
    mysql的with rollup
    java中的枚举enum
  • 原文地址:https://www.cnblogs.com/sxdcgaq8080/p/7511139.html
Copyright © 2011-2022 走看看