Java之微信支付(掃碼支付模式二)案例實戰

摘要:最近的一個項目中涉及到了支付業務,其中用到了微信支付和支付寶支付,在作的過程當中也遇到些問題,因此如今總結梳理一下,分享給有須要的人,也爲本身之後回顧留個思路。php

一:微信支付接入準備工做html

首先,微信支付,只支持企業用戶,我的用戶是不能接入微信支付的,因此要想接入微信支付,首先須要有微信公衆號,這個的企業才能申請。有了微信公衆號,就能申請微信支付的相關內容,因此在準備開始寫代碼以前須要先把下面的這些參數申請好:公衆帳號ID、微信支付商戶號、API密鑰、AppSecret是APPID對應的接口密碼、回調地址(回調必須保證外網能訪問到此地址)、發起請求的電腦IPjava

二:微信支付流程說明:git

有了上面提到的這些參數,那咱們就能夠接入微信支付了,下面我來看下微信支付的官方文檔(https://pay.weixin.qq.com/wiki/doc/api/index.html)、訪問該地址能夠看到有多種支付方式能夠選擇,咱們這裏選擇掃碼支付的方式(https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1)web

這裏咱們選擇模式二,下面看下模式二的時序圖,以下圖:spring

模式二與模式一相比,流程更爲簡單,不依賴設置的回調支付URL。商戶後臺系統先調用微信支付的統一下單接口,微信後臺系統返回連接參數code_url,商戶後臺系統將code_url值生成二維碼圖片,用戶使用微信客戶端掃碼後發起支付。注意:code_url有效期爲2小時,過時後掃碼不能再發起支付。api

 業務流程說明:安全

(1)商戶後臺系統根據用戶選購的商品生成訂單。springboot

(2)用戶確認支付後調用微信支付【統一下單API】生成預支付交易;服務器

(3)微信支付系統收到請求後生成預支付交易單,並返回交易會話的二維碼連接code_url。

(4)商戶後臺系統根據返回的code_url生成二維碼。

(5)用戶打開微信「掃一掃」掃描二維碼,微信客戶端將掃碼內容發送到微信支付系統。

(6)微信支付系統收到客戶端請求,驗證連接有效性後發起用戶支付,要求用戶受權。

(7)用戶在微信客戶端輸入密碼,確認支付後,微信客戶端提交受權。

(8)微信支付系統根據用戶受權完成支付交易。

(9)微信支付系統完成支付交易後給微信客戶端返回交易結果,並將交易結果經過短信、微信消息提示用戶。微信客戶端展現支付交易結果頁面。

(10)微信支付系統經過發送異步消息通知商戶後臺系統支付結果。商戶後臺系統需回覆接收狀況,通知微信後臺系統再也不發送該單的支付通知。

(11)未收到支付通知的狀況,商戶後臺系統調用【查詢訂單API】。

(12)商戶確認訂單已支付後給用戶發貨。

三:微信支付所須要的maven依賴:

<!--生成二維碼jar-->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.2.1</version>
        </dependency>

四:微信支付調用統一下單接口的核心代碼

3.1:微信支付工具類:

HttpUtil.java

package com.micai.springboot.util.pay.wx;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;

/**
 * http工具類,負責發起post請求並獲取的返回
 */
public class HttpUtil {

    private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);

    private final static int CONNECT_TIMEOUT = 5000; // in milliseconds  
    private final static String DEFAULT_ENCODING = "UTF-8";  
      
    public static String postData(String urlStr, String data){  
        return postData(urlStr, data, null);
    }
      
    public static String postData(String urlStr, String data, String contentType){  
        BufferedReader reader = null;  
        try {  
            URL url = new URL(urlStr);  
            URLConnection conn = url.openConnection();  
            conn.setDoOutput(true);  
            conn.setConnectTimeout(CONNECT_TIMEOUT);  
            conn.setReadTimeout(CONNECT_TIMEOUT);  
            if(contentType != null)  
                conn.setRequestProperty("content-type", contentType);  
            OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);  
            if(data == null)  
                data = "";  
            writer.write(data);   
            writer.flush();  
            writer.close();    
  
            reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));  
            StringBuilder sb = new StringBuilder();  
            String line = null;  
            while ((line = reader.readLine()) != null) {  
                sb.append(line);  
                sb.append("\r\n");  
            }  
            return sb.toString();  
        } catch (IOException e) {  
            logger.error("Error connecting to " + urlStr + ": " + e.getMessage());
        } finally {
            try {  
                if (reader != null)  
                    reader.close();  
            } catch (IOException e) {
                e.printStackTrace();
            }  
        }
        return null;  
    }  

}

MD5Util.java

package com.micai.springboot.util.pay.wx; import java.security.MessageDigest; public class MD5Util { private static String byteArrayToHexString(byte b[]) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) resultSb.append(byteToHexString(b[i])); return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } public static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = new String(origin); MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) resultString = byteArrayToHexString(md.digest(resultString .getBytes())); else resultString = byteArrayToHexString(md.digest(resultString .getBytes(charsetname))); } catch (Exception exception) { } return resultString; } private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; }

PayConfigUtil.java

package com.micai.springboot.util.pay.wx;

public class PayConfigUtil {
	//初始化
//	public final static String APP_ID = "11111111111"; //公衆帳號appid(改成本身實際的)
//	public final static String APP_SECRET = "";
//	public final static String MCH_ID = "111111"; //商戶號(改成本身實際的)
//	public final static String API_KEY = "11111111111"; //(改成本身實際的)key設置路徑:微信商戶平臺(pay.weixin.qq.com)-->帳戶設置-->API安全-->密鑰設置
	
	//統一下單
	public final static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
//	public final static String NOTIFY_URL = "http://xxxxxxx"; //微信支付回調接口,就是微信那邊收到(改成本身實際的)
//	//企業向我的帳號付款的URL
//	public final static String SEND_EED_PACK_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
//
//	public final static String CREATE_IP = "113.69.246.11";//發起支付ip(改成本身實際的)
	
}
PayToolUtil.java
package com.micai.springboot.util.pay.wx; import java.text.SimpleDateFormat; import java.util.*; public class PayToolUtil { /** * 是否簽名正確,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。 * @return boolean */  
    public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) { StringBuffer sb = new StringBuffer(); Set es = packageParams.entrySet(); Iterator it = es.iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); String k = (String)entry.getKey(); String v = (String)entry.getValue(); if(!"sign".equals(k) && null != v && !"".equals(v)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + API_KEY); //算出摘要 
        String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase(); String tenpaySign = ((String)packageParams.get("sign")).toLowerCase(); //System.out.println(tenpaySign + " " + mysign); 
        return tenpaySign.equals(mysign); } /** * 建立sign簽名 * @param characterEncoding 編碼格式 * @param packageParams 請求參數 * @param API_KEY API密鑰 * @return
     */
    public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) { StringBuffer sb = new StringBuffer(); Set es = packageParams.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + API_KEY); String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; } /** * 將請求參數轉換爲xml格式的string * @param parameters 請求參數 * @return 轉換後的字符串 */
    public static String getRequestXml(SortedMap<Object, Object> parameters) { StringBuffer sb = new StringBuffer(); sb.append("<xml>"); Set es = parameters.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) { sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">"); } else { sb.append("<" + k + ">" + v + "</" + k + ">"); } } sb.append("</xml>"); return sb.toString(); } /** * 取出一個指定長度大小的隨機正整數 * @param length int 設定所取出隨機數的長度。length小於11 * @return int 返回生成的隨機數。 */
    public static int buildRandom(int length) { int num = 1; double random = Math.random(); if (random < 0.1) { random = random + 0.1; } for (int i = 0; i < length; i++) { num = num * 10; } return (int) ((random * num)); } /** * 獲取當前時間 yyyyMMddHHmmss * @return
     */
    public static String getCurrTime() { Date now = new Date(); SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss"); return outFormat.format(now); } }

QRUtil.java

package com.micai.springboot.util.pay.wx;

import com.google.zxing.common.BitMatrix;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

/**
 * 二維碼生產工具類
 */
public class QRUtil {
	
   private static final int BLACK = 0xFF000000; 
   private static final int WHITE = 0xFFFFFFFF; 
    
   private QRUtil() {} 

   public static BufferedImage toBufferedImage(BitMatrix matrix) {
     int width = matrix.getWidth(); 
     int height = matrix.getHeight(); 
     BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
     for (int x = 0; x < width; x++) { 
       for (int y = 0; y < height; y++) { 
         image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); 
       } 
     } 
     return image; 
   } 

   public static void writeToFile(BitMatrix matrix, String format, File file)
       throws IOException { 
     BufferedImage image = toBufferedImage(matrix); 
     if (!ImageIO.write(image, format, file)) { 
       throw new IOException("Could not write an image of format " + format + " to " + file); 
     } 
   }

   public static void writeToStream(BitMatrix matrix, String format, OutputStream stream)
       throws IOException { 
     BufferedImage image = toBufferedImage(matrix); 
     if (!ImageIO.write(image, format, stream)) { 
       throw new IOException("Could not write an image of format " + format); 
     }
   }
}
XMLUtil4jdom.java
package com.micai.springboot.util.pay.wx;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class XMLUtil4jdom {

    /** 
     * 解析xml,返回第一級元素鍵值對。若是第一級元素有子節點,則此節點的值是子節點的xml數據。 
     * @param strxml 
     * @return 
     * @throws JDOMException 
     * @throws IOException 
     */  
    public static Map doXMLParse(String strxml) throws JDOMException, IOException {  
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");  
        if(null == strxml || "".equals(strxml)) {
            return null;  
        }
        Map<String, String> m = new HashMap<String, String>();
        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));  
        SAXBuilder builder = new SAXBuilder();  
        Document doc = builder.build(in);  
        Element root = doc.getRootElement();  
        List list = root.getChildren();  
        Iterator it = list.iterator();  
        while(it.hasNext()) {  
            Element e = (Element) it.next();  
            String k = e.getName();  
            String v = "";  
            List children = e.getChildren();  
            if(children.isEmpty()) {  
                v = e.getTextNormalize();  
            } else {  
                v = XMLUtil4jdom.getChildrenText(children);  
            }  
            m.put(k, v);
        }  
        //關閉流
        in.close();  
        return m;
    }  
      
    /** 
     * 獲取子結點的xml 
     * @param children 
     * @return String 
     */  
    public static String getChildrenText(List children) {  
        StringBuffer sb = new StringBuffer();  
        if(!children.isEmpty()) {  
            Iterator it = children.iterator();  
            while(it.hasNext()) {  
                Element e = (Element) it.next();  
                String name = e.getName();  
                String value = e.getTextNormalize();  
                List list = e.getChildren();  
                sb.append("<" + name + ">");  
                if(!list.isEmpty()) {  
                    sb.append(XMLUtil4jdom.getChildrenText(list));  
                }  
                sb.append(value);  
                sb.append("</" + name + ">");  
            }  
        }  
        return sb.toString();
    }

}

3.2:微信支付實體對象:

WxpayVo.java
package com.micai.springboot.vo.pay;

import java.io.Serializable;

/**
 * @Auther: zhaoxinguo
 * @Date: 2018/8/31 11:34
 * @Description:
 */
public class WxpayVo implements Serializable {

    private String app_id;//公衆帳號ID
    private String mch_id;//微信支付商戶號
    private String key;//API密鑰
    private String app_secret;//AppSecret是APPID對應的接口密碼

    private String out_trade_no;// 商戶訂單號
    private String currTime;
    private String strTime;
    private String strRandom;
    private String nonce_str;//隨機字符串
    private String spbill_create_ip;
    private String notify_url;
    private String trade_type;
    private String total_fee;

    public String getApp_id() {
        return app_id;
    }

    public void setApp_id(String app_id) {
        this.app_id = app_id;
    }

    public String getMch_id() {
        return mch_id;
    }

    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getApp_secret() {
        return app_secret;
    }

    public void setApp_secret(String app_secret) {
        this.app_secret = app_secret;
    }

    public String getOut_trade_no() {
        return out_trade_no;
    }

    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }

    public String getCurrTime() {
        return currTime;
    }

    public void setCurrTime(String currTime) {
        this.currTime = currTime;
    }

    public String getStrTime() {
        return strTime;
    }

    public void setStrTime(String strTime) {
        this.strTime = strTime;
    }

    public String getStrRandom() {
        return strRandom;
    }

    public void setStrRandom(String strRandom) {
        this.strRandom = strRandom;
    }

    public String getNonce_str() {
        return nonce_str;
    }

    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }

    public String getSpbill_create_ip() {
        return spbill_create_ip;
    }

    public void setSpbill_create_ip(String spbill_create_ip) {
        this.spbill_create_ip = spbill_create_ip;
    }

    public String getNotify_url() {
        return notify_url;
    }

    public void setNotify_url(String notify_url) {
        this.notify_url = notify_url;
    }

    public String getTrade_type() {
        return trade_type;
    }

    public void setTrade_type(String trade_type) {
        this.trade_type = trade_type;
    }

    public String getTotal_fee() {
        return total_fee;
    }

    public void setTotal_fee(String total_fee) {
        this.total_fee = total_fee;
    }
}

3.3:微信支付業務對象:

PayBaseController.java
package com.micai.springboot.controller.pay;

import com.micai.springboot.base.BaseController;
import org.springframework.beans.factory.annotation.Value;

/**
 * @Auther: zhaoxinguo
 * @Date: 2018/8/31 13:40
 * @Description:
 */
public abstract class PayBaseController extends BaseController {

    // 支付寶支付參數配置 //
    @Value("${ALIPAY.APPID}")
    protected String app_id;//應用ID,您的APPID,收款帳號既是您的APPID對應支付寶帳號
    @Value("${ALIPAY.PRIVATEKEY}")
    protected String merchant_private_key;//商戶私鑰,您的PKCS8格式RSA2私鑰
    @Value("${ALIPAY.PUBLICKEY}")
    protected String alipay_public_key;//支付寶公鑰,查看地址:https://openhome.alipay.com/platform/keyManage.htm 對應APPID下的支付寶公鑰。
    @Value("${ALIPAY.NOTIFY_URL}")
    protected String notify_url;//服務器異步通知頁面路徑
    @Value("${ALIPAY.RETURNA_URL}")
    protected String return_url;//頁面跳轉同步通知頁面路徑
    @Value("${ALIPAY.SIGN}")
    protected String sign_type = "RSA2";//簽名方式
    protected String charset = "utf-8";//字符編碼格式
    @Value("${ALIPAY.GATEWAY_URL}")
    protected String gateway_url;//支付寶網關

    // 微信支付參數配置 //
    @Value("${WXPAY.APPID}")
    protected String APPID;//公衆帳號ID
    @Value("${WXPAY.MCHID}")
    protected String MCHID;//微信支付商戶號
    @Value("${WXPAY.KEY}")
    protected String KEY;//API密鑰
    @Value("${WXPAY.APPSECRET}")
    protected String APPSECRET;//AppSecret是APPID對應的接口密碼
    @Value("${WXPAY.NOTIFY_URL}")
    protected String NOTIFY_URL;//回調地址。測試回調必須保證外網能訪問到此地址
    @Value("${WXPAY.CREATE_IP}")
    protected String CREATE_IP;//發起請求的電腦IP

}

WxpayController.java

package com.micai.springboot.controller.pay;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.micai.springboot.util.pay.wx.*;
import com.micai.springboot.vo.pay.WxpayVo;
import org.jdom.JDOMException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

/**
 * @Auther: zhaoxinguo
 * @Date: 2018/8/31 10:37
 * @Description: 微信支付後臺接口
 */
@RestController
@RequestMapping(value = "/wxpay")
public class WxpayController extends PayBaseController {

    /**
     * 微信支付->掃碼支付(模式二)->統一下單->微信二維碼
     * @return
     */
    @GetMapping("/qrcode")
    public void wxpayPay(HttpServletResponse response) {
        String urlCode = null;
        // 獲取訂單信息
        WxpayVo vo = new WxpayVo();
        String out_trade_no = UUID.randomUUID().toString().replace("-", "");
        vo.setOut_trade_no(out_trade_no);
        // 帳號信息
        vo.setApp_id(APPID);
        vo.setMch_id(MCHID);
        vo.setKey(KEY);
        String currTime = PayToolUtil.getCurrTime();
        vo.setCurrTime(currTime);
        String strTime = currTime.substring(8, currTime.length());
        vo.setStrTime(strTime);
        String strRandom = String.valueOf(PayToolUtil.buildRandom(4));
        vo.setStrRandom(strRandom);
        String nonce_str = strTime + strRandom;
        vo.setNonce_str(nonce_str);
        vo.setSpbill_create_ip(CREATE_IP);
        vo.setNotify_url(NOTIFY_URL);
        vo.setTrade_type("NATIVE");
        String total_fee = "1";
        vo.setTotal_fee(total_fee);//價格的單位爲分

        SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
        packageParams.put("appid", APPID);//公衆帳號ID
        packageParams.put("mch_id", MCHID);//商戶號
        packageParams.put("nonce_str", nonce_str);//隨機字符串
        packageParams.put("body", "資源");  //商品描述
        packageParams.put("out_trade_no", out_trade_no);//商戶訂單號
        packageParams.put("total_fee", total_fee); //標價金額 訂單總金額,單位爲分
        packageParams.put("spbill_create_ip", CREATE_IP);//終端IP APP和網頁支付提交用戶端ip,Native支付填調用微信支付API的機器IP
        packageParams.put("notify_url", NOTIFY_URL);//通知地址 異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數
        packageParams.put("trade_type", "NATIVE");//交易類型 NATIVE 掃碼支付
        // 簽名
        String sign = PayToolUtil.createSign("UTF-8", packageParams, KEY);
        packageParams.put("sign", sign);

        // 將請求參數轉換爲xml格式的string
        String requestXML = PayToolUtil.getRequestXml(packageParams);
        logger.info("requestXML:{}", requestXML);

        // 調用微信支付統一下單接口
        String resXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML);
        logger.info("resXml: {}", resXml);

        // 解析微信支付結果
        Map map = null;
        try {
            map = XMLUtil4jdom.doXMLParse(resXml);
            logger.info("map: {}", map);
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 返回微信支付的二維碼鏈接
        urlCode = (String) map.get("code_url");
        logger.info("urlCode:{}", urlCode);

        try {
            int width = 300;
            int height = 300;
            //二維碼的圖片格式
            String format = "gif";
            Hashtable hints = new Hashtable();
            //內容所使用編碼
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            BitMatrix bitMatrix;
            bitMatrix = new MultiFormatWriter().encode(urlCode, BarcodeFormat.QR_CODE, width, height, hints);
            QRUtil.writeToStream(bitMatrix, format, response.getOutputStream());
        } catch (WriterException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 微信支付-回調
     * @param request
     * @param response
     */
    @PostMapping("/notify")
    public String wxpayNotify(HttpServletRequest request, HttpServletResponse response) {
        //讀取參數
        InputStream inputStream ;
        StringBuffer sb = null;
        try {
            sb = new StringBuffer();
            inputStream = request.getInputStream();
            String s ;
            BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            while ((s = in.readLine()) != null){
                sb.append(s);
            }
            in.close();
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //解析xml成map
        Map<String, String> map = new HashMap<String, String>();
        try {
            map = XMLUtil4jdom.doXMLParse(sb.toString());
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //過濾空 設置 TreeMap
        SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
        Iterator it = map.keySet().iterator();
        while (it.hasNext()) {
            String parameter = (String) it.next();
            String parameterValue = map.get(parameter);
            String v = "";
            if(null != parameterValue) {
                v = parameterValue.trim();
            }
            packageParams.put(parameter, v);
        }

        //判斷簽名是否正確
        if(PayToolUtil.isTenpaySign("UTF-8", packageParams, KEY)) {
            //------------------------------
            //處理業務開始
            //------------------------------
            String resXml = "";
            if("SUCCESS".equals((String)packageParams.get("result_code"))){
                // 這裏是支付成功
                //////////執行本身的業務邏輯////////////////
                String mch_id = (String)packageParams.get("mch_id");
                String openid = (String)packageParams.get("openid");
                String is_subscribe = (String)packageParams.get("is_subscribe");
                String out_trade_no = (String)packageParams.get("out_trade_no");

                String total_fee = (String)packageParams.get("total_fee");

                //////////執行本身的業務邏輯////////////////
                //暫時使用最簡單的業務邏輯來處理:只是將業務處理結果保存到session中
                //(根據本身的實際業務邏輯來調整,不少時候,咱們會操做業務表,將返回成功的狀態保留下來)
                request.getSession().setAttribute("_PAY_RESULT", "OK");

                logger.info("支付成功");

                //通知微信.異步確認成功.必寫.否則會一直通知後臺.八次以後就認爲交易失敗了.
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";

            } else {
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[報文爲空]]></return_msg>" + "</xml> ";
                return ("fail");
            }
            //------------------------------
            //處理業務完畢
            //------------------------------
            try {
                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                out.write(resXml.getBytes());
                out.flush();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } else{
            logger.info("通知簽名驗證失敗");
        }
        return ("success");
    }

}

五:訪問支付URLhttp://dvnq2b.natappfree.cc/wxpay/qrcode、回返回微信的支付二維碼,用戶經過微信的掃一掃,就能夠掃碼支付了、這裏注意:因爲微信回調須要能外網訪問的域名,因此咱們這裏使用了一個內網穿透工具natapp,具體怎麼實現內網穿透,直接官網就能夠了很簡單,這是附上natapp的官網地址:https://natapp.cn/、配置好內容穿透工具後,修改下微信回調的配置文件,以下:

## 微信支付配置 測試環境(若是須要測試,改爲本身的正式環境) ##
WXPAY.APPID=wx82b23234467t34347661
WXPAY.MCHID=1234dsdf5345
WXPAY.KEY=rtert345dfgh345fg34ddfg345fdg
WXPAY.APPSECRET=36546dfghdfgdszdfsdffg45354dfg
WXPAY.NOTIFY_URL= http://dvnq2b.natappfree.cc/wxpay/notify
WXPAY.CREATE_IP=192.168.0.190

訪問支付url返回微信二維碼,以下圖:

 

使用微信的掃一掃,掃碼支付,以下圖:

微信支付回調,以下圖:

這裏對於回調只是簡單輸出了日誌,你能夠根據本身的實際狀況選擇作相應的處理,通常都是對訂單的支付狀態作更新。

六:總結: 

通過上面的因此流程,相信你們都明白了微信支付的流程,這裏咱們對上面的流程作個總結,要想接入微信支付,必須是企業用戶才行,我的用戶不支持,因此在開始寫代碼以前,要和公司的相關負責人申請好微信支付的相關配置參數,有了這些才能進行下面的工做,這裏最重要的一點就是微信支付的回調了,回調,在生產環境必須配置能夠外網訪問的URL,同時域名必須是備案過的,二級域名也能夠,這裏咱們爲了方便測試,因此就使用了內網穿透工具natapp,該工具既有免費通道也有收費通道,收費通道也很便宜,若是隻是測試,免費通道就夠用了,另外還有一點要注意,就是微信支付的回調,默認微信是回調好幾回的,因此會有重複回調的問題,這裏留給你們一個思考,怎麼防止微信的屢次回調,以避免影響業務,但願有興趣的小夥伴能夠留言交流。以上就是微信支付(掃碼支付模式二)的所有內容了,有想要徹底源代碼的小夥伴,能夠加羣交流,羣號:715224124。

相關文章
相關標籤/搜索