微信支付之二維碼支付(native)

HoJe
男孩子你要加油阿javascript

準備材料微信支付須要的參數統一下單二維碼回調接口用到的工具類css

. 準備材料

首先確定是要有微信的開發文檔
開發文檔地址
再而後就是一些必的參數
html


注意:回調地址異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數。

再而後就是微信的SDK
前端

. 微信支付須要的參數

上面的開發文檔你確定看熟了吧,流程確定會了吧,代碼怎麼寫呢?先來看看須要哪些參數吧.
java



好了知道流程了知道須要哪些參數了那我們動手吧!git

. 統一下單

首頁你得有統一下單是url:https://api.mch.weixin.qq.com/pay/unifiedordergithub

 1@Controller
2@RequestMapping("/wxpay")
3public class WXpayController {
4    @Autowired
5    private PayOrderService payOrderService;
6
7    /**
8     * 微信二維碼支付
9     */

10    @RequestMapping(value = "/nativePay")
11    public Map<String, String> createQRCode(HttpServletRequest request, HttpServletResponse response, String orderid) {
12        PayOrderDO payOrderDO = this.payOrderService.getOder(orderid);//訂單信息
13        //生成訂單對象
14        Map<String, String> request_data = new HashMap<>();
15        try {
16            Map<String, String> data = new HashMap<String, String>();
17            data.put("appid", WxConstants.APP_ID);//公衆帳號ID
18            data.put("mch_id",WxConstants.PARTNER);//商戶號
19            data.put("body""測試");//商品詳情
20            data.put("out_trade_no",orderid);//訂單號
21            data.put("nonce_str", UuidUtil.get32UUID());//32位字符串
22            //轉換微信中存在最小計算單位是分的問題
23            BigDecimal payMoney = payOrderDO.getPayMoney();
24            BigDecimal bigDecimal = new BigDecimal(100);
25            BigDecimal amount = payMoney.multiply(bigDecimal).setScale(0, BigDecimal.ROUND_DOWN);
26            data.put("total_fee", String.valueOf(amount));//總金額
27            data.put("spbill_create_ip", IPUtils.getIpAddr(request));//用戶終端IP
28            data.put("trade_type""NATIVE");  // H5支付的交易類型爲MWEB
29            data.put("notify_url", WxConstants.NOTIFY_URL);//通知地址
30            data.put("product_id",orderid ); 
31            String sign = createSign(data, WxConstants.PARTNER_KEY, WxConstants.CHARSET);
32            //調用生成簽名的方法,用以Map集合中的相關參數生成簽名 須要簽名密鑰
33            data.put("sign", sign);//簽名
34            String xml = WXPayUtil.generateSignedXml(data, WxConstants.PARTNER_KEY);//轉Xml格式 微信SDK自帶的
35
36            System.out.println("request - XML:" + xml);
37
38            String resultXML = HttpsClientUtil.doPost(WxConstants.BAUSE_URL, xml);//發送post請求   返回的是微信給咱們的xml格式的數據
39
40            System.out.println("result - XML:" + resultXML);
41
42                Map<String,String> result_map = xmlToMap(resultXML);
43                //xml轉map 微信SDK自帶的
44                String return_msg = result_map.get("return_msg");//返回信息
45                String return_code = result_map.get("return_code");//狀態碼
46                String result_code = result_map.get("result_code");//業務結果
47                if (null != result_map && "SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
48                    request_data.put("url", result_map.get("code_url"));
49                }else{
50                request_data.put("url""");
51            }
52
53        }catch (Exception e){
54            request_data.put("url""");
55        }
56        return request_data;
57    }

本人本身寫的也可能不是很完美歡迎大家指出 送上更完美的demo 謝謝!!!web

. 二維碼

QR碼是一種矩陣碼,或二維空間的條碼,1994年由日本Denso-Wave公司發明。QR是英文Quick Response的縮寫,即快速反應的意思,源自發明者但願QR碼可以讓其內容快速被解碼。QR碼常見於日本,併爲目前日本最流行的二維空間條碼。QR碼比普通條碼可儲存更多資料,亦無需像普通條碼般在掃描時需直線對準掃描器。
QR碼呈正方形,只有黑白兩色。在4個角落的其中3個,印有較小,像「回」字的的正方圖案。這3個是供解碼軟體做定位用的圖案,使用者無需對準,不管以任何角度掃描,資料仍可正確被讀取。
QR Code條碼的特色
1.高密度編碼,信息容量大:   
可容納多達1850個大寫字母或2710個數字或1108個字節,或500多個漢字,比普通條碼信息容量約高几十倍。   
2.編碼範圍廣:   
該條碼能夠把圖片、聲音、文字、簽字、指紋等能夠數字化的信息進行編碼,用條碼錶示出來;能夠表示多種語言文字;可表示圖像數據。   
3.容錯能力強,具備糾錯功能:   
這使得二維條碼因穿孔、污損等引發局部損壞時,照樣能夠正確獲得識讀,損毀面積達50%仍可恢復信息。   
4.譯碼可靠性高:   
它比普通條碼譯碼錯誤率百萬分之二要低得多,誤碼率不超過千萬分之一。   
5.可引入加密措施:   
保密性、防僞性好。   
6.成本低,易製做,持久耐用。
本人百度粘貼的阿!!!
廢話很少說了微信二維碼支付關鍵不就是個二維碼嘛!
數據庫


當統一下單成功了返回的結果"code_url"就是咱們要的二維碼的連接
有不少種生成二位碼的方法我知道的就兩種
1丶第一種是前端的js插件QRious
下載連接沒有找到更好的抱歉了各位
下這是一個在線的地址

使用該二維碼生成插件須要在頁面中引入qrious.js文件。
<script src="https://cdn.bootcss.com/qrious/4.0.2/qrious.js"></script>
使用一個img元素來做爲二維碼圖片的容器。
<img id="qr"></img>
能夠經過QRious()方法來實例化一個對象實例。

1(function({
2  const qr = new QRious({
3    elementdocument.getElementById('qr'),
4    value'http://www.baidu.com/'
5  })
6})()

效果如圖
json


好了前端代碼怎麼寫看你怎麼作了
2丶Zxing是Google提供的關於條碼(一維碼、二維碼)的解析工具,提供了二維碼的生成與解析的方法,如今我簡單介紹一下使用Java利用Zxing生成與解析二維碼
這種方法得寫一個工具類百度網上有的我是用的QRious就很少說了

. 回調接口


我踩的坑阿!
注意:
1丶回調url必須得填寫正確要否則微信訪問不到會一直調用,就是支付成功後微信異步通知咱們的服務器地址加項目加路徑.
2丶必定要驗證簽名,要否則微信不知道是那個商戶的會以爲不合法.
3丶給微信的數據必定是xml格式的,要否則微信解析不到就會一直調用(這就是微信比支付寶坑的地方)
話很少說上代碼

 1/**
2     * 微信支付回調函數
3     * 支付成功後微信服務器會調用此方法,修改數據庫訂單狀態
4     */

5    @RequestMapping(value = "/notify")
6    public void wxPayCallBack(HttpServletRequest request, HttpServletResponse response) {
7        try {
8            InputStream inStream = request.getInputStream();
9            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
10            byte[] buffer = new byte[1024];
11            int len = 0;
12            while ((len = inStream.read(buffer)) != -1) {
13                outSteam.write(buffer, 0, len);
14            }
15            outSteam.close();
16            inStream.close();
17            String result = new String(outSteam.toByteArray(), WxConstants.CHARSET);
18            Map<String, String> map = xmlToMap(result);
19            // 判斷簽名是否正確 微信SDK自帶的方法
20            if (WXPayUtil.isSignatureValid(map, WxConstants.PARTNER_KEY)) {
21                 logger.info("微信支付成功回調");
22                // ------------------------------
23                // 處理業務開始
24                // ------------------------------
25                String resXml = "";
26                if ("SUCCESS".equals((String) map.get("result_code"))) {
27                    // 這裏是支付成功
28                    String orderNo = (String) map.get("out_trade_no");
29                    logger.info("微信訂單號{}付款成功",orderNo);
30                    //這裏 根據實際業務場景 作相應的操做 咱們這裏是更改數據庫訂單狀態
31                    // 通知微信.異步確認成功.必寫.否則會一直通知後臺.八次以後就認爲交易失敗了.
32                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
33                } else {
34                    logger.info("支付失敗,錯誤信息:{}",packageParams.get("err_code"));
35                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[報文爲空]]></return_msg>" + "</xml> ";
36                }
37                // ------------------------------
38                // 處理業務完畢
39                // ------------------------------
40                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
41                out.write(resXml.getBytes());
42                out.flush();
43                out.close();
44            } else {
45                System.out.println("通知簽名驗證失敗");
46            }
47
48
49        } catch (Exception e) {
50           e.printStackTrace();
51           logger.info("通知簽名驗證失敗");
52        }
53
54    }

. 用到的工具類

1丶32位字符串

1public class UuidUtil {
2
3    public static String get32UUID() {
4        String uuid = UUID.randomUUID().toString().trim().replaceAll("-""");
5        return uuid;
6    }
7}

2丶獲取用戶的終端ip

 1/**
2 * IP地址
3 *
4 * @author HoJe
5 */

6public class IPUtils {
7    private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
8
9    /**
10     * 獲取IP地址
11     *
12     * 使用Nginx等反向代理軟件, 則不能經過request.getRemoteAddr()獲取IP地址
13     * 若是使用了多級反向代理的話,X-Forwarded-For的值並不止一個,而是一串IP地址,X-Forwarded-For中第一個非unknown的有效IP字符串,則爲真實IP地址
14     */

15    public static String getIpAddr(HttpServletRequest request) {
16        String ip = null;
17        try {
18            ip = request.getHeader("x-forwarded-for");
19            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
20                ip = request.getHeader("Proxy-Client-IP");
21            }
22            if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
23                ip = request.getHeader("WL-Proxy-Client-IP");
24            }
25            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
26                ip = request.getHeader("HTTP_CLIENT_IP");
27            }
28            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
29                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
30            }
31            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
32                ip = request.getRemoteAddr();
33            }
34        } catch (Exception e) {
35            logger.error("IPUtils ERROR ", e);
36        }
37
38        //使用代理,則獲取第一個IP地址
39        if(StringUtils.isEmpty(ip) && ip.length() > 15) {
40            if(ip.indexOf(",") > 0) {
41                ip = ip.substring(0, ip.indexOf(","));
42            }
43        }
44
45        return ip;
46    }
47
48}

3丶生成簽名

 1/**
2     * 生成簽名
3     * 這個方法是從微信sdk裏copy過來的,本身也能夠寫,要注意生成簽名後UTF-8的轉換,要否則容易報簽名Body UTF-8錯誤
4     *
5     * @param data 待簽名數據
6     * @param key  API密鑰
7     * @param charset UTF-8
8     */

9    public static String createSign(final Map<String, String> data, String key, String charset) throws Exception {
10        return createSign(data, key, WXPayConstants.SignType.MD5, charset);
11    }
12
13    /**
14     * 生成簽名. 注意,若含有sign_type字段,必須和signType參數保持一致。
15     *
16     * @param data     待簽名數據
17     * @param key      API密鑰
18     * @param signType 簽名方式
19     * @param charset UTF-8
20     * @return 簽名
21     */

22    private static String createSign(final Map<String, String> data, String key, WXPayConstants.SignType signType, String charset) throws Exception {
23        //根據規則建立可排序的map集合
24        Set<String> keySet = data.keySet();
25        String[] keyArray = keySet.toArray(new String[keySet.size()]);
26        Arrays.sort(keyArray);
27        StringBuilder sb = new StringBuilder();
28        for (String k : keyArray) {
29            if (k.equals(WXPayConstants.FIELD_SIGN)) {
30                continue;
31            }
32            if (data.get(k).trim().length() > 0){
33                sb.append(k).append("=").append(data.get(k).trim()).append("&");
34            } // 參數值爲空,則不參與簽名
35        }
36        sb.append("key=").append(key);
37        //轉換UTF-8
38        String str = new String(sb.toString().getBytes(charset));
39        if (WXPayConstants.SignType.MD5.equals(signType)) {
40            return MD5(sb.toString()).toUpperCase();
41        } else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
42            return HMACSHA256(sb.toString(), key);
43        } else {
44            throw new Exception(String.format("Invalid sign_type: %s", signType));
45        }
46    }
47}

4丶http請求的工具 實際沒有用到不少方法有的是退款須要用到的

 1/**
2 * http請求工具
3 *
4 *
5 *
6 *
7 */

8public class HttpsClientUtil {
9    private static PoolingHttpClientConnectionManager connMgr;
10    private static RequestConfig requestConfig;
11    private static final int MAX_TIMEOUT = 7000;
12
13    static {
14        // 設置鏈接池
15        connMgr = new PoolingHttpClientConnectionManager();
16        // 設置鏈接池大小
17        connMgr.setMaxTotal(100);
18        connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());
19
20        RequestConfig.Builder configBuilder = RequestConfig.custom();
21        // 設置鏈接超時
22        configBuilder.setConnectTimeout(MAX_TIMEOUT);
23        // 設置讀取超時
24        configBuilder.setSocketTimeout(MAX_TIMEOUT);
25        // 設置從鏈接池獲取鏈接實例的超時
26        configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
27        // 在提交請求以前 測試鏈接是否可用
28        configBuilder.setStaleConnectionCheckEnabled(true);
29        requestConfig = configBuilder.build();
30    }
31
32    /**
33     * 發送 GET 請求(HTTP),不帶輸入數據
34     *
35     * @param url
36     * @return
37     */

38    public static String doGet(String url) {
39        return doGet(url, new HashMap<String, Object>());
40    }
41
42    /**
43     * 發送 GET 請求(HTTP),K-V形式
44     *
45     * @param url
46     * @param params
47     * @return
48     */

49    public static String doGet(String url, Map<String, Object> params) {
50        String apiUrl = url;
51        StringBuffer param = new StringBuffer();
52        int i = 0;
53        for (String key : params.keySet()) {
54            if (i == 0)
55                param.append("?");
56            else
57                param.append("&");
58            param.append(key).append("=").append(params.get(key));
59            i++;
60        }
61        apiUrl += param;
62        String result = null;
63        HttpClient httpclient = new DefaultHttpClient();
64        try {
65            HttpGet httpPost = new HttpGet(apiUrl);
66            HttpResponse response = httpclient.execute(httpPost);
67            int statusCode = response.getStatusLine().getStatusCode();
68
69            System.out.println("執行狀態碼 : " + statusCode);
70
71            HttpEntity entity = response.getEntity();
72            if (entity != null) {
73                InputStream instream = entity.getContent();
74                result = IOUtils.toString(instream);
75            }
76        } catch (IOException e) {
77            e.printStackTrace();
78        }
79        return result;
80    }
81
82    /**
83     * 發送 POST 請求(HTTP),不帶輸入數據
84     *
85     * @param apiUrl
86     * @return
87     */

88    public static String doPost(String apiUrl) {
89        return doPost(apiUrl, new HashMap<String, Object>());
90    }
91
92    /**
93     * 發送 POST 請求(HTTP),K-V形式
94     *
95     * @param apiUrl API接口URL
96     * @param params 參數map
97     * @return
98     */

99    public static String doPost(String apiUrl, Map<String, Object> params) {
100        CloseableHttpClient httpClient = HttpClients.createDefault();
101        String httpStr = null;
102        HttpPost httpPost = new HttpPost(apiUrl);
103        CloseableHttpResponse response = null;
104
105        try {
106            httpPost.setConfig(requestConfig);
107            List<NameValuePair> pairList = new ArrayList<>(params.size());
108            for (Map.Entry<String, Object> entry : params.entrySet()) {
109                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry
110                        .getValue().toString());
111                pairList.add(pair);
112            }
113            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));
114            response = httpClient.execute(httpPost);
115            System.out.println(response.toString());
116            HttpEntity entity = response.getEntity();
117            httpStr = EntityUtils.toString(entity, "UTF-8");
118        } catch (IOException e) {
119            e.printStackTrace();
120        } finally {
121            if (response != null) {
122                try {
123                    EntityUtils.consume(response.getEntity());
124                } catch (IOException e) {
125                    e.printStackTrace();
126                }
127            }
128        }
129        return httpStr;
130    }
131
132    /**
133     * 發送 POST 請求(HTTP),JSON形式
134     *
135     * @param apiUrl
136     * @param json   json對象
137     * @return
138     */

139    public static String doPost(String apiUrl, Object json) {
140        CloseableHttpClient httpClient = HttpClients.createDefault();
141        String httpStr = null;
142        HttpPost httpPost = new HttpPost(apiUrl);
143        CloseableHttpResponse response = null;
144
145        try {
146            httpPost.setConfig(requestConfig);
147            StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");//解決中文亂碼問題
148            stringEntity.setContentEncoding("UTF-8");
149            stringEntity.setContentType("application/json");
150            httpPost.setEntity(stringEntity);
151            response = httpClient.execute(httpPost);
152            HttpEntity entity = response.getEntity();
153            System.out.println(response.getStatusLine().getStatusCode());
154            httpStr = EntityUtils.toString(entity, "UTF-8");
155        } catch (IOException e) {
156            e.printStackTrace();
157        } finally {
158            if (response != null) {
159                try {
160                    EntityUtils.consume(response.getEntity());
161                } catch (IOException e) {
162                    e.printStackTrace();
163                }
164            }
165        }
166        return httpStr;
167    }
168
169    /**
170     * 發送 SSL POST 請求(HTTPS),K-V形式
171     *
172     * @param apiUrl API接口URL
173     * @param params 參數map
174     * @return
175     */

176    public static String doPostSSL(String apiUrl, Map<String, Object> params) {
177        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
178        HttpPost httpPost = new HttpPost(apiUrl);
179        CloseableHttpResponse response = null;
180        String httpStr = null;
181
182        try {
183            httpPost.setConfig(requestConfig);
184            List<NameValuePair> pairList = new ArrayList<NameValuePair>(params.size());
185            for (Map.Entry<String, Object> entry : params.entrySet()) {
186                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry
187                        .getValue().toString());
188                pairList.add(pair);
189            }
190            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("utf-8")));
191            response = httpClient.execute(httpPost);
192            int statusCode = response.getStatusLine().getStatusCode();
193            if (statusCode != HttpStatus.SC_OK) {
194                return null;
195            }
196            HttpEntity entity = response.getEntity();
197            if (entity == null) {
198                return null;
199            }
200            httpStr = EntityUtils.toString(entity, "utf-8");
201        } catch (Exception e) {
202            e.printStackTrace();
203        } finally {
204            if (response != null) {
205                try {
206                    EntityUtils.consume(response.getEntity());
207                } catch (IOException e) {
208                    e.printStackTrace();
209                }
210            }
211        }
212        return httpStr;
213    }
214
215    /**
216     * 發送 SSL POST 請求(HTTPS),JSON形式
217     *
218     * @param apiUrl API接口URL
219     * @param json   JSON對象
220     * @return
221     */

222    public static String doPostSSL(String apiUrl, Object json) {
223        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
224        HttpPost httpPost = new HttpPost(apiUrl);
225        CloseableHttpResponse response = null;
226        String httpStr = null;
227
228        try {
229            httpPost.setConfig(requestConfig);
230            StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");//解決中文亂碼問題
231            stringEntity.setContentEncoding("UTF-8");
232            stringEntity.setContentType("application/json");
233            httpPost.setEntity(stringEntity);
234            response = httpClient.execute(httpPost);
235            int statusCode = response.getStatusLine().getStatusCode();
236            if (statusCode != HttpStatus.SC_OK) {
237                return null;
238            }
239            HttpEntity entity = response.getEntity();
240            if (entity == null) {
241                return null;
242            }
243            httpStr = EntityUtils.toString(entity, "utf-8");
244        } catch (Exception e) {
245            e.printStackTrace();
246        } finally {
247            if (response != null) {
248                try {
249                    EntityUtils.consume(response.getEntity());
250                } catch (IOException e) {
251                    e.printStackTrace();
252                }
253            }
254        }
255        return httpStr;
256    }
257
258    /**
259     * 建立SSL安全鏈接
260     *
261     * @return
262     */

263    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
264        SSLConnectionSocketFactory sslsf = null;
265        try {
266            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(nullnew TrustStrategy() {
267
268                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
269                    return true;
270                }
271            }).build();
272            sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
273
274                @Override
275                public boolean verify(String arg0, SSLSession arg1) {
276                    return true;
277                }
278
279                @Override
280                public void verify(String host, SSLSocket ssl) throws IOException {
281                }
282
283                @Override
284                public void verify(String host, X509Certificate cert) throws SSLException {
285                }
286
287                @Override
288                public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
289                }
290            });
291        } catch (GeneralSecurityException e) {
292            e.printStackTrace();
293        }
294        return sslsf;
295    }

我這我的比較懶還有查詢,退款,jsapi支付,H5支付慢慢更新總結.
今天就到這裏了,拜拜

相關文章
相關標籤/搜索