Java微信支付快速入门&工具类

时间:2022-04-29
本文章向大家介绍Java微信支付快速入门&工具类,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

快速入门

1、微信支付官方在线API入口: https://pay.weixin.qq.com/wiki/doc/api/index.html 2、微信支付能力介绍: http://action.weixin.qq.com/payact/readtemplate?t=mobile/merchant/ability_tmpl 3、DEMO下载: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

4、微信支付相关平台:

商户平台 https://pay.weixin.qq.com/ 开放平台 https://open.weixin.qq.com/ 公众平台 https://mp.weixin.qq.com/

需要关注点:

1、随机字符串的生成方式;

2、sign签名的生成方式;

3、请求报文的组装方式;

4、httpclient的应用方式,特别是退款申请要使用双向证书验证(ssl);

5、对于返回报文的解析,比如对账接口情况失败情况是xml格式,而成功则是文本表格格式;

以下是工具类;需要用到httpclient4.3.4

package sven.util;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.apache.http.client.ClientProtocolException;

/**
 * 微信支付工具类
 * 
 * @author 蔡政滦
 * @version 2015年8月2日
 */
public class WxUtils {

    /**
     * 随机字符串,不长于32 位
     * 
     * @return
     * @author 蔡政滦 modify by 2015年8月2日
     */
    public static String randomStr() {
        String template = "abcdefghijklmnopqrstuvwxyz0123456789";
        StringBuffer buffer = new StringBuffer();
        Random random = new Random();
        while (buffer.length() < 32) {
            int index = random.nextInt(36);
            char c = template.charAt(index);
            buffer.append(c);
        }
        return buffer.toString();
    }

    /**
     * 签名
     * 
     * @param map 数据
     * @param password 密钥
     * @return
     * @author 蔡政滦 modify by 2015年8月2日
     * @throws Exception 
     */
    public static String getSign(Map<String, Object> map, String password) throws Exception {
        return getSign(map, password, "");
    }
    
    /**
     * 签名
     * 
     * @param map 数据
     * @param password 密钥
     * @param ignore_keys 忽略的key
     * @return
     * @author 蔡政滦 modify by 2015年8月2日
     * @throws Exception 
     */
    public static String getSign(Map<String, Object> map, String password, String... ignore_keys) throws Exception {
        String result = "";
        ArrayList<String> list = new ArrayList<String>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            /*if (StringUtils.isNotEmpty(ignore_key) && ignore_key.equals(entry.getKey())) {
                continue;
            }*/
            if (ignore_keys != null) {
                for (int i = 0; i < ignore_keys.length; i++) {
                    if (ignore_keys[i].equals(entry.getKey())) {
                        continue;
                    }
                }
            }
            if (entry.getValue() != null && !"".equals(entry.getValue())) {
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        if (size > 0) {
            String[] arrayToSort = list.toArray(new String[size]);
            Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < size; i++) {
                sb.append(arrayToSort[i]);
            }
            result = sb.toString();
            result += "key=" + password;
            result = PayUtils.md5Digest(result);
            result = result.toUpperCase();
        }
        return result;
    }

    /**
     * 组装请求数据字符串
     * 
     * @param postData 请求数据
     * @return
     * @author 蔡政滦 modify by 2015年8月2日
     */
    public static String toXml(Map<String, String> postData) {
        return HttpsUtils.toXml("xml", postData);
    }

    /**
     * 提交http请求,获取响应数据字符串
     * 
     * @param url 请求URL
     * @param xml 请求数据字符串
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @author 蔡政滦 modify by 2015年8月2日
     */
    public static String postXml(String url, String xml) throws Exception {
        Map<String, String> headerInfo = new HashMap<String, String>();
        headerInfo.put("Content-Type", "text/xml");
        headerInfo.put("Connection", "keep-alive");
        headerInfo.put("Accept", "*/*");
        headerInfo.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        headerInfo.put("Host", "api.mch.weixin.qq.com");
        headerInfo.put("X-Requested-With", "XMLHttpRequest");
        headerInfo.put("Cache-Control", "max-age=0");
        headerInfo.put("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
        return HttpsUtils.postXml(url, headerInfo, xml);
    }

    /**
     * 提交https请求,获取响应数据字符串
     * 
     * @param url 请求URL
     * @param xml 请求数据字符串
     * @keyStorePath 证书存放路径
     * @keysecret 证书密码
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @author 蔡政滦 modify by 2015年8月2日
     */
    public static String postXmlSSL(String url, String xml, String keyStorePath, String keysecret) throws IllegalStateException, IOException, Exception {
        Map<String, String> headerInfo = new HashMap<String, String>();
        headerInfo.put("Content-Type", "text/xml");
        headerInfo.put("Connection", "keep-alive");
        headerInfo.put("Accept", "*/*");
        headerInfo.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        headerInfo.put("Host", "api.mch.weixin.qq.com");
        headerInfo.put("X-Requested-With", "XMLHttpRequest");
        headerInfo.put("Cache-Control", "max-age=0");
        headerInfo.put("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
        return HttpsUtils.postXmlSSL(url, headerInfo, xml, keyStorePath, keysecret);
    }
}

  https工具类:

package sven.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.util.Iterator;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

/**
 * https工具类
 * 
 * @author SvenAugustus(蔡政滦)  e-mail: SvenAugustus@outlook.com
 * @version 2015年8月13日
 */
public class HttpsUtils {

    /**
     * 组装请求数据字符串
     * 
     * @param rootElement 根元素名称
     * @param postData 请求数据
     * @return
     * @author SvenAugustus(蔡政滦)  e-mail: SvenAugustus@outlook.com modify by 2015年8月2日
     */
    public static String toXml(String rootElement, Map<String, String> postData) {
        Element root = DocumentHelper.createElement(rootElement);
        Document document = DocumentHelper.createDocument(root);
        Iterator it = postData.keySet().iterator();
        while (it.hasNext()) {
            String key = (String) it.next();
            String value = postData.get(key);
            Element element = root.addElement(key);
            element.addCDATA(StringUtils.isEmpty(value) ? "" : value);
        }
        return document.asXML();
    }

    /**
     * 提交http请求,获取响应数据字符串
     * 
     * @param url 请求URL
     * @headerInfo 请求头信息
     * @param xml 请求数据字符串
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @author SvenAugustus(蔡政滦)  e-mail: SvenAugustus@outlook.com modify by 2015年8月2日
     */
    public static String postXml(String url, Map<String, String> headerInfo, String xml) throws Exception {
        // httpclient 4.2.2
        //        String result = "";
        //
        //        HttpClient httpclient = new DefaultHttpClient();
        //        HttpPost pmethod = new HttpPost(url); // 设置响应头信息
        //        pmethod.addHeader("Connection", "keep-alive");
        //        pmethod.addHeader("Accept", "*/*");
        //        pmethod.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        //        pmethod.addHeader("Host", "api.mch.weixin.qq.com");
        //        pmethod.addHeader("X-Requested-With", "XMLHttpRequest");
        //        pmethod.addHeader("Cache-Control", "max-age=0");
        //        pmethod.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
        //        pmethod.setEntity(new StringEntity(xml, "UTF-8"));
        //
        //        HttpResponse response = httpclient.execute(pmethod);
        //        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
        //            result = EntityUtils.toString(response.getEntity(), "UTF-8");
        //        }
        //        return result;
        //return HttpsUtils.httpRequest(url, "POST", xml, "utf-8");

        // httpclient 4.3.4
        String result = null;
        HttpEntity postEntity = new StringEntity(xml, "utf-8");
        HttpPost httpPost = new HttpPost(url);
        //        httpPost.addHeader("Content-Type", "text/xml");
        //        httpPost.addHeader("Connection", "keep-alive");
        //        httpPost.addHeader("Accept", "*/*");
        //        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        //        httpPost.addHeader("Host", "api.mch.weixin.qq.com");
        //        httpPost.addHeader("X-Requested-With", "XMLHttpRequest");
        //        httpPost.addHeader("Cache-Control", "max-age=0");
        //        httpPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
        if (headerInfo != null) {
            Iterator it = headerInfo.keySet().iterator();
            while (it.hasNext()) {
                String name = (String) it.next();
                String value = headerInfo.get(name);
                httpPost.addHeader(name, value);
            }
        }
        httpPost.setEntity(postEntity);

        CloseableHttpClient httpclient = HttpClients.custom().build();
        try {
            HttpResponse response = httpclient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            /*if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                String location = response.getFirstHeader("Location").getValue();
                return get(location);
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }*/
            if (statusCode == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    result = EntityUtils.toString(entity, "utf-8");
                }
            }
        } finally {
            httpclient.close();
        }
        return result;
    }

    /**
     * 提交https请求,获取响应数据字符串
     * 
     * @param url 请求URL
     * @headerInfo 请求头信息
     * @param xml 请求数据字符串
     * @keyStorePath 证书存放路径
     * @keysecret 证书密码
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @author SvenAugustus(蔡政滦)  e-mail: SvenAugustus@outlook.com modify by 2015年8月2日
     */
    public static String postXmlSSL(String url, Map<String, String> headerInfo, String xml, String keyStorePath, String keysecret)
            throws IllegalStateException, IOException, Exception {
        // httpclient 4.3.4 支持ssl / https
        String result = null;
        if (com.ztesoft.common.util.StringUtils.isNotEmpty(keyStorePath) && com.ztesoft.common.util.StringUtils.isNotEmpty(keysecret)) {
            HttpEntity postEntity = new StringEntity(xml, "utf-8");
            HttpPost httpPost = new HttpPost(url);
            //        httpPost.addHeader("Content-Type", "text/xml");
            //        httpPost.addHeader("Connection", "keep-alive");
            //        httpPost.addHeader("Accept", "*/*");
            //        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            //        httpPost.addHeader("Host", "api.mch.weixin.qq.com");
            //        httpPost.addHeader("X-Requested-With", "XMLHttpRequest");
            //        httpPost.addHeader("Cache-Control", "max-age=0");
            //        httpPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            if (headerInfo != null) {
                Iterator it = headerInfo.keySet().iterator();
                while (it.hasNext()) {
                    String name = (String) it.next();
                    String value = headerInfo.get(name);
                    httpPost.addHeader(name, value);
                }
            }
            httpPost.setEntity(postEntity);

            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            //File keyStoreFile = new File("D:/10016225.p12");
            File keyStoreFile = new File(keyStorePath);
            FileInputStream instream = new FileInputStream(keyStoreFile);
            try {
                keyStore.load(instream, keysecret.toCharArray());
            } finally {
                instream.close();
            }
            // Trust own CA and all self-signed certs
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, keysecret.toCharArray()).build();
            // Allow TLSv1 protocol only
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            org.apache.http.impl.client.HttpClientBuilder httpClientBuilder = HttpClients.custom();
            httpClientBuilder.setSSLSocketFactory(sslsf);
            CloseableHttpClient httpclient = httpClientBuilder.build();
            try {
                HttpResponse response = httpclient.execute(httpPost);
                int statusCode = response.getStatusLine().getStatusCode();
                /*if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                    String location = response.getFirstHeader("Location").getValue();
                    return get(location);
                }
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    result = EntityUtils.toString(entity, "utf-8");
                }*/
                if (statusCode == HttpStatus.SC_OK) {
                    HttpEntity entity = response.getEntity();
                    if (entity != null) {
                        result = EntityUtils.toString(entity, "utf-8");
                    }
                }
            } finally {
                httpclient.close();
            }
        }
        return result;
    }
    

    public static String get(String url) throws Exception {
        String result = "";
        HttpGet request = new HttpGet(url);
        CloseableHttpClient httpclient = HttpClients.custom().build();
        HttpResponse response = httpclient.execute(request);
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
            String location = response.getFirstHeader("Location").getValue();
            return get(location);
        }
        HttpEntity entity = response.getEntity();
        HeaderElement[] hes = entity.getContentType().getElements();
        String encode = "utf-8";
        if (hes != null && hes.length > 0) {
            for (HeaderElement he : hes) {
                encode = he.getParameterByName("charset") == null ? "utf-8" : he.getParameterByName("charset").getValue();
            }
        }
        if (entity != null) {
            result = EntityUtils.toString(entity, encode);
        }
        return result;
    }
    
}