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]

如果你觉得这篇内容对你挺有启发请点赞+关注

 

 

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