微信公衆號支付詳細demo.前臺後臺都有,親測可以使用.

申請及配置在這裏:https://blog.csdn.net/dmw412724/article/details/82735906

目錄

一.後臺統一下單代碼:

1.常量類.這個不要修改.來自微信官方.

2.工具類,不要修改,來自微信官方

3.解析xml的工具類.來自微信官方,不要修改.

4.配置類.填上你自己的公衆號appid,商戶id和key

5.統一下單工具類.我寫好的,不需要修改,直接用就成了.

6.怎麼使用?就這樣使用

二. 前臺該怎麼寫?

1.jssdk寫法.

2.微信內置對象寫法

3.一些返回fail的坑?


一.後臺統一下單代碼:

需要5個類.修改自官方demo.官方demo有很多是用不上的.

1.常量類.這個不要修改.來自微信官方.

import org.apache.http.client.HttpClient;

/**
 * 常量
 */
public class WXPayConstants {

    public enum SignType {
        MD5, HMACSHA256
    }

    public static final String DOMAIN_API = "api.mch.weixin.qq.com";
    public static final String DOMAIN_API2 = "api2.mch.weixin.qq.com";
    public static final String DOMAIN_APIHK = "apihk.mch.weixin.qq.com";
    public static final String DOMAIN_APIUS = "apius.mch.weixin.qq.com";


    public static final String FAIL     = "FAIL";
    public static final String SUCCESS  = "SUCCESS";
    public static final String HMACSHA256 = "HMAC-SHA256";
    public static final String MD5 = "MD5";

    public static final String FIELD_SIGN = "sign";
    public static final String FIELD_SIGN_TYPE = "sign_type";

    public static final String WXPAYSDK_VERSION = "WXPaySDK/3.0.9";
    public static final String USER_AGENT = WXPAYSDK_VERSION +
            " (" + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version") +
            ") Java/" + System.getProperty("java.version") + " HttpClient/" + HttpClient.class.getPackage().getImplementationVersion();

    public static final String MICROPAY_URL_SUFFIX     = "/pay/micropay";
    public static final String UNIFIEDORDER_URL_SUFFIX = "/pay/unifiedorder";
    public static final String ORDERQUERY_URL_SUFFIX   = "/pay/orderquery";
    public static final String REVERSE_URL_SUFFIX      = "/secapi/pay/reverse";
    public static final String CLOSEORDER_URL_SUFFIX   = "/pay/closeorder";
    public static final String REFUND_URL_SUFFIX       = "/secapi/pay/refund";
    public static final String REFUNDQUERY_URL_SUFFIX  = "/pay/refundquery";
    public static final String DOWNLOADBILL_URL_SUFFIX = "/pay/downloadbill";
    public static final String REPORT_URL_SUFFIX       = "/payitil/report";
    public static final String SHORTURL_URL_SUFFIX     = "/tools/shorturl";
    public static final String AUTHCODETOOPENID_URL_SUFFIX = "/tools/authcodetoopenid";

    // sandbox
    public static final String SANDBOX_MICROPAY_URL_SUFFIX     = "/sandboxnew/pay/micropay";
    public static final String SANDBOX_UNIFIEDORDER_URL_SUFFIX = "/sandboxnew/pay/unifiedorder";
    public static final String SANDBOX_ORDERQUERY_URL_SUFFIX   = "/sandboxnew/pay/orderquery";
    public static final String SANDBOX_REVERSE_URL_SUFFIX      = "/sandboxnew/secapi/pay/reverse";
    public static final String SANDBOX_CLOSEORDER_URL_SUFFIX   = "/sandboxnew/pay/closeorder";
    public static final String SANDBOX_REFUND_URL_SUFFIX       = "/sandboxnew/secapi/pay/refund";
    public static final String SANDBOX_REFUNDQUERY_URL_SUFFIX  = "/sandboxnew/pay/refundquery";
    public static final String SANDBOX_DOWNLOADBILL_URL_SUFFIX = "/sandboxnew/pay/downloadbill";
    public static final String SANDBOX_REPORT_URL_SUFFIX       = "/sandboxnew/payitil/report";
    public static final String SANDBOX_SHORTURL_URL_SUFFIX     = "/sandboxnew/tools/shorturl";
    public static final String SANDBOX_AUTHCODETOOPENID_URL_SUFFIX = "/sandboxnew/tools/authcodetoopenid";

}

2.工具類,不要修改,來自微信官方

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import xx.WXPayConstants.SignType;


public class WXPayUtil {

    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final Random RANDOM = new SecureRandom();

    /**
     * XML格式字符串轉換爲Map
     *
     * @param strXML XML字符串
     * @return XML數據轉換後的Map
     * @throws Exception
     */
    public static Map<String, String> xmlToMap(String strXML) throws Exception {
        try {
            Map<String, String> data = new HashMap<String, String>();
            DocumentBuilder documentBuilder = WXPayXmlUtil.newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                stream.close();
            } catch (Exception ex) {
                // do nothing
            }
            return data;
        } catch (Exception ex) {
            WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
            throw ex;
        }

    }

    /**
     * 將Map轉換爲XML格式的字符串
     *
     * @param data Map類型數據
     * @return XML格式的字符串
     * @throws Exception
     */
    public static String mapToXml(Map<String, String> data) throws Exception {
        org.w3c.dom.Document document = WXPayXmlUtil.newDocument();
        org.w3c.dom.Element root = document.createElement("xml");
        document.appendChild(root);
        for (String key: data.keySet()) {
            String value = data.get(key);
            if (value == null) {
                value = "";
            }
            value = value.trim();
            org.w3c.dom.Element filed = document.createElement(key);
            filed.appendChild(document.createTextNode(value));
            root.appendChild(filed);
        }
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        DOMSource source = new DOMSource(document);
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        transformer.transform(source, result);
        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
        try {
            writer.close();
        }
        catch (Exception ex) {
        }
        return output;
    }


    /**
     * 生成帶有 sign 的 XML 格式字符串
     *
     * @param data Map類型數據
     * @param key API密鑰
     * @return 含有sign字段的XML
     */
    public static String generateSignedXml(final Map<String, String> data, String key) throws Exception {
        return generateSignedXml(data, key, SignType.MD5);
    }

    /**
     * 生成帶有 sign 的 XML 格式字符串
     *
     * @param data Map類型數據
     * @param key API密鑰
     * @param signType 簽名類型
     * @return 含有sign字段的XML
     */
    public static String generateSignedXml(final Map<String, String> data, String key, SignType signType) throws Exception {
        String sign = generateSignature(data, key, signType);
        data.put(WXPayConstants.FIELD_SIGN, sign);
        return mapToXml(data);
    }


    /**
     * 判斷簽名是否正確
     *
     * @param xmlStr XML格式數據
     * @param key API密鑰
     * @return 簽名是否正確
     * @throws Exception
     */
    public static boolean isSignatureValid(String xmlStr, String key) throws Exception {
        Map<String, String> data = xmlToMap(xmlStr);
        if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
            return false;
        }
        String sign = data.get(WXPayConstants.FIELD_SIGN);
        return generateSignature(data, key).equals(sign);
    }

    /**
     * 判斷簽名是否正確,必須包含sign字段,否則返回false。使用MD5簽名。
     *
     * @param data Map類型數據
     * @param key API密鑰
     * @return 簽名是否正確
     * @throws Exception
     */
    public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {
        return isSignatureValid(data, key, SignType.MD5);
    }

    /**
     * 判斷簽名是否正確,必須包含sign字段,否則返回false。
     *
     * @param data Map類型數據
     * @param key API密鑰
     * @param signType 簽名方式
     * @return 簽名是否正確
     * @throws Exception
     */
    public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType) throws Exception {
        if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
            return false;
        }
        String sign = data.get(WXPayConstants.FIELD_SIGN);
        return generateSignature(data, key, signType).equals(sign);
    }

    /**
     * 生成簽名
     *
     * @param data 待簽名數據
     * @param key API密鑰
     * @return 簽名
     */
    public static String generateSignature(final Map<String, String> data, String key) throws Exception {
        return generateSignature(data, key, SignType.MD5);
    }

    /**
     * 生成簽名. 注意,若含有sign_type字段,必須和signType參數保持一致。
     *
     * @param data 待簽名數據
     * @param key API密鑰
     * @param signType 簽名方式
     * @return 簽名
     */
    public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals(WXPayConstants.FIELD_SIGN)) {
                continue;
            }
            if (data.get(k).trim().length() > 0) // 參數值爲空,則不參與簽名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(key);
        if (SignType.MD5.equals(signType)) {
        	System.out.println("====|||"+sb.toString());
            return MD5(sb.toString()).toUpperCase();
        }
        else if (SignType.HMACSHA256.equals(signType)) {
            return HMACSHA256(sb.toString(), key);
        }
        else {
            throw new Exception(String.format("Invalid sign_type: %s", signType));
        }
    }


    /**
     * 獲取隨機字符串 Nonce Str
     *
     * @return String 隨機字符串
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }


    /**
     * 生成 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();
    }

    /**
     * 生成 HMACSHA256
     * @param data 待處理數據
     * @param key 密鑰
     * @return 加密結果
     * @throws Exception
     */
    public static String HMACSHA256(String data, String key) throws Exception {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] array = sha256_HMAC.doFinal(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();
    }

    /**
     * 日誌
     * @return
     */
    public static Logger getLogger() {
        Logger logger = LoggerFactory.getLogger("wxpay java sdk");
        return logger;
    }

    /**
     * 獲取當前時間戳,單位秒
     * @return
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis()/1000;
    }

    /**
     * 獲取當前時間戳,單位毫秒
     * @return
     */
    public static long getCurrentTimestampMs() {
        return System.currentTimeMillis();
    }

}

3.解析xml的工具類.來自微信官方,不要修改.

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;

/**
 * 2018/7/3
 */
public final class WXPayXmlUtil {
    public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        documentBuilderFactory.setXIncludeAware(false);
        documentBuilderFactory.setExpandEntityReferences(false);

        return documentBuilderFactory.newDocumentBuilder();
    }

    public static Document newDocument() throws ParserConfigurationException {
        return newDocumentBuilder().newDocument();
    }
}

4.配置類.填上你自己的公衆號appid,商戶id和key

public class WxPayConfig {
	
	public static final String APPID = "xxx";
	
	public static final String MCH_ID ="";
	
	public static final String KEY ="";
}

5.統一下單工具類.我寫好的,不需要修改具體邏輯,直接用就成了.當然你可以修改異常處理.這裏面異常都是拋的運行時異常.

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

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

/**
 * 微信公衆號支付
 * 
 * @author dmw
 *
 *         2018年9月17日
 */
public class WxMapPay {

	/**
	 * 這裏面放參數
	 */
	public Map<String, String> map;

	public static WxMapPay ready() {
		WxMapPay wxMapPay = new WxMapPay();
		Map<String, String> map = wxMapPay.map;
		map.put("appid", WxPayConfig.APPID);
		map.put("mch_id", WxPayConfig.MCH_ID);

		map.put("trade_type", "JSAPI");
		map.put("nonce_str", WXPayUtil.generateNonceStr());
		return wxMapPay;
	}

	/**
	 * 加入商品描述
	 * 
	 * @param nonce_str
	 * @return
	 */
	public WxMapPay setGoodsDiscription(String body) {
		map.put("body", body);
		return this;
	}

	/**
	 * 商品唯一訂單號
	 * 
	 * @param out_trade_no
	 * @return
	 */
	public WxMapPay setOutTradeNo(String out_trade_no) {
		map.put("out_trade_no", out_trade_no);
		return this;
	}

	/**
	 * 商品價格 單位分
	 * 
	 * @param total_fee
	 * @return
	 */
	public WxMapPay setTotalFee(int total_fee) {
		map.put("total_fee", Integer.toString(total_fee));
		return this;
	}

	/**
	 * 客戶端ip
	 * 
	 * @param spbill_create_ip
	 * @return
	 */
	public WxMapPay setClientIp(String spbill_create_ip) {
		map.put("spbill_create_ip", spbill_create_ip);
		return this;
	}

	/**
	 * 回調網址 異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數。
	 * 
	 * @param notify_url
	 * @return
	 */
	public WxMapPay setNotifyUrl(String notify_url) {
		map.put("notify_url", notify_url);
		return this;
	}

	/**
	 * 回調網址 異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數。
	 * 
	 * @param notify_url
	 * @return
	 */
	public WxMapPay setOpenid(String openid) {
		map.put("openid", openid);
		return this;
	}

	/**
	 * 填其他
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public WxMapPay other(String key, String value) {
		map.put(key, value);
		return this;
	}

	public WxMapPayResult go() {
		check();
		String xml;
		try {
			xml = WXPayUtil.generateSignedXml(map, WxPayConfig.KEY);
		} catch (Exception e1) {
			e1.printStackTrace();
			throw new RuntimeException("生成xml錯誤");
			
		}
		String repBody = http(xml);
		try {
			Map<String, String> xmltoMap = WXPayUtil.xmlToMap(repBody);
			return new WxMapPayResult(xmltoMap); 
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("返回結果解析錯誤");
		}
	}

	private String http(String body) {
		String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(RegistryBuilder
				.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory())
				.register("https", SSLConnectionSocketFactory.getSocketFactory()).build(), null, null, null);
		HttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager).build();

		HttpPost httpPost = new HttpPost(url);

		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(8 * 1000).setConnectTimeout(6 * 1000)
				.build();
		httpPost.setConfig(requestConfig);

		StringEntity postEntity = new StringEntity(body, "UTF-8");
		httpPost.addHeader("Content-Type", "text/xml");
		httpPost.setEntity(postEntity);
		
		try {
			HttpResponse httpResponse = httpClient.execute(httpPost);
			HttpEntity httpEntity = httpResponse.getEntity();
			return EntityUtils.toString(httpEntity, "UTF-8");
		} catch (Exception e) {
			throw new RuntimeException("支付發送錯誤!");
		}

	}

	private void check() {
		if (!map.containsKey("nonce_str")) {
			throw new RuntimeException("沒有nonce_str");
		}
		if (!map.containsKey("body")) {
			throw new RuntimeException("沒有body");
		}
		if (!map.containsKey("out_trade_no")) {
			throw new RuntimeException("沒有out_trade_no");
		}
		if (!map.containsKey("total_fee")) {
			throw new RuntimeException("沒有total_fee");
		}
		if (!map.containsKey("spbill_create_ip")) {
			throw new RuntimeException("沒有spbill_create_ip");
		}
		if (!map.containsKey("notify_url")) {
			throw new RuntimeException("沒有notify_url");
		}
		if (!map.containsKey("openid")) {
			throw new RuntimeException("沒有openid");
		}
	}

	public String get(String key) {
		return map.get(key);
	}

	private WxMapPay() {
		super();
		map = new HashMap<>();
	}
	
	public class WxMapPayResult{
		private boolean reflag;
		private Map<String,String> map;
		
		
		
		public WxMapPayResult(Map<String, String> map) {
			super();
			this.map = map;
		}
		public boolean isHttpOk(){
			String return_code = map.get("return_code");
			if (return_code == null || !return_code.equals(WXPayConstants.SUCCESS)){
				return false;
			}
			return true;
		}
		public boolean isTradeOk(){
			String result_code = map.get("result_code");
			if (result_code == null || !result_code.equals(WXPayConstants.SUCCESS)){
				return false;
			}
			return true;
		}
		
		public Map<String,String> reSign(){
			if (!reflag){
				String prepay_id = map.get("prepay_id");
				map.clear();
				map.put("appId", WxPayConfig.APPID);
				map.put("timeStamp", Long.toString(WXPayUtil.getCurrentTimestamp()));
				map.put("package", "prepay_id="+prepay_id);
				map.put("nonceStr", WXPayUtil.generateNonceStr());
				map.put("signType", "MD5");
				String signature = null;
				try {
					signature = WXPayUtil.generateSignature(map, WxPayConfig.KEY);
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException("簽名錯誤了又");
				}
				map.put("paySign", signature);
				reflag = true;
				return map;
			}
			throw new RuntimeException("已經重新生成了,不能再生成");
		}
	}
}

6.怎麼使用?就這樣使用

WxMapPayResult result = 
				WxMapPay
				//初始化,加載配置
				.ready()
				//設置客戶端ip
				.setClientIp(remoteAddr)
				//設置商品描述
				.setGoodsDiscription("團購")
				//設置回調通知
				.setNotifyUrl("http://你的交易成功通知url")
				//設置openid
				.setOpenid(openid)
				//設置本地的訂單編號
				.setOutTradeNo(id)
				//設置交易金額,但位分
				.setTotalFee(1).
				//下單去
				go();
		/**
		 * 如果http請求狀態,且交易狀態ok
		 */
		if (result.isHttpOk() && result.isTradeOk()){
			//返回前臺需要的加密數據
			Map<String, String> map = result.reSign();
		}

說明:

1. WxMapPay的構造是私有的,你只能使用靜態ready()來初始化加載配置,然後去設置必須要設置的一些屬性.比如手機端的客戶端ip,商品描述,回調通知啊等.如果你還想添加其他的,這裏面有一個other(String key,String value)方法,請根據自行需要和微信開發文檔來添加.必須設置的屬性的方法名都是以set開頭的,所以你很容易把他們一個個給找到.如果你set不完,程序會自動檢查報錯的.

2.關於客戶端的ip.必須是真實ip,請注意如果你使用了nginx,要記得把真實ip傳過來.否則微信可能檢查ip拒絕調起支付窗口.

3.WxMapPayResult  有兩個ok狀態,一個是http狀態ok,一個是統一下單狀態ok,這倆你都得判斷.

4.返回的map裏包括了

appId,

timeStamp,

nonceStr,

package,

signType,

paySign

這六個內容,如果你看了微信jsapi的支付就應該明白,這六個正好是所需要的.

然後把這個map傳遞到前臺就行了.

5.設置set商品描述時.它有它固有的名字規則.請看.

二. 前臺該怎麼寫?

兩種寫法.一種是使用微信jssdk.一種是直接使用微信內置瀏覽器對象.它倆什麼關係?應該是jssdk裏引用了微信內置瀏覽器對象吧.

使用微信內置瀏覽器對象就意味着必須在微信裏才能使用.這並不是在其他應用裏喚醒微信並打開微信支付 .

1.jssdk寫法.

這個是在使用jssdk需要進行初始化驗籤保證安全.這個大家都清楚.如果不懂,那麼去看另外一種方法吧.

wx.config({
				    //debug: true,
				appId: "", 
				timestamp: "", 
				nonceStr: "", 
				signature: "",
				jsApiList: ["chooseWXPay"] 
			});	

你還要引入一個js.微信的js

 <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

驗完後調用這個就行了.

 wx.chooseWXPay({
	appId: data.body.appId,
	timestamp: data.body.timeStamp,
        nonceStr: data.body.nonceStr,
	package: data.body.package, 
	signType: data.body.signType, 
	paySign: data.body.paySign,								
	success: function (res) {
		alert("成功");	
	},
	fail: function(res) {
		alert('fail--'+JSON.stringify(res))
	},
	complete: function(res) {
		alert('complete--'+JSON.stringify(res))
	}
									
})  

這個裏面.data.body.xxx就是上面那1.6裏說的那個map裏面的值.

不管怎樣,都會走complete方法.

如果用戶確認支付了,會走success方法.

如果調用api錯誤了.那麼會走fail方法.

2.微信內置對象寫法

WeixinJSBridge.invoke(
     'getBrandWCPayRequest',
      {
        "appId":data.body.appId,     //公衆號名稱,由商戶傳入     
        "timeStamp":data.body.timeStamp,         //時間戳,自1970年以來的秒數     
        "nonceStr":data.body.nonceStr, //隨機串     
        "package":data.body.package,     
        "signType":data.body.signType,         //微信簽名方式:     
        "paySign":data.body.paySign //微信簽名 
     },
     function(res){
      if(res.err_msg == "get_brand_wcpay_request:ok" ){
      		// 使用以上方式判斷前端返回,微信團隊鄭重提示:
            //res.err_msg將在用戶支付成功後返回ok,但並不保證它絕對可靠。
       }
   }
);   

這個裏面.data.body.xxx就是上面那1.6裏說的那個map裏面的值.

3.一些返回fail的坑?

1.對於安卓來說,不管什麼都是fail.所以請使用ios來調試,ios會告訴你到底怎麼回事.

2.微信支付授權目錄要配置正確(我目前是沒有這個問題的).timeStamp是要大寫的,但如果你用了我的工具類,也是不會出現這樣的問題的..

3.客戶端ip要真實.

4.如果使用jssdk寫法.請引入jweixin-1.0.0.js

5.如果ios調試沒有問題,而安卓有問題(或部分機型有問題?),那麼你應該使用的是jssdk,你引入的那個jweixin-1.0.0.js放在了下面,應該把這條js放到最上面來引用.

三.回調

public String notifyUrlByWx(HttpServletRequest request) throws Exception {
        String notifyData = WebUtils.getPostBody(request);//獲取輸入流xml字符串
		Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData); // 轉換成map
		if (WXPayUtil.isSignatureValid(notifyMap, WxPayConfig.KEY)) {
			// 簽名正確
			// 進行處理。
			// 注意特殊情況:訂單已經退款,但收到了支付結果成功的通知,不應把商戶側訂單狀態從退款改成支付成功			
			String resultCode = notifyMap.get("result_code");
			if (resultCode.equals("SUCCESS")){
				//處理業務邏輯
                
                //返回
				return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";

				
			}else{
				//如果支付失敗
			}
		} else {
			// 簽名錯誤,如果數據裏沒有sign字段,也認爲是簽名錯誤
		}
		return "error";
	}

 

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