1. 程式人生 > >java呼叫微信支付

java呼叫微信支付

微信開發文件地址:https://mp.weixin.qq.com/wiki/home/
從呼叫處開始
我的流程: 1.點選“支付”按鈕,去後臺 —-> 2.後臺生成支付所需資料返回頁面 —-> 3.頁面點選“確認支付”呼叫微信支付js。完成支付功能。

支付按鈕

<div class="button" id="pay" onclick="payBox()">支付</div>
支付按鈕js

function payBox(){
        //獲得支付的錢數
        var money = $(".money input").val();
        //後臺路徑,加上引數
location.href = "/XXX/XXX/XXXX/XXXX?money ="+money; }

後臺方法(例:index())
註釋:
getPara( ) == request.getParameter(name);
setAttr( ) == request.setAttribute(name, value);
render() == 我現在所用框架返回頁面的一種方法。

首先得OpenId;下面是具體方法。

    public String getOpenId(){
            String
code = getPara("code"); String openid = ""; if (StringUtils.isEmpty(openid) && !StringUtils.isEmpty(code)) { SnsAccessToken token = SnsAccessTokenApi.getSnsAccessToken("你的APPID","你的appsecret密碼", code); openid = token.getOpenid(); } getSession().setAttribute("openandid"
,openid); return openid; }
public void index() throws Exception{
        String openid = getOpenId();
        //得到金額
        String money=  getPara("money");
        Map<String ,String > map=new HashMap<String,String>();
        //獲取隨機串
        String nonceStr=UUID.randomUUID().toString().substring(0, 32);
        //可以是支付物品的訂單號。一個號碼,看自己怎麼給
        String out_trade_no="123456789";        
        //支付金額。微信預設支付是(1=0.01)的比例,下面是將金額換算成微信可識別的
        BigDecimal re1=new BigDecimal(expressCharge);  
        BigDecimal re2=new BigDecimal(Float.toString(100.00f)); 
        Float aa = re1.multiply(re2).floatValue();
        String total_fee = String.valueOf(aa);
        String[] smill = total_fee.split("\\.");
        total_fee = smill[0];
        //微信的appid
        String appid="XXXXXXXXXXXXXXXXX";
        String mch_id="XXXXXXXXX";//商戶號
        String body="xxxxxxx";//商品資訊,可以自己起最好寫英文
        //密匙,商戶平臺的支付API密匙,注意是商戶平臺,不是微信平臺
        String key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        long timestamp = System.currentTimeMillis() / 1000;
        map.put("appid", appid );
        map.put("mch_id", mch_id);
        map.put("nonce_str",nonceStr);
        map.put("body", body);
        map.put("out_trade_no", out_trade_no);
        map.put("total_fee", total_fee);
        map.put("spbill_create_ip",getRequest().getRemoteAddr());
        //這裡是支付成功後返回的地址,微信會以XML形式放回資料,就是本篇文章的下一類(例:wxxml())方法名。
        map.put("notify_url", "http://www.XXXX.com/XXXX/XXXX/xxxx/wxxml");
        map.put("trade_type", "JSAPI");
        map.put("openid", openid);//傳入OpenId
        //這裡傳入Map集合和key商戶支付密匙
        String paySign=getPayCustomSign(map,key);
        map.put("sign",paySign);
        //將map轉為XML格式
        String xml= ArrayToXml(map);
        //統一下單,這裡不用改 
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; 
        String xmlStr = HttpKit.post(url, xml);  
        //prepayid由微信返回的 。
        String prepayid = ""; 
        if (xmlStr.indexOf("SUCCESS") != -1) {  
            Map<String, String> map2 = doXMLParse(xmlStr);  
            prepayid = (String) map2.get("prepay_id");  
        } 
        String paySign2=getPayCustomSign(signMap,key);
        setAttr("model", model);
        setAttr("appId", appid);
        setAttr("paytimestamp", String.valueOf(timestamp));
        setAttr("paynonceStr", nonceStr);
        setAttr("paypackage", "prepay_id="+prepayid);
        setAttr("paysignType","MD5");
        setAttr("paySign", paySign2);
        //去到確認支付頁面,返回頁面方式不同,(例:pay.html頁面),下面
        render("/XXXX/pay.html");
    }
/**
     * 獲取支付所需簽名
     * @param ticket
     * @param timeStamp
     * @param card_id
     * @param code
     * @return
     * @throws Exception
     */
    public static String getPayCustomSign(Map<String, String> bizObj,String key) throws Exception {
        String bizString = FormatBizQueryParaMap(bizObj, false);
        return sign(bizString, key);
    }
    /**
     * 字典排序
     * @param paraMap
     * @param urlencode
     * @return
     * @throws Exception
     */
    public static String FormatBizQueryParaMap(Map<String, String> paraMap,
            boolean urlencode) throws Exception {
        String buff = "";
        try {
            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(paraMap.entrySet());
            Collections.sort(infoIds,
                    new Comparator<Map.Entry<String, String>>() {
           public int compare(Map.Entry<String, String> o1,
                  Map.Entry<String, String> o2) {
                 return (o1.getKey()).toString().compareTo(
                                    o2.getKey());
                        }
                    });
            for (int i = 0; i < infoIds.size(); i++) {
                Map.Entry<String, String> item = infoIds.get(i);
                //System.out.println(item.getKey());
                if (item.getKey() != "") {
                    String key = item.getKey();
                    String val = item.getValue();
                    if (urlencode) {
                        val = URLEncoder.encode(val, "utf-8");
                    }
                    buff += key + "=" + val + "&";
                }
            }
            if (buff.isEmpty() == false) {
                buff = buff.substring(0, buff.length() - 1);
            }
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
        return buff;
    }
    //支付所需簽名處呼叫此方法
    public static String sign(String content, String key)
            throws Exception{
        String signStr = "";
        signStr = content + "&key=" + key;
        return MD5(signStr).toUpperCase();
    }
    //上一方法,MD5加密處理
    public final static String MD5(String s) {
        char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};       
        try {
            byte[] btInput = s.getBytes();
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
       }
    }
    //轉為XML格式
    public static String ArrayToXml(Map<String, String> arr) {
        String xml = "<xml>";
        Iterator<Entry<String, String>> iter = arr.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<String, String> entry = iter.next();
            String key = entry.getKey();
            String val = entry.getValue();
            if (IsNumeric(val)) {
                xml += "<" + key + ">" + val + "</" + key + ">";
            } else
                xml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";
        }
        xml += "</xml>";
        return xml;
    }

    public static boolean IsNumeric(String str) {
        if (str.matches("\\d *")) {
            return true;
        } else {
            return false;
        }
    }
    //解析XML
        private Map<String, String> doXMLParse(String xml)  
                throws XmlPullParserException, IOException {  

            InputStream inputStream = new ByteArrayInputStream(xml.getBytes());  

            Map<String, String> map = null;  

            XmlPullParser pullParser = XmlPullParserFactory.newInstance()  
                    .newPullParser();  

            pullParser.setInput(inputStream, "UTF-8");// 為xml設定要解析的xml資料  

            int eventType = pullParser.getEventType();  

            while (eventType != XmlPullParser.END_DOCUMENT) {  
                switch (eventType) {  
                case XmlPullParser.START_DOCUMENT:  
                    map = new HashMap<String, String>();  
                    break;  

                case XmlPullParser.START_TAG:  
                    String key = pullParser.getName();  
                    if (key.equals("xml"))  
                        break;  
                    String value = pullParser.nextText();  
                    map.put(key, value);  
                    break;  
                case XmlPullParser.END_TAG:  
                    break; 
                }  
                eventType = pullParser.next();  
            } 
            return map;  
        }  

pay頁面(上面步驟執行完後去的頁面)
此處是頁面js程式碼,接受後臺程式碼傳回來的引數。現在用的是BSL模板引擎,引數可以以EL表示式方式接收。可先將後臺傳會的引數,放在幾個input型別type=”hidden”標籤標籤中。

<input type="hidden" name="appId" value="${appId}" id="appid" />

js中得到值

 var appid = $("#appid").val();

js引用

<script type="text/javascript" src="${staticPath}/front/js/weixin.js"></script>

下面是JS程式碼,由於是bsl,自己看著傳引數吧,反正都是後臺來的。

<div class="button" id="onlinePayNow">確認支付</div>
//先寫一個點選事件,當點選id為onlinePayNow的按鈕時,觸發該事件。
$("#onlinePayNow").click(function getpay(){
            if (typeof WeixinJSBridge=="undefined") {
                if (document.addEventListener) {document.addEventListener('WeixinJSBridgeReady',onBridgeReady,false);
                }else if(document.attachEvent){document.attachEvent('WeixinJSBridgeReady',onBridgeReady);document.attachEvent('onWeixinJSBridgeReady',onBridgeReady);
                }
            }else{ 
                //如果報錯,可用下面方法看看是不是引數缺少。
                /* alert('${appId}');
                alert('${paytimestamp}');
                alert('${paynonceStr}');
                alert('${paypackage}');
                alert('${paysignType}');
                alert('${paySign}');  */
                //呼叫下面方法。開啟微信支付。
                onBridgeReady();
            }
        })

function onBridgeReady(){
        WeixinJSBridge.invoke('getBrandWCPayRequest', {
                "appId" : '${appId}', //公眾號名稱,由商戶傳入     
                "timeStamp" : '${paytimestamp}', //時間戳,自1970年以來的秒數     
                "nonceStr" : '${paynonceStr}', //隨機串     
                "package" : '${paypackage}',
                "signType" : '${paysignType}', //微信簽名方式:     
                "paySign" : '${paySign}' //微信簽名 
            }, function(res) {
                //alert(res.err_msg); // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在使用者支付成功後返
                if(res.err_msg == "get_brand_wcpay_request:ok"){
                //支付成功,完成後去到哪個頁面。                               
                window.location.href="/XXXX/xxxx.html";
                }
            });
        }

在微信公眾平臺配置,支付授權目錄。
授權目錄建議:
http://www.XXXX.com/XXXX/xxx/index/
我覺得最好寫後臺是action地址就寫Action地址,Controller就寫Controller地址,如果有Spring註解,就寫註解後名稱。
這裡寫圖片描述

我所匯入的包(java後臺,就是index方法。)

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import com.jfinal.kit.HttpKit;
import com.uitrs.express.common.Constants;