App wechat payment

Keywords: Delphi Java xml Apache SSL

I. Basic Process of wechat payment

Main interaction between merchant system and wechat payment system:

Step 1: the user selects the goods in the merchant APP, submits the order and selects wechat payment.

Step 2: the merchant receives the user payment form at the background and calls the unified order interface of wechat payment. See also Unified order API].

Step 3: return the normal prepay ﹣ ID to the unified single interface, and then regenerate the signature according to the signature specification, and then transfer the data to the APP. The fields involved in signing are appid, partnerid, prepayid, noncestr, timestamp, package. Note: the value format of package is Sign=WXPay

Step 4: the merchant APP initiates wechat payment. api see also. Description of app development steps]

Step 5: merchant background receives payment notice. api see also. Payment result notification API]

Step 6: merchant background query payment results. , api see[ Query order API]

II. Specific preparation steps

1: fill in wechat payment related information and app information, and wait for approval

2: get app ID

3: obtain merchant number after successful application

Merchant number and password will be sent to the email at the time of application

4: Login Wechat merchant platform Set API key and download certificate

 

5: install the API certificate on the server

Three: specific demo code

1: Tools

import java.util.Date;

/**
 * 
 * @author jiangbo_lin
 * @2018-09-14
 * @desc:Date tool
 */

public class DateUtils {

    /**
     * Get the time stamp of the current system
     * 
     * @return
     */
    public static String getCurrentTimestamp() {

        long timeStamp = new Date().getTime();
        return String.valueOf(timeStamp);
    }

    public static String getCurrentTimestamp10() {

        long timeStamp = new Date().getTime() / 1000;
        String timestr = String.valueOf(timeStamp);
        return timestr;
    }

    public static String getTimeStamp() {
        int time = (int) (System.currentTimeMillis() / 1000);
        return String.valueOf(time);
    }

}
import java.util.*;
import java.util.Map.Entry;

/**
 *@author jiangbo_lin
 * 2018-09-18
 * @desc:ASCII sorting of map key
 */
public class MapUtils {

    /**
     * Sort the map in ASCII order according to the key
     * 
     * @param map Disordered map
     * @return
     */
    public static SortedMap<String, Object> sortMap(Map<String, Object> map) {

        List<Entry<String, Object>> infoIds = new ArrayList<Entry<String, Object>>(map.entrySet());

        // sort
        Collections.sort(infoIds, new Comparator<Entry<String, Object>>() {
            public int compare(Entry<String, Object> o1,
                    Entry<String, Object> o2) {
                // return (o2.getValue() - o1.getValue());//value Handle
                return (o1.getKey()).toString().compareTo(o2.getKey());
            }
        });
        // After sorting
        SortedMap<String, Object> sortmap = new TreeMap<String, Object>();
        for (int i = 0; i < infoIds.size(); i++) {
            Entry<String, Object> data = infoIds.get(i);
            String key = data.getKey() ;
            Object value = data.getValue();
            if(value==null){
                sortmap.put(data.getKey(), data.getValue());
            }else{
                sortmap.put(data.getKey(),data.getValue().toString());
            }

        }
        return sortmap;
    }

    /**
     * map to String
     * 
     * @param map
     * @return
     */
    public static String toString(Map<String, Object> map) {
        StringBuffer buf = new StringBuffer();
        buf.append("{");
        Iterator<Entry<String, Object>> i = map.entrySet().iterator();
        boolean hasNext = i.hasNext();
        while (hasNext) {
            Entry<String, Object> e = i.next();
            Object key = e.getKey();
            Object value = e.getValue();
            if (key == MapUtils.class)
                buf.append("(this Map)");
            else
                buf.append(key);
            buf.append("=");
            if (value == MapUtils.class)
                buf.append("(this Map)");
            else
                buf.append(value);
            hasNext = i.hasNext();
            if (hasNext)
                buf.append(", ");
        }
        buf.append("}");
        return buf.toString();
    }

}
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.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 *
 * @desc:XML Parsing tool
 */
@SuppressWarnings("all")
public class XMLUtil {
    /**
     * Parse the xml and return the first level element key value pair.
     * If the first level element has children,
     * The value of this node is the xml data of the child node.
     * 
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    public static SortedMap<String, Object> doXMLParse(String strxml)
            throws JDOMException, IOException {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
        if (null == strxml || "".equals(strxml)) {
            return null;
        }
        SortedMap<String, Object> map = new TreeMap<String, Object>();
        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 key = e.getName();
            String value = "";
            List children = e.getChildren();
            if (children.isEmpty()) {
                value = e.getTextNormalize();
            } else {
                value = XMLUtil.getChildrenText(children);
            }
            map.put(key, value);
        }
        // Closed flow
        in.close();
        return map;
    }

    /**
     * Get the xml of the child node
     * @param children
     * @return
     */
    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(XMLUtil.getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }
        return sb.toString();
    }

}
import java.security.MessageDigest;
/**
 *
 * @author jiangbo_lin
 * @2018/-09-14
 * @desc:md5 Tool class
 */
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" };
}
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * 
 * @author jiangbo_lin
 * @2018-09-14
 * @desc:Trust management center
 */
public class FsTrustManager implements X509TrustManager {

    // Check client certificate
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    // Check server certificate
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    // Return to trusted X509 Certificate array
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.*;


public class WeixinPayUtil {

    //Get loggers Logger,Name is the class name of this class
    private static Logger logger = LoggerFactory.getLogger(WeixinPayUtil.class);

    /**
     * The method of generating random number
     *
     * @return String random number
     */
    public static String generateNonceStr() {
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        String res = "";
        for (int i = 0; i < 16; i++) {
            Random rd = new Random();
            res += chars.charAt(rd.nextInt(chars.length() - 1));
        }
        return res;
    }

    /**
     * Generate signature string
     *
     * @param characterEncoding Encoding format
     * @param parameters        parameter
     * @return String Signature string
     */
    public static String createSign(String characterEncoding, SortedMap<String, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        Iterator<Map.Entry<String, Object>> it = parameters.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
            String key = (String) entry.getKey();
            Object value = entry.getValue();//Strip removal sign Item
            if (null != value && !"".equals(value) && !"sign".equals(key)
                    && !"key".equals(key)) {
                sb.append(key + "=" + value + "&");
            }
        }
        sb.append("key=" + WeixinConfig.API_KEY);
        //Be careful sign Turn capitalization
        return MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
    }

    /**
     * @param parameters Request parameters
     * @return String xml string in format
     * @Description: Convert the request parameter to a string in xml format
     */
    public static String getRequestXml(SortedMap<String, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Iterator<Map.Entry<String, Object>> iterator = parameters.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            String key = entry.getKey();
            String value = (String) entry.getValue();
            if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key)
                    || "sign".equalsIgnoreCase(key)) {
                sb.append("<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">");
            } else {
                sb.append("<" + key + ">" + value + "</" + key + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }


    /**
     * @param return_code Return code
     * @param return_msg  Return information
     * @return
     * @Description: Parameters returned to wechat
     */
    public static String setXML(String return_code, String return_msg) {
        return "<xml><return_code><![CDATA[" + return_code
                + "]]></return_code><return_msg><![CDATA[" + return_msg
                + "]]></return_msg></xml>";
    }

    /**
     * Send https request
     *
     * @param requestUrl    Request address
     * @param requestMethod Request mode (GET, POST)
     * @param outputStr     Submitted data
     * @return Return wechat server response information
     * @throws Exception
     */
    public static String httpsRequest(String requestUrl, String requestMethod,
                                      String outputStr) throws Exception {
        try {
            // Establish SSLContext Object and initialized with the trust manager we specified
            TrustManager[] tm = {new FsTrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // From above SSLContext Object SSLSocketFactory object
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // Set request method( GET/POST)
            conn.setRequestMethod(requestMethod);
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // When outputStr Not for null Write data to time output stream
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // Pay attention to the coding format
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // Read return content from input stream
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(
                    inputStream, "UTF-8");
            BufferedReader bufferedReader = new BufferedReader(
                    inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // Release resources
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            logger.error("[WeChat payment-Connection timeout]:{}", ce);
            throw new RuntimeException("Link exception" + ce);
        } catch (Exception e) {
            logger.error("WeChat payment-https Request exception]:{}", e);
            throw new RuntimeException("https Request exception" + e);
        }
    }

    /**
     * https Two way signature authentication for payment application refund
     */
    public static String payHttps(String url, String requestMethod, String xml) throws Exception {
        //Merchant id
        String MCH_ID = WeixinConfig.MCH_ID;
        //Specifies that the read certificate format is PKCS12
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        String path = "F:\\software\\apache-tomcat-8.0.11\\webapps\\frq-app\\certificate\\apiclient_cert.p12"

Posted by bfinucan on Mon, 04 Nov 2019 08:05:21 -0800