【微信公眾號發紅包轉賬】微信公眾號上手機網頁接收請求,通過公眾號給用戶發紅包 開發流程


有了微信支付 的開發做鋪墊,相關的微信其他業務處理起來邏輯就能清晰很多。

 

准備好這兩個架包

 

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

 

----------------------------------------------------------------------------------------------至此,微信公眾號 發送紅包   【待完善】---------------------------------------------------------------

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM