微信支付的Demo

是在一个子项目完成的,

依赖:

 

        
            org.springframework.boot
            spring-boot-starter-web
        


        
            org.apache.httpcomponents
            httpclient
            4.5.3
        

        
            org.slf4j
            slf4j-api
            1.7.21
        

        
            org.slf4j
            slf4j-simple
            1.7.21
        
        
            com.google.zxing
            core
            3.1.0
        
        
            com.google.zxing
            javase
            3.1.0
        

        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
    

下面是工具类:

WXPayConstants工具类
package com.sdk.pay.wechat;

import org.apache.http.client.HttpClient;


public class WXPayConstants {
    //商户密钥
    public static final String APP_KEY = "sbNCm1JnevqI36LrEaxFwcaT0hkGxFnC";
    //商户id
    public static final String MCH_ID = "1497984412";
    //APPid
    public static final String APP_ID = "wx632c8f211f8122c6";
    public static final String URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    //回调地址要写自己的 28k6010n77.wicp.vip这个是做了内网穿透
    public static final String NOTIFY_URL = "28k6010n77.wicp.vip/wxcallback.html";
    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";
}
WXPayUtil工具类
package com.sdk.pay.wechat;

import com.sdk.pay.wechat.WXPayConstants.SignType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

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 java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.*;


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 xmlToMap(String strXML) throws Exception {
        try {
            Map data = new HashMap();
            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 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 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 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 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 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 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 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 data, String key, SignType signType) throws Exception {
        Set 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)) {
            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 {
        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();
    }
}

 

WXPayXmlUtil工具类
package com.sdk.pay.wechat;

import org.w3c.dom.Document;

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


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();
    }
}
HttpsHandler工具类
package com.sdk.pay.util;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class HttpsHandler {

    public static void trustAllHttpsCertificates() throws Exception {
        TrustManager[] tm_array=new TrustManager[1];
        TrustManager tm=new myTrustManager();
        tm_array[0]=tm;
        SSLContext sc=SSLContext.getInstance("SSL");
        sc.init(null, tm_array, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    public static class myTrustManager implements TrustManager, X509TrustManager {

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
            return;
        }

        public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
            return;
        }
    }
}
HTTPUtil工具类
package com.sdk.pay.util;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HTTPUtil {


    public static String httpPost(String urlStr, String params, String charSet) {
        HttpURLConnection httpConn = null;
        try {
            byte[] data = params.getBytes(charSet);
            URL url = new URL(urlStr);
            httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setRequestMethod("POST");
            httpConn.setRequestProperty("ContentType", "application/x-www-form-urlencoded");
            httpConn.setRequestProperty("Content-Length", String.valueOf(data.length));
            httpConn.setDoInput(true);
            httpConn.setDoOutput(true);
            // System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//jdk1.4换成这个,连接超时
            // System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //jdk1.4换成这个,读操作超时
            httpConn.setConnectTimeout(30000);// jdk 1.5换成这个,连接超时
            httpConn.setReadTimeout(30000);// jdk 1.5换成这个,读操作超时
            httpConn.connect();
            OutputStream os1 = httpConn.getOutputStream();
            os1.write(data);
            os1.flush();
            os1.close();
            return getResponseResult(httpConn, urlStr, charSet);
        } catch (Exception ex) {
            if (ex instanceof java.net.ConnectException || ex instanceof java.net.SocketTimeoutException) {
                NetUtil.clearDNSCache();
            }
        } finally {
            if (null != httpConn) {
                httpConn.disconnect();
            }
        }
        return null;
    }


    public static String httpsPost(String urlStr, String params, String charSet) {
        HttpsURLConnection httpsConn = null;
        try {
            byte[] data = params.getBytes(charSet);
            URL url = new URL(urlStr);
            HttpsHandler.trustAllHttpsCertificates();
            HostnameVerifier hv = new HostnameVerifier() {

                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
            };
            HttpsURLConnection.setDefaultHostnameVerifier(hv);
            httpsConn = (HttpsURLConnection) url.openConnection();
            httpsConn.setRequestMethod("POST");
            httpsConn.setRequestProperty("ContentType", "application/x-www-form-urlencoded");
            httpsConn.setRequestProperty("Content-Length", String.valueOf(data.length));
            httpsConn.setDoInput(true);
            httpsConn.setDoOutput(true);
            httpsConn.setConnectTimeout(30000);// jdk 1.5换成这个,连接超时
            httpsConn.setReadTimeout(30000);// jdk 1.5换成这个,读操作超时
            httpsConn.connect();
            OutputStream os1 = httpsConn.getOutputStream();
            os1.write(data);
            os1.flush();
            os1.close();
            return getResponseResult(httpsConn, urlStr, charSet);
        } catch (Exception ex) {
            if (ex instanceof java.net.ConnectException || ex instanceof java.net.SocketTimeoutException) {
                NetUtil.clearDNSCache();
            }
        } finally {
            if (null != httpsConn) {
                httpsConn.disconnect();
            }
        }
        return null;
    }

    public static String httpPostJson(String urlStr, String params, String charSet) {
        HttpURLConnection httpConn = null;
        try {
            httpConn = (HttpURLConnection) ((new URL(urlStr).openConnection()));
            httpConn.setDoOutput(true);
            httpConn.setRequestProperty("Content-Type", "application/json");
            httpConn.setRequestProperty("Accept", "application/json");
            httpConn.setRequestMethod("POST");
            httpConn.connect();
            byte[] outputBytes = params.getBytes(charSet);
            OutputStream os = httpConn.getOutputStream();
            os.write(outputBytes);
            os.close();
            return getResponseResult(httpConn, urlStr, charSet);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != httpConn) {
                httpConn.disconnect();
            }
        }
        return null;
    }

    /**
     * 发送json字符
     *
     * @param urlStr
     * @param params
     * @param charSet
     * @param header
     * @param headerVal
     * @return
     */
    public static String httpPostJson(String urlStr, String params, String charSet, String header, String headerVal) {
        HttpURLConnection httpConn = null;
        try {
            httpConn = (HttpURLConnection) ((new URL(urlStr).openConnection()));
            httpConn.setDoOutput(true);
            httpConn.setRequestProperty("Content-Type", "application/json");
            httpConn.setRequestProperty("Accept", "application/json");
            if (header != null && header.trim().length() > 0) {
                httpConn.setRequestProperty(header, headerVal);
            }
            httpConn.setRequestMethod("POST");
            httpConn.connect();
            byte[] outputBytes = params.getBytes(charSet);
            OutputStream os = httpConn.getOutputStream();
            os.write(outputBytes);
            os.close();
            return getResponseResult(httpConn, urlStr, charSet);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != httpConn) {
                httpConn.disconnect();
            }
        }
        return null;
    }

//    /**
//     * post过去的参数分成不同的域发送过去
//     * @param urlStr
//     * @param params
//     * @param charSet
//     * @return
//     */
//    public static String httpPost(String urlStr, Map params, String charSet) {
//        HttpURLConnection httpConn=null;
//        try {
//            String paramstring= ParameterUtil.mapToUrlString(params);
//            URL url=new URL(urlStr);
//            httpConn=(HttpURLConnection)url.openConnection();
//            httpConn.setRequestMethod("POST");
//            httpConn.setRequestProperty("ContentType", "application/x-www-form-urlencoded");
//            httpConn.setRequestProperty("Content-Length", String.valueOf(paramstring.length()));
//            httpConn.setDoInput(true);
//            httpConn.setDoOutput(true);
//            // System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//jdk1.4换成这个,连接超时
//            // System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //jdk1.4换成这个,读操作超时
//            httpConn.setConnectTimeout(30000);// jdk 1.5换成这个,连接超时
//            httpConn.setReadTimeout(30000);// jdk 1.5换成这个,读操作超时
//            httpConn.connect();
//            OutputStream os1=httpConn.getOutputStream();
//            Iterator it=params.keySet().iterator();
//            int size=params.keySet().size();
//            int i=1;
//            while(it.hasNext()){
//                String andStr="&";
//                if(i==size){
//                    andStr="";
//                }
//                String key=it.next();
//                String val=params.get(key);
//                byte[] data=(key+"="+URLEncoder.encode(val, "utf-8")+ andStr).getBytes();
//                os1.write(data);
//            }
//            os1.flush();
//            os1.close();
//            return getResponseResult(httpConn, urlStr, charSet);
//        } catch(Exception ex) {
//            if(ex instanceof java.net.ConnectException || ex instanceof java.net.SocketTimeoutException) {
//                com.sdk.pay.util.NetUtil.clearDNSCache();
//            }
//            logger.error(urlStr, ex);
//        } finally {
//            if(null != httpConn) {
//                httpConn.disconnect();
//            }
//        }
//        return null;
//    }

    public static String httpGet(String urlStr, String params, String charSet) {
        HttpURLConnection httpConn = null;
        try {
            if (null != params && params.length() > 0) {
                if (urlStr.indexOf("?") == -1) {
                    urlStr += "?" + params;
                } else {
                    urlStr += "&" + params;
                }
            }
            URL url = new URL(urlStr);
            httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setRequestMethod("GET");
            httpConn.setRequestProperty("ContentType", "application/x-www-form-urlencoded");
            httpConn.setDoInput(true);
            httpConn.setDoOutput(true);
            // System.setProperty("sun.net.client.defaultConnectTimeout", "30000");//jdk1.4换成这个,连接超时
            // System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //jdk1.4换成这个,读操作超时
            httpConn.setConnectTimeout(30000);// jdk 1.5换成这个,连接超时
            httpConn.setReadTimeout(30000);// jdk 1.5换成这个,读操作超时
            httpConn.connect();
            return getResponseResult(httpConn, urlStr, charSet);
        } catch (Exception ex) {
            if (ex instanceof java.net.ConnectException || ex instanceof java.net.SocketTimeoutException) {
                NetUtil.clearDNSCache();
            }
            ex.printStackTrace();
        } finally {
            if (null != httpConn) {
                httpConn.disconnect();
            }
        }
        return null;
    }

    public static String httpsGet(String urlStr, String params, String charSet) {
        HttpsURLConnection httpsConn = null;
        try {
            if (null != params && params.length() > 0) {
                if (urlStr.indexOf("?") == -1) {
                    urlStr += "?" + params;
                } else {
                    urlStr += "&" + params;
                }
            }
            byte[] data = params.getBytes(charSet);
            URL url = new URL(urlStr);
            HttpsHandler.trustAllHttpsCertificates();
            HostnameVerifier hv = new HostnameVerifier() {

                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
            };
            HttpsURLConnection.setDefaultHostnameVerifier(hv);
            httpsConn = (HttpsURLConnection) url.openConnection();
            httpsConn.setRequestMethod("GET");
            httpsConn.setRequestProperty("ContentType", "application/x-www-form-urlencoded");
            httpsConn.setRequestProperty("Content-Length", String.valueOf(data.length));
            httpsConn.setDoInput(true);
            httpsConn.setDoOutput(true);
            httpsConn.setConnectTimeout(30000);// jdk 1.5换成这个,连接超时
            httpsConn.setReadTimeout(30000);// jdk 1.5换成这个,读操作超时
            httpsConn.connect();
            OutputStream os1 = httpsConn.getOutputStream();
            os1.write(data);
            os1.flush();
            os1.close();
            return getResponseResult(httpsConn, urlStr, charSet);
        } catch (Exception ex) {
            if (ex instanceof java.net.ConnectException || ex instanceof java.net.SocketTimeoutException) {
                NetUtil.clearDNSCache();
            }
            ex.printStackTrace();
        } finally {
            if (null != httpsConn) {
                httpsConn.disconnect();
            }
        }
        return null;
    }

    private static String getResponseResult(HttpURLConnection httpConn, String urlStr, String charSet) throws IOException {
        String res = null;
        // 获得响应状态
        int responseCode = httpConn.getResponseCode();
        if (HttpURLConnection.HTTP_OK == responseCode) {
            byte[] buffer = new byte[1024];
            int len = -1;
            InputStream is = httpConn.getInputStream();
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            while ((len = is.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            res = bos.toString(charSet);
            is.close();
            bos.close();
            System.out.println(urlStr + " Response Code:" + responseCode + " content:" + res);
        } else {
            System.out.println(urlStr + " Response Code:" + responseCode);
        }
        return res;
    }

}
NetUtil工具类
package com.sdk.pay.util;

import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;

public class NetUtil {

    @SuppressWarnings("unchecked")
    public static void clearDNSCache() {
        try {
            Class clazz=java.net.InetAddress.class;
            final Field cacheField=clazz.getDeclaredField("addressCache");
            cacheField.setAccessible(true);
            final Object o=cacheField.get(clazz);
            Class clazz2=o.getClass();
            // final Field cachePolicyField = clazz2.getDeclaredField("policy");
            final Field cacheMapField=clazz2.getDeclaredField("cache");
            cacheMapField.setAccessible(true);
            final Map cacheMap=(Map)cacheMapField.get(o);
            // cachePolicyField.setAccessible(true);
            AccessController.doPrivileged(new PrivilegedAction() {

                public Object run() {
                    try {
                        synchronized(o) {// 同步是必须的,因为o可能会有多个线程同时访问修改。
                            cacheMap.clear();// 这步比较关键,用于清除原来的缓存
                            // cachePolicyField.setInt(o,0);//设置缓存的时间,单位秒(-1,永久缓存;0,不缓存;其它>0的值为缓存的秒数)
                        }
                    } catch(Throwable te) {
                        throw new RuntimeException(te);
                    }
                    return null;
                }
            });
        } catch(Exception ex) {
        }
    }
} 
  
 
QRCodeUtil工具类
package com.sdk.pay.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.awt.image.BufferedImage;
import java.util.Hashtable;


public class QRCodeUtil {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 300;
    // LOGO宽度
    private static final int WIDTH = 60;
    // LOGO高度
    private static final int HEIGHT = 60;

    public static BufferedImage createImage(String content) throws Exception {
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
                BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.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, bitMatrix.get(x, y) ? 0xFF000000
                        : 0xFFFFFFFF);
            }
        }
        return image;
    }

}
WchatController Controller层
package com.sdk.pay.controller;

import com.sdk.pay.util.HTTPUtil;
import com.sdk.pay.util.QRCodeUtil;
import com.sdk.pay.wechat.WXPayConstants;
import com.sdk.pay.wechat.WXPayUtil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;


@Controller
public class WchatController {
    @RequestMapping("wechat.html")
    public String wechat(Integer amount, Model model) {
        if (amount != null) {
            Map data = new HashMap<>();
            data.put("appid", WXPayConstants.APP_ID);
            data.put("mch_id", WXPayConstants.MCH_ID);
            //随机字符串 这里用时间戳代替
            data.put("nonce_str", System.currentTimeMillis() + "");
            //商品描述
            data.put("body", "年货");
            //商户订单号 商户系统内部订单号,要求32个字符内,
            // 只能是数字、大小写字母_-|* 且在同一个商户号下唯一。
            // 这里用时间戳代替
            data.put("out_trade_no", System.currentTimeMillis() + "");
            //标价金额 订单总金额,单位为分,详见支付金额
            data.put("total_fee", amount.toString());
            //终端IP 支持IPV4和IPV6两种格式的IP地址。用户的客户端IP
            data.put("spbill_create_ip", "10.9.45.62");//从request中获取
            //通知地址
            //异步接收微信支付结果通知的回调地址,
            // 通知url必须为外网可访问的url,不能携带参数。自己测试需要做内网穿透
            data.put("notify_url", WXPayConstants.NOTIFY_URL);
            //交易类型 NATIVE -Native支付
            data.put("trade_type", "NATIVE ");
            try {
                //封装好的生成XML的工具类 把数据封装到map里面就可以生成了
                String xml = WXPayUtil.generateSignedXml(data, WXPayConstants.APP_KEY);
                System.out.println(xml);

                String res = HTTPUtil.httpPost(WXPayConstants.URL, xml, "utf-8");

                Map result = WXPayUtil.xmlToMap(res);

                model.addAttribute("code_url", result.get("code_url"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return "wechat";
    }

    @RequestMapping("code.html")
    public void code(HttpServletResponse response, String code) {
        if (code == null) {
            return;
        }
        try {
            BufferedImage img = QRCodeUtil.createImage(code);
            ImageIO.write(img, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    String OK = " ";
    String ERROR = " ";

    @RequestMapping("wxcallback.html")
    public void callback(HttpServletRequest request, HttpServletResponse response) {
        String line = null;
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
            StringBuilder builder = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            String xml = builder.toString();//微信通知结果
            System.out.println(xml);
            Map data = WXPayUtil.xmlToMap(xml);
            if ("SUCCESS".equals(data.get("return_code"))) {//成功
                //校验签名
                boolean check = WXPayUtil.isSignatureValid(xml, WXPayConstants.APP_KEY);
                if (check) {//签名正确
                    //更新订单
                    System.out.println("订单号:"+data.get("out_trade_no"));
                    System.out.println("微信订单号:"+data.get("transaction_id"));
                    System.out.println("收到金额:"+data.get("cash_fee"));
                    System.out.println("支付状态:"+data.get("result_code"));
                    response.getWriter().write(OK);
                } else {//签名错误
                    response.getWriter().write(ERROR);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            response.getWriter().flush();
            response.getWriter().close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

页面 chat.html

 1 DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Titletitle>
 6 head>
 7 <body>
 8 <form action="wechat.html" method="post">
 9     金额<input name="amount"/>
10     <input type="submit" value="提交"/>
11 form>
12 <img th:src="${'code.html?code='+code_url}">
13 body>
14 html>

你可能感兴趣的:(微信支付的Demo)