微信支付

二維碼生成的 js 插件

# bootcdn 網站
https://www.bootcdn.cn/

qriousphp

qrious 下載

https://www.bootcdn.cn/qrious/
https://github.com/neocotic/qrious
https://cdnjs.cloudflare.com/ajax/libs/qrious/3.0.1/qrious.min.js

Field Type Description Default Read Only
background String Background color of the QR code "white" No
backgroundAlpha Number Background alpha of the QR code 1.0 No
element Element Element to render the QR code <canvas> Yes
foreground String Foreground color of the QR code "black" No
foregroundAlpha Number Foreground alpha of the QR code 1.0 No
level String Error correction level of the QR code (L, M, Q, H) "L" No
mime String MIME type used to render the image for the QR code "image/png" No
padding Number Padding for the QR code (pixels) null (auto) No
size Number Size of the QR code (pixels) 100 No
value String Value encoded within the QR code "" No

qrious 參數和演示

element 頁面容納二維碼的元素,必須是 <canvas> 或者 <img> 。只讀,經過構造器傳入。
value 二維碼錶示的信息
background 背景色
backgroundAlpha 背景色透明度 [0, 1] 0:徹底透明 1:徹底不透明
foreground 前景色
foregroundAlpha 前景色透明度 [0, 1] 0:徹底透明 1:徹底不透明
level 容錯級別
padding 填充
size 大小 (包括填充在內)
mime 指定生成二維碼的 mime 類型
<!DOCTYPE html>
<html>
<head>
    <title>二維碼入門小demo</title>
</head>
<body>
<div >
    <!--
    <canvas id="qrious"></canvas>
    -->
    <img id="qrious" >
</div>
<script src="js/QRious.js"></script>
<script>
    var qr = new QRious({
        element: document.getElementById('qrious')
    });
    qr.value = 'https://github.com/neocotic/qrious';
    qr.background = 'pink';
    qr.backgroundAlpha = 0.5;//背景色透明度爲 0.5
    qr.foreground = 'orange';
    qr.foregroundAlpha = 1;
    qr.level = 'H';
    qr.padding = 20;
    qr.size = 400;
</script>
</body>
</html>

qrcodehtml

https://www.bootcdn.cn/qrcode-generator/

黑馬公衆號支付信息

appid=wx8397f8696b538317 微信公衆帳號或開放平臺 APP 的惟一標識
partner=1473426802 財付通平臺的商戶帳號
partnerkey=T6m9iK73b0kn9g5v426MKfHQH7X8rKwb 財付通平臺的商戶密鑰
notifyurl=http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify 回調地址

微信支付接口

微信支付參考文檔

# 微信支付文檔導航
微信支付 > 幫助中心 > 開發文檔 > Native 支付
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1
# 微信開發者社區
https://developers.weixin.qq.com/community/develop/mixflow

安裝微信支付 SDK

SDK 與 DEMO 下載,下載的 zip 是一個 maven 項目,使用集成開發環境打開,並執行 maven install ,將 SDK 安裝到本地倉庫。java

https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_JAVA.zip
<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>3.0.9</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.3</version>
</dependency>

簽名算法

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_3
Tunnel a31ef7db.ngrok.io not found
<xml>
    <return_code><![CDATA[FAIL]]></return_code>
    <return_msg><![CDATA[XML格式錯誤]]></return_msg>
</xml>

<!--
    param.put("total_fee", String.valueOf(0.01));
-->
<xml>
    <return_code><![CDATA[FAIL]]></return_code>
    <return_msg><![CDATA[invalid total_fee]]></return_msg>
</xml>

下單

package com.mozq.wxpay.demo;

import com.github.wxpay.sdk.WXPayUtil;

import java.util.HashMap;
import java.util.Map;

public class WXPayOrderDemo {
    public static void main(String[] args) throws Exception {
        //參數
        Map<String, String> param = new HashMap<>();
        param.put("appid", "wx8397f8696b538317");
        param.put("mch_id", "1473426802");
        String nonceStr = WXPayUtil.generateNonceStr();
        param.put("nonce_str", nonceStr);
        param.put("body", "凡人修仙充值中心-凡人仙院充值");
        param.put("out_trade_no", "201907280001");
        param.put("total_fee", String.valueOf(1));
        param.put("spbill_create_ip", "123.12.12.123");
        param.put("notify_url", "http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify");
        param.put("trade_type", "NATIVE");

        HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
        //生成簽名
        String xmlParam = WXPayUtil.generateSignedXml(param, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb");
        httpClient.setXmlParam(xmlParam);
        httpClient.setHttps(false);

        //請求
        httpClient.post();

        //解析結果
        String content = httpClient.getContent();
        Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
        System.out.println(resultMap);
    }
}
{
    nonce_str=OUPjKBzycEz8cz10, 
    code_url=weixin://wxpay/bizpayurl?pr=gh8wAgg, 
    appid=wx8397f8696b538317, 
    sign=CDAD758D394BC2DA2484E89617022736, 
    trade_type=NATIVE, 
    return_msg=OK, 
    result_code=SUCCESS, 
    mch_id=1473426802, 
    return_code=SUCCESS, 
    prepay_id=wx282236255907477d09cfe0341493615900
}
<xml>
   <return_code><![CDATA[SUCCESS]]></return_code>
   <return_msg><![CDATA[OK]]></return_msg>
   <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
   <mch_id><![CDATA[10000100]]></mch_id>
   <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
   <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
   <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
   <result_code><![CDATA[SUCCESS]]></result_code>
   <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
   <trade_type><![CDATA[JSAPI]]></trade_type>
</xml>
package com.mozq.wxpay.demo;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

/**
 * http請求客戶端
 * 
 * @author Administrator
 * 
 */
public class HttpClient {
    private String url;
    private Map<String, String> param;
    private int statusCode;
    private String content;
    private String xmlParam;
    private boolean isHttps;

    public boolean isHttps() {
        return isHttps;
    }

    public void setHttps(boolean isHttps) {
        this.isHttps = isHttps;
    }

    public String getXmlParam() {
        return xmlParam;
    }

    public void setXmlParam(String xmlParam) {
        this.xmlParam = xmlParam;
    }

    public HttpClient(String url, Map<String, String> param) {
        this.url = url;
        this.param = param;
    }

    public HttpClient(String url) {
        this.url = url;
    }

    public void setParameter(Map<String, String> map) {
        param = map;
    }

    public void addParameter(String key, String value) {
        if (param == null)
            param = new HashMap<String, String>();
        param.put(key, value);
    }

    public void post() throws ClientProtocolException, IOException {
        HttpPost http = new HttpPost(url);
        setEntity(http);
        execute(http);
    }

    public void put() throws ClientProtocolException, IOException {
        HttpPut http = new HttpPut(url);
        setEntity(http);
        execute(http);
    }

    public void get() throws ClientProtocolException, IOException {
        if (param != null) {
            StringBuilder url = new StringBuilder(this.url);
            boolean isFirst = true;
            for (String key : param.keySet()) {
                if (isFirst)
                    url.append("?");
                else
                    url.append("&");
                url.append(key).append("=").append(param.get(key));
            }
            this.url = url.toString();
        }
        HttpGet http = new HttpGet(url);
        execute(http);
    }

    /**
     * set http post,put param
     */
    private void setEntity(HttpEntityEnclosingRequestBase http) {
        if (param != null) {
            List<NameValuePair> nvps = new LinkedList<NameValuePair>();
            for (String key : param.keySet())
                nvps.add(new BasicNameValuePair(key, param.get(key))); // 參數
            http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 設置參數
        }
        if (xmlParam != null) {
            http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
        }
    }

    private void execute(HttpUriRequest http) throws ClientProtocolException,
    IOException {
        CloseableHttpClient httpClient = null;
        try {
            if (isHttps) {
                SSLContext sslContext = new SSLContextBuilder()
                    .loadTrustMaterial(null, new TrustStrategy() {
                        // 信任全部
                        public boolean isTrusted(X509Certificate[] chain,
                                                 String authType)
                            throws CertificateException {
                            return true;
                        }
                    }).build();
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslContext);
                httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
                    .build();
            } else {
                httpClient = HttpClients.createDefault();
            }
            CloseableHttpResponse response = httpClient.execute(http);
            try {
                if (response != null) {
                    if (response.getStatusLine() != null)
                        statusCode = response.getStatusLine().getStatusCode();
                    HttpEntity entity = response.getEntity();
                    // 響應內容
                    content = EntityUtils.toString(entity, Consts.UTF_8);
                }
            } finally {
                response.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpClient.close();
        }
    }

    public int getStatusCode() {
        return statusCode;
    }

    public String getContent() throws ParseException, IOException {
        return content;
    }

}

查詢訂單

下單後,並無返回 transaction_id ,因此這個值是我先用 out_trade_no 查詢後知道的。git

package com.mozq.wxpay.demo;

import com.github.wxpay.sdk.WXPayUtil;

import java.util.HashMap;
import java.util.Map;

public class WXPayQueryPayStatus {
    public static void main(String[] args) throws Exception {
        //查詢參數
        Map<String, String> param = new HashMap<>();
        param.put("appid", "wx8397f8696b538317");
        param.put("mch_id", "1473426802");
        String nonceStr = WXPayUtil.generateNonceStr();
        param.put("nonce_str", nonceStr);
        //發現下單後,並無返回 transaction_id ,因此這個值是我先用 out_trade_no 查詢後知道的。
        param.put("transaction_id", "4200000344201907286520086822");
//        param.put("out_trade_no", "201907280001");
        String url = "https://api.mch.weixin.qq.com/pay/orderquery";

        HttpClient httpClient = new HttpClient(url);
        //生成簽名
        String xmlParam = WXPayUtil.generateSignedXml(param, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb");
        httpClient.setXmlParam(xmlParam);
        httpClient.setHttps(false);
        //請求
        httpClient.post();

        //解析結果
        String content = httpClient.getContent();
        Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
        System.out.println(resultMap);
    }
}
param.put("transaction_id", "wx282236255907477d09cfe0341493615900");
{return_msg=transaction_id參數長度有誤, return_code=FAIL}
{
    transaction_id=4200000344201907286520086822,
    nonce_str=zY9Kxhrt5oGxYZSW, 
    trade_state=SUCCESS, bank_type=CFT,
    openid=oNpSGwYhk9R8kJz6MqLz79KvTaM4,
    sign=A0B8AFA851CAA0AB5A33953FD9E454E8, 
    return_msg=OK, 
    fee_type=CNY, 
    mch_id=1473426802, 
    cash_fee=1, 
    out_trade_no=201907280001, 
    appid=wx8397f8696b538317, 
    total_fee=1, 
    trade_state_desc=支付成功,
    trade_type=NATIVE, 
    result_code=SUCCESS, 
    attach=, 
    time_end=20190728223947, 
    is_subscribe=N, 
    return_code=SUCCESS
}
<xml>
   <return_code><![CDATA[SUCCESS]]></return_code>
   <return_msg><![CDATA[OK]]></return_msg>
   <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
   <mch_id><![CDATA[10000100]]></mch_id>
   <device_info><![CDATA[1000]]></device_info>
   <nonce_str><![CDATA[TN55wO9Pba5yENl8]]></nonce_str>
   <sign><![CDATA[BDF0099C15FF7BC6B1585FBB110AB635]]></sign>
   <result_code><![CDATA[SUCCESS]]></result_code>
   <openid><![CDATA[oUpF8uN95-Ptaags6E_roPHg7AG0]]></openid>
   <is_subscribe><![CDATA[Y]]></is_subscribe>
   <trade_type><![CDATA[MICROPAY]]></trade_type>
   <bank_type><![CDATA[CCB_DEBIT]]></bank_type>
   <total_fee>1</total_fee>
   <fee_type><![CDATA[CNY]]></fee_type>
   <transaction_id><![CDATA[1008450740201411110005820873]]></transaction_id>
   <out_trade_no><![CDATA[1415757673]]></out_trade_no>
   <attach><![CDATA[訂單額外描述]]></attach>
   <time_end><![CDATA[20141111170043]]></time_end>
   <trade_state><![CDATA[SUCCESS]]></trade_state>
</xml>

實戰

package com.pinyougou.pay.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.github.wxpay.sdk.WXPayUtil;
import com.pinyougou.pay.service.WeixinPayService;
import org.springframework.beans.factory.annotation.Value;
import util.HttpClient;

import java.util.HashMap;
import java.util.Map;

@Service
public class WeixinPayServiceImpl implements WeixinPayService {

    @Value("${appid}")
    private String appid;

    @Value("${partner}")
    private String partner;

    @Value("${partnerkey}")
    private String partnerkey;

    @Value("${notifyurl}")
    private String notifyurl;


    @Override
    public Map<String, String> createNative(String out_trade_no, String total_fee) {

        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("appid", appid);//公衆號
        paramMap.put("mch_id", partner);//商戶號
        paramMap.put("nonce_str", WXPayUtil.generateNonceStr());//隨機字符串
        paramMap.put("body", "品優購充值");//訂單描述
        paramMap.put("out_trade_no", out_trade_no);//商戶訂單號
        paramMap.put("total_fee", total_fee);//總金額(分)
        paramMap.put("spbill_create_ip", "123.12.12.123");// IP
        paramMap.put("notify_url", "http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify");//回調地址
        paramMap.put("trade_type", "NATIVE");//交易類型
        System.out.println(paramMap);

        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//支付接口

        try {
            HttpClient httpClient = new HttpClient(url);
            //生成簽名
            String xmlParamMap = WXPayUtil.generateSignedXml(paramMap, partnerkey);
            httpClient.setXmlParam(xmlParamMap);
            httpClient.setHttps(true);
            //請求
            httpClient.post();

            //解析結果
            String content = httpClient.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
            System.out.println(resultMap);

            Map<String, String> result = new HashMap<>();
            result.put("code_url", resultMap.get("code_url"));//支付 url
            result.put("out_trade_no", out_trade_no);//訂單號
            result.put("total_fee", total_fee);//總金額

            return  result;
        } catch (Exception e) {
            e.printStackTrace();
            return new HashMap<>();
        }
    }

    @Override
    public Map<String, String> queryPayStatus(String out_trade_no) {
        //查詢參數
        Map<String, String> param = new HashMap<>();
        param.put("appid", appid);
        param.put("mch_id", partner);
        param.put("nonce_str", WXPayUtil.generateNonceStr());
        param.put("out_trade_no", out_trade_no);
        String url = "https://api.mch.weixin.qq.com/pay/orderquery";

        try {
            HttpClient httpClient = new HttpClient(url);
            //生成簽名
            String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);
            httpClient.setXmlParam(xmlParam);
            httpClient.setHttps(true);
            //請求
            httpClient.post();

            //解析結果
            String content = httpClient.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
            System.out.println(resultMap);

            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
# weixinpay.properties 文件
appid=wx8397f8696b538317
partner=1473426802
partnerkey=T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
notifyurl=http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify
相關文章
相關標籤/搜索