java 微信jsapi支付

拋開微信後臺配置不說,只要認真看一下其他的博文就可以解決

微信就是血坑,翻車了好幾次,加班通宵還幾次,終於解決了

網上都沒有完全的代碼,demo還有償,沒辦法自己研究

js:


    $(function () {
        zf()
    })
    function zf(){
        $.ajax({
            url: rootPath+'a/api/jssdk/wx-config',//調用方法1
            type: 'GET',
            dataType: 'json',
            async:false,
            data: {url: location.href.split('#')[0]},//回調地址,這地方測試用
            complete:function (xhr,textStatus) {
                var data = JSON.parse(xhr.responseText);
                console.log(data);
                if (data.code+""=="1") {
                    wx.config({
                        debug: false,
                        appId: data.appId,
                        timestamp:data.timestamp,
                        nonceStr:data.nonceStr,
                        signature: data.signature,
                        jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表
                    });
                    wx.ready(function() {


                    })
//點擊支付按鈕時支付
                    $("#zfs").click(function() {
                        //獲取支付金額
                        var active = $(".active").attr("id");
                        console.log(active);
                        //金額爲空時支付一分
                        if (active == undefined) {
                            active = "1";
                        }
                        //!!!!!!!!!重要!!!支付金額沒有小數 是:當前金額*100
                        $.ajax({
                            type: "post",
                            async: false,
                            url: rootPath + 'a/api/zf',//方法二
                            data: {
                                jes: active,//支付金額
                                url:location.href.split('#')[0]
                            }, complete: function (xhr, textStatus) {
                                var datas = JSON.parse(xhr.responseText);
                                wx.chooseWXPay({
                                   // "appId": datas.appids.toString(), //公衆號名稱,由商戶傳入
                                    "timestamp": datas.timestampss, //時間戳,自1970年以來的秒數
                                    "nonceStr": datas.nonceStrss, //隨機串
                                    "package": datas.packagess,
                                    "signType": 'MD5', //微信簽名方式:
                                    "paySign": datas.paySignss,
                                    complete:function (xhr,textStatus) {
                                        
                                        if (xhr.errMsg == "chooseWXPay:ok") {
                                            console.log(res);
                                            window.location.href=rootPath+"a/personal.html";
                                            var uid=$("#uid").val();
                                            $.ajax({
                                                type:"post",
                                                async:false,
                                                url:rootPath+'xxx.xxx.xxx',
                                                data:{
                                                    xxx:xxx
                                                }, complete:function (xhr,textStatus) {
                                                    var data = JSON.parse(xhr.responseText);
                                                    console.log(data);
                                                    var ss=data.results;
                                                    if (data.code + "" == "1") {

                                                        alert("充值成功!");
                                                        window.location.href=rootPath+"xxxxx.xxx";
                                                    }else {
                                                        alert("充值失敗!");
                                                    }
                                                }
                                            })
                                        }
                                    }
                                });
                            }
                        });
                    })
                }
            }
        })
    }

方法1

@RequestMapping(value="/api/jssdk/wx-config")
	@ResponseBody
	public Map<String, Object> get_wx_config(@RequestParam(name = "url", required = false) String url ) throws ParseException {

		//驗證access_token是否在有效期(可以自己寫存到數據庫)
		List<Map<String, Object>> list =  loginServers.select_token();

		Map<String, Object> sss=list.get(0);
		String t1 = sss.get("newDate").toString();
		String t2 = getBeforeByHourTime(1);
		DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = new Date();
		String access_token="";
		if(sdf.parse(t1).getTime()>sdf.parse(t2).getTime()){
			access_token=sss.get("access_token").toString();
		}else {
			//access_token不在有效期
			try {
				access_token =weChatJSSDKController.getAccessToken();
			} catch (Exception e) {
				e.printStackTrace();
			}
			loginServers.insert_token(access_token);
		}
      //end 驗證access_token是否在有效期

		//定義返回配置JSON對象
		JSONObject config = new JSONObject();

		//獲取微信js-sdk開發ticket
		//注意,jsapi_ticket,有效期7200秒,開發者必須在自己的服務全局緩存jsapi_ticket
		//請自行保存到緩存
		//本示例僅演示獲取流程
		//Ticket jsApiTicket = weixin.getJsApiTicket();

		//獲得jsapi_ticket之後,就可以生成JS-SDK權限驗證的簽名了。
		//簽名算法
		//簽名生成規則如下:
		//參與簽名的字段包括noncestr(隨機字符串),有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其後面部分)。
		//對所有待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1。
		//這裏需要注意的是所有參數名均爲小寫字符。
		//對string1作sha1加密,字段名和字段值都採用原始值,不進行URL轉義。
		//對應我們weixin4j的開發,則已經把簽名算法寫好了
		String noncestr = UUID.randomUUID().toString().substring(0, 15);
		Long timestamp = new Date().getTime();
		String sjc=timestamp.toString().substring(0, 10);
		//注:本鏈接僅作爲演示,實際鏈接請以自己業務鏈接爲主
		//String urls = "http://www.huwangnong.com/index";
		Map<String, String> map=new HashMap<>();
		map=JsapiTicketUtil.JsapiTicket(access_token);
		String string = "jsapi_ticket="+ map.get("ticket").toString() + "&noncestr=" + noncestr + "&timestamp=" + sjc + "&url="+ url;
		System.out.println(url);
		String signature = SHA1.encode(string);
		System.out.println(timestamp);
		System.out.println(map.get("ticket").toString());
		System.out.println(string);
		System.out.println(noncestr);
		//System.out.println(urls);
		System.out.println(signature);

		//返回wx.config參數
		sss.clear();
		sss.put("appId",appids);
		sss.put("code", 1);
		sss.put("timestamp", sjc);
		sss.put("ticket", map.get("ticket").toString());
		sss.put("nonceStr", noncestr);
		sss.put("signature", signature);
		sss.put("url", url);
		return sss;
	}

方法二:

    @Value("${weixin4j.oauth.appids}")
    private  String appids;

    @Value("${weixin4j.oauth.secrets}")
    private  String appsecret;

    @Value("${weixin4j.oauth.mch_id}")
    private  String mch_id;  //商戶id

    @Value("${weixin4j.oauth.MerchantKey}")
    private  String MerchantKey;  //商戶密鑰

public Map<String, Object> zf1(String jes,String urls,
            HttpServletRequest request, HttpServletResponse response){
        //openid 用戶的!我登陸時獲取存到數據庫及session中,便於獲取
        HttpSession session= request.getSession();
        String openid=session.getAttribute("openid").toString();

        Map<String, Object> returnMap=new HashMap<String, Object>();
        String appId =appids;
        String body = "xxx商品支付";
        String merchantId = mch_id;
        String tradeNo = String.valueOf(new Date().getTime());
        String nonceStr1 = createNonceStr();
        String notifyUrl = urls;
        String openId = openid;
        String totalFee = jes;//不可爲小數,否則報錯


        TreeMap<String, String> map = new TreeMap<String, String>();
        map.put("appid", appId);
        map.put("mch_id", merchantId);
        map.put("device_info", "WEB");
        map.put("body", body);
        map.put("trade_type", "JSAPI");
        map.put("nonce_str", nonceStr1);
        map.put("notify_url", notifyUrl);
        map.put("out_trade_no", tradeNo);
        map.put("total_fee", totalFee);
        map.put("openid", openId);
        String sign = createSign(map);


        String xml = "<xml>" +
        "<appid>" + appId + "</appid>" +
        "<body>" + body +"</body>" +
        "<device_info>WEB</device_info>" +
        "<mch_id>" + merchantId + "</mch_id>" +
        "<nonce_str>" + nonceStr1 + "</nonce_str>" +
        "<notify_url>" + notifyUrl +"</notify_url>" +
        "<openid>" + openId + "</openid>" +
        "<out_trade_no>" + tradeNo + "</out_trade_no>" +
        "<total_fee>" + totalFee + "</total_fee>" +
        "<trade_type>JSAPI</trade_type>" +
        "<sign>" + sign + "</sign>" +
        "</xml>";
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";

        String result = null;

        result = HttpsUtil.httpsRequestToString(url, "POST", xml);


        String reg = "<prepay_id><!\\[CDATA\\[(\\w+)\\]\\]></prepay_id>";

        Pattern pattern = Pattern.compile(reg);

        Matcher matcher = pattern.matcher(result);

        String prepayId = "";

        while (matcher.find()) {

            prepayId = matcher.group(1);

            System.out.println("預支付ID:" + prepayId);
        }
        Date beijingDate = Calendar.getInstance(Locale.CHINA).getTime();
        String  datassss=String.valueOf(beijingDate.getTime() / 1000);
        String  nonceStrss =createNonceStr();
      //appId, timeStamp, nonceStr, package, signType
        //再一次簽名,我看網上的有好多都沒說,是後來報錯了我搜索才發現要重新簽名
        String stringAs="appId="+appids+"&nonceStr="+nonceStrss+"&package=prepay_id="+prepayId+"&signType=MD5&timeStamp="+datassss+"&key="+MerchantKey;
        System.out.println(stringAs);
        String dd = null;
        try {
            dd = MD5(stringAs).toUpperCase();
        } catch (Exception e) {
            e.printStackTrace();
        }

        returnMap.put("paySignss",dd);
        returnMap.put("appids",appids);
        returnMap.put("timestampss", datassss);
        returnMap.put("nonceStrss", nonceStrss);
        returnMap.put("packagess", "prepay_id=" + prepayId);
        returnMap.put("signTypess", "MD5");

        return returnMap;
    }

 /**
     * 生成 MD5
     *
     * @param data 待處理數據
     * @return MD5結果
     */
    public static String MD5(String data) throws Exception {
        java.security.MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

/**
 * 生成隨機數
 * <p>算法參考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3</p>
 * @return 隨機數字符串

 */

    public static String createNonceStr() {
        SecureRandom random = new SecureRandom();
        int randomNum = random.nextInt();
        return Integer.toString(randomNum);
    }

/**
 * 生成簽名,用於在微信支付前,獲取預支付時候需要使用的參數sign
 * <p>算法參考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3</p>
 * @param params 需要發送的所有數據設置爲的Map
 * @return 簽名sign
 */

    public  String createSign(TreeMap<String, String> params) {
        String signValue = "";
        String stringSignTemp = "";

        String stringA = "";
        //獲得stringA
        Set<String> keys = params.keySet();
        for (String key : keys) {
            stringA += (key + "=" + params.get(key) + "&");
        }
        stringA = stringA.substring(0, stringA.length() - 1);
        //獲得stringSignTemp
        stringSignTemp = stringA + "&key=" + MerchantKey;
        //獲得signValue
        signValue = encryptByMD5(stringSignTemp).toUpperCase();
        System.out.println("預支付簽名:" + signValue);
        return signValue;
    }

/**
 * MD5加密
 * @param sourceStr
 * @return
 */

    public static String encryptByMD5(String sourceStr) {
        String result = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(sourceStr.getBytes("UTF-8"));
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                i += 256;
                if (i < 16)
                buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            result = buf.toString();
        } catch (NoSuchAlgorithmException e) {
            System.out.println(e);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

補發工具類:



import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.URL;


public class HttpsUtil {

    /**
     * 以https方式發送請求並將請求響應內容以String方式返回
     *
     * @param path   請求路徑
     * @param method 請求方法
     * @param body   請求數據體
     * @return 請求響應內容轉換成字符串信息
     */
    public static String httpsRequestToString(String path, String method, String body) {
        if (path == null || method == null) {
            return null;
        }

        String response = null;
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        HttpsURLConnection conn = null;
        try {
            // 創建SSLConrext對象,並使用我們指定的信任管理器初始化
            TrustManager[] tm = {new JEEWeiXinX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());

            // 從上述對象中的到SSLSocketFactory
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            System.out.println(path);

            URL url = new URL(path);
            conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);

            //設置請求方式(git|post)
            conn.setRequestMethod(method);

            //有數據提交時
            if (null != body) {
                OutputStream outputStream = conn.getOutputStream();
                outputStream.write(body.getBytes("UTF-8"));
                outputStream.close();
            }

            // 將返回的輸入流轉換成字符串
            inputStream = conn.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
            bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }

            response = buffer.toString();
        } catch (Exception e) {

        } finally {
            if (conn != null) {
                conn.disconnect();
            }
            try {
                bufferedReader.close();
                inputStreamReader.close();
                inputStream.close();
            } catch (IOException execption) {

            }
        }
        return response;
    }
}

 

package com.ruoyi.system.util;

import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

class JEEWeiXinX509TrustManager implements X509TrustManager {
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
    }

    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}

知識無價 贊助有價,有疑問可致電郵箱 [email protected]

如果你覺得這篇內容對你挺有啓發請點贊+關注

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章