【微信公众号发红包转账】微信公众号上手机网页接收请求,通过公众号给用户发红包 开发流程

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

 

准备好这两个架包

 

---------------------------------------------------------------------------------------------------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

 

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

 

posted @ 2017-09-12 17:11  Angel挤一挤  阅读(1529)  评论(0编辑  收藏  举报