app微信支付-java服务端接口 支付-查询-退款

摘要:
我不太理解微信文档。看了很多前辈的写法,我终于调整好了,在这里做个记录吧。微信通知”2。http客户端工具类importjavax。网ssl。HttpsURLConnection;importjavax。网ssl。KeyManagerFactory;importjavax。网ssl。SLContext;importjavax。网ssl。TrustManagerFactory;importjava。io.*;importjava。网HttpURLConnection;importjava。网URL;importjava。安全。*;importjava。安全cert.CertificateException;importjava。util。HashMap;导入java.util.Map;publicclassHttpClientUtil{/***http客户端工具class**/publicstaticfinalStringSunX509=“SunX509”;publicstaticfinarStringJKS=“JKS”;publicstaticfinalStringPKCS12=“PKCS12”;publicStaticfinalString TLS=“TLS”;/***getHttpURLConnection*@paramstrUrurl address*@returnHttpURLConnection*@throwsjava.io。IOException*/publicstaticHttpURLConnection getHttpURLConnection pURLConnection throwsIOException{URLrl=newURL;HttpURLConnection httpURLConnection=url.openConnection();returnhttpURLConnection;}/***getHttpsURLConnection*@paramstrUrlURL地址*@returnHttpsURLConnection*@throwsIOException*/publicstaticHttpsURLConnect getHttpsURL连接throwsIOException{URLurl=newURL;HttpsURLConnectionhttpsURLConnection=url.openConnection();return httpsURLConnection;}/***获取url*@paramstrUrl*@returnString*/publicstaticStringgetURL{if(null!

个人不怎么看得懂微信的文档,看了很多前辈的写法,终于调通了,在这里做一下记录。

首先来定义各种处理类(微信支付不需要特殊jar包,很多处理需要自己封装,当然也可以自己写完打个jar包)

参数要用jdom解析   自行导入jar包   

或者在maven pom.xml中导入 

<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1.3</version>
</dependency>
version根据自己maven库中版本号进行设置
1、常用参数类
/**
 * 微信支付请求常量
 * Created by HQ on 2017/12/11 0011.
 */
public class ConstantUtil {
    /**
     * 微信开发平台应用ID
     */
    public static final String APP_ID="***";
    /**
     * 应用对应的凭证
     */
    public static final String APP_SECRET="***";
    /**
     * 应用对应的密钥
     */
    public static final String APP_KEY="***";
    /**
     * 微信支付商户号
     */
    public static final String MCH_ID="***";
    /**
     * 商品描述
     */
    public static final String BODY="***";
    /**
     * 商户号对应的密钥
     */
    public static final String PARTNER_key="***";
    /**
     * 商户id  我是用的与商户号相同
     */
    public static final String PARTNER_ID="***";
    /**
     * 常量固定值 可自定义
     */
    public static final String GRANT_TYPE="client_credential";
    /**
     * 获取预支付id的接口url   微信端提供的预支付信息生成借口
     */
    public static String GATEURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    /**
     * 获取支付订单信息url  微信端提供的查询订单接口
     */
    public static String GATESELECTURL = "https://api.mch.weixin.qq.com/pay/orderquery";
    /**
     * 微信退款url  微信端提供的退款接口
     */
    public static String GATEREFUNDURL = "https://api.mch.weixin.qq.com/secapi/pay/refund";

    /**
     * 微信服务器回调通知url  编写的回调借口  根据自己框架的url访问方式配置
* 我们的url格式是 http://ip:端口/项目名/controller.do?方法requestMap
*/ public static String NOTIFY_URL=".do?weiXinNotify";
2、http客户端工具类
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.Map;

public class HttpClientUtil {
    /**
     * http客户端工具类
     *
     */
    public static final String SunX509 = "SunX509";
    public static final String JKS = "JKS";
    public static final String PKCS12 = "PKCS12";
    public static final String TLS = "TLS";

    /**
     * get HttpURLConnection
     * @param strUrl url地址
     * @return HttpURLConnection
     * @throws java.io.IOException
     */
    public static HttpURLConnection getHttpURLConnection(String strUrl)
            throws IOException {
        URL url = new URL(strUrl);
        HttpURLConnection httpURLConnection = (HttpURLConnection) url
                .openConnection();
        return httpURLConnection;
    }

    /**
     * get HttpsURLConnection
     * @param strUrl url地址ַ
     * @return HttpsURLConnection
     * @throws IOException
     */
    public static HttpsURLConnection getHttpsURLConnection(String strUrl)
            throws IOException {
        URL url = new URL(strUrl);
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url
                .openConnection();
        return httpsURLConnection;
    }

    /**
     * 获取不带查询串的url
     * @param strUrl
     * @return String
     */
    public static String getURL(String strUrl) {

        if(null != strUrl) {
            int indexOf = strUrl.indexOf("?");
            if(-1 != indexOf) {
                return strUrl.substring(0, indexOf);
            }

            return strUrl;
        }

        return strUrl;

    }

    /**
     * 获取查询串
     * @param strUrl
     * @return String
     */
    public static String getQueryString(String strUrl) {

        if(null != strUrl) {
            int indexOf = strUrl.indexOf("?");
            if(-1 != indexOf) {
                return strUrl.substring(indexOf+1, strUrl.length());
            }

            return "";
        }

        return strUrl;
    }

    /**
     * 查询字符串转化为map
     * name1=key1&name2=key2&...
     * @param queryString
     * @return
     */
    public static Map queryString2Map(String queryString) {
        if(null == queryString || "".equals(queryString)) {
            return null;
        }

        Map m = new HashMap();
        String[] strArray = queryString.split("&");
        for(int index = 0; index < strArray.length; index++) {
            String pair = strArray[index];
            HttpClientUtil.putMapByPair(pair, m);
        }

        return m;

    }

    /**
     * 把键值添加到map
     * pair:name=value
     * @param pair name=value
     * @param m
     */
    public static void putMapByPair(String pair, Map m) {

        if(null == pair || "".equals(pair)) {
            return;
        }

        int indexOf = pair.indexOf("=");
        if(-1 != indexOf) {
            String k = pair.substring(0, indexOf);
            String v = pair.substring(indexOf+1, pair.length());
            if(null != k && !"".equals(k)) {
                m.put(k, v);
            }
        } else {
            m.put(pair, "");
        }
    }
    /**
     * BufferedReader转换成String<br/>
     * 注意:流关闭需要自行处理
     * @param reader
     * @return
     * @throws IOException
     */
    public static String bufferedReader2String(BufferedReader reader) throws IOException {
        StringBuffer buf = new StringBuffer();
        String line = null;
        while( (line = reader.readLine()) != null) {
            buf.append(line);
            buf.append("
");
        }

        return buf.toString();
    }
    /**
     * 处理输出<br/>
     * 注意:流关闭需要自行处理
     * @param out
     * @param data
     * @param len
     * @throws IOException
     */
    public static void doOutput(OutputStream out, byte[] data, int len)
            throws IOException {
        int dataLen = data.length;
        int off = 0;
        while (off < data.length) {
            if (len >= dataLen) {
                out.write(data, off, dataLen);
                off += dataLen;
            } else {
                out.write(data, off, len);
                off += len;
                dataLen -= len;
            }

            // ˢ�»�����
            out.flush();
        }

    }
    /**
     * 获取SSLContext
     * @param trustFileInputStream
     * @param trustPasswd
     * @param keyFileInputStream
     * @param keyPasswd
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     * @throws IOException
     * @throws CertificateException
     * @throws UnrecoverableKeyException
     * @throws KeyManagementException
     */
    public static SSLContext getSSLContext(
            FileInputStream trustFileInputStream, String trustPasswd,
            FileInputStream keyFileInputStream, String keyPasswd)
            throws NoSuchAlgorithmException, KeyStoreException,
            CertificateException, IOException, UnrecoverableKeyException,
            KeyManagementException {

        // ca
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(HttpClientUtil.SunX509);
        KeyStore trustKeyStore = KeyStore.getInstance(HttpClientUtil.JKS);
        trustKeyStore.load(trustFileInputStream, HttpClientUtil
                .str2CharArray(trustPasswd));
        tmf.init(trustKeyStore);

        final char[] kp = HttpClientUtil.str2CharArray(keyPasswd);
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(HttpClientUtil.SunX509);
        KeyStore ks = KeyStore.getInstance(HttpClientUtil.PKCS12);
        ks.load(keyFileInputStream, kp);
        kmf.init(ks, kp);

        SecureRandom rand = new SecureRandom();
        SSLContext ctx = SSLContext.getInstance(HttpClientUtil.TLS);
        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), rand);

        return ctx;
    }

    /**
     * 字符串转换成char数组
     * @param str
     * @return char[]
     */
    public static char[] str2CharArray(String str) {
        if(null == str) return null;

        return str.toCharArray();
    }

    public static InputStream String2Inputstream(String str) {
        return new ByteArrayInputStream(str.getBytes());
    }

    /**
     * InputStream转换成Byte
     * 注意:流关闭需要自行处理
     * @param in
     * @return byte
     * @throws Exception
     */
    public static byte[] InputStreamTOByte(InputStream in) throws IOException{

        int BUFFER_SIZE = 4096;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        int count = -1;

        while((count = in.read(data,0,BUFFER_SIZE)) != -1)
            outStream.write(data, 0, count);

        data = null;
        byte[] outByte = outStream.toByteArray();
        outStream.close();

        return outByte;
    }

    /**
     * InputStream转换成String
     * 注意:流关闭需要自行处理
     * @param in
     * @param encoding 编码
     * @return String
     * @throws Exception
     */
    public static String InputStreamTOString(InputStream in,String encoding) throws IOException{

        return new String(InputStreamTOByte(in),encoding);

    }
3、MD5加密类
import java.security.MessageDigest;

/**
 * Created by HQ on 2017/12/11 0011.
 */
public class MD5Util {
    /**
     * MD5加密
     * @param b
     * @return
     */
    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" };

    public  static String getMessageDigest(byte[] buffer) {
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(buffer);
            byte[] md = mdTemp.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            return "异常";
        }
    }

}

4、订单号生成类    这个可以自行判断要不要(只要不重复就行)    我是提前有个订单信息 前端直接给我订单号,当然订单号也是用这个类生成的。

import org.jeecgframework.core.util.DateUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Random;

/**
 * Created by HQ on 2017/12/11 0011.
 */
public class OrderNumUtil {
    private static Date date = new Date();
    private static StringBuilder buf = new StringBuilder();
    private static int seq = 0;
    private static final int ROTATION = 99999;

    public static synchronized String next() {
        if (seq > ROTATION)
            seq = 0;
        buf.delete(0, buf.length());
        date.setTime(System.currentTimeMillis());
        String str = String.format("%1$tY%1$tm%1$td%1$tk%1$tM%1$tS%2$05d", date, seq++);
        return str;
    }

    public static synchronized String orderDatrNum() {
        String randNum ="";
        try {
            Random rand = new Random();
            int shu2 = rand.nextInt(9);
            randNum+= DateUtils.getDate("yyyyMMddHHmmss") + shu2;//  DateUtils 是项目中统一处理时间的 没有的话可自行处理  就是个时间格式转换
        } catch (Exception e) {
            e.printStackTrace();
        }
        return randNum;
    }
}
5、获取支付prypPayId请求类
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * 微信支付处理
 * Created by HQon 2017/12/11 0011.
 */
public class PrepayIdRequestHandler extends RequestHandler{
    public PrepayIdRequestHandler(HttpServletRequest request,
                                  HttpServletResponse response) {
        super(request, response);
    }

    public String createMD5Sign() {
        StringBuffer sb = new StringBuffer();
        Set es = super.getAllParameters().entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            sb.append(k + "=" + v + "&");
        }
        String params=sb.append("key="+ ConstantUtil.APP_KEY).substring(0);
        String sign = MD5Util.MD5Encode(params, "utf8");
        return sign.toUpperCase();
    }

    // 提交预支付
    public String sendPrepay() throws Exception {
        String prepayid = "";
        Set es=super.getAllParameters().entrySet();
        Iterator it=es.iterator();
        StringBuffer sb = new StringBuffer("<xml>");
        while(it.hasNext()){
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            sb.append("<"+k+">"+v+"</"+k+">");
        }
        sb.append("</xml>");
        String params=sb.substring(0);
        System.out.println("请求参数:"+params);
        String requestUrl = super.getGateUrl();
        System.out.println("请求url:"+requestUrl);
        TenpayHttpClient httpClient = new TenpayHttpClient();
        httpClient.setReqContent(requestUrl);
        String resContent = "";
        if (httpClient.callHttpPost(requestUrl, params)) {
            resContent = httpClient.getResContent();
            System.out.println("获取prepayid的返回值:"+resContent);
            Map<String,String> map=XMLUtil.doXMLParse(resContent);
            if(map.containsKey("prepay_id"))
                prepayid=map.get("prepay_id");
        }
        return prepayid;
    }
}
6、签名请求类
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
/**
 * Created by HQ on 2017/12/11 0011.
 */
public class RequestHandler {
    /** 网关url地址 */
    private String gateUrl;

    /** 密钥 */
    private String key;

    /** 请求的参数 */
    private SortedMap parameters;

    protected HttpServletRequest request;

    protected HttpServletResponse response;

    /**
     * 构造函数
     * @param request
     * @param response
     */
    public RequestHandler(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;

        this.gateUrl = "https://gw.tenpay.com/gateway/pay.htm";
        this.key = "";
        this.parameters = new TreeMap();
    }

    /**
     *初始化函数。
     */
    public void init() {
        //nothing to do
    }

    /**
     *获取入口地址,不包含参数值
     */
    public String getGateUrl() {
        return gateUrl;
    }
    /**
     *设置入口地址,不包含参数值
     */
    public void setGateUrl(String gateUrl) {
        this.gateUrl = gateUrl;
    }

    /**
     *获取密钥
     */
    public String getKey() {
        return key;
    }

    /**
     *设置密钥
     */
    public void setKey(String key) {
        this.key = key;
    }

    /**
     * 获取参数值
     * @param parameter 参数名称
     * @return String
     */
    public String getParameter(String parameter) {
        String s = (String)this.parameters.get(parameter);
        return (null == s) ? "" : s;
    }

    /**
     * 设置参数值
     * @param parameter 参数名称
     * @param parameterValue 参数值
     */
    public void setParameter(String parameter, Object parameterValue) {
        String v = "";
        if(null != parameterValue) {
            if(parameterValue instanceof String)
                v = ((String) parameterValue).trim();
        }
        this.parameters.put(parameter, v);
    }

    /**
     * 返回所有的参数
     * @return SortedMap
     */
    public SortedMap getAllParameters() {
        return this.parameters;
    }

    /**
     * 获取带参数的请求URL
     * @return String
     * @throws UnsupportedEncodingException
     */
    public String getRequestURL() throws UnsupportedEncodingException {

        this.createSign();

        StringBuffer sb = new StringBuffer();
        String enc = TenpayUtil.getCharacterEncoding(this.request, this.response);
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();

            if(!"spbill_create_ip".equals(k)) {
                sb.append(k + "=" + URLEncoder.encode(v, enc) + "&");
            } else {
                sb.append(k + "=" + v.replace("\.", "%2E") + "&");
            }
        }

        //去掉最后一个&
        String reqPars = sb.substring(0, sb.lastIndexOf("&"));

        return this.getGateUrl() + "?" + reqPars;

    }

    public void doSend() throws UnsupportedEncodingException, IOException {
        this.response.sendRedirect(this.getRequestURL());
    }

    /**
     * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     */
    protected void createSign() {
        StringBuffer sb = new StringBuffer();
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            if(null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + this.getKey());
        String enc = TenpayUtil.getCharacterEncoding(this.request, this.response);
        String sign = MD5Util.MD5Encode(sb.toString(), enc).toUpperCase();

        this.setParameter("sign", sign);

    }

    protected HttpServletRequest getHttpServletRequest() {
        return this.request;
    }

    protected HttpServletResponse getHttpServletResponse() {
        return this.response;
    }
}
7、响应参数处理类
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * Created by HQ on 2017/12/11 0011.
 */
public class ResponseHandler {
    /** 密钥 */
    private String key;

    /** 应答的参数 */
    private SortedMap parameters;

    private HttpServletRequest request;

    private HttpServletResponse response;

    private String uriEncoding;

    /**
     * 构造函数
     *
     * @param request
     * @param response
     */
    public ResponseHandler(HttpServletRequest request,
                           HttpServletResponse response)  {
        this.request = request;
        this.response = response;

        this.key = "";
        this.parameters = new TreeMap();
        this.uriEncoding = "";

        Map m = this.request.getParameterMap();
        Iterator it = m.keySet().iterator();
        while (it.hasNext()) {
            String k = (String) it.next();
            String v = ((String[]) m.get(k))[0];
            this.setParameter(k, v);
        }

    }

    /**
     *获取密钥
     */
    public String getKey() {
        return key;
    }

    /**
     *设置密钥
     */
    public void setKey(String key) {
        this.key = key;
    }

    /**
     * 获取参数值
     * @param parameter 参数名称
     * @return String
     */
    public String getParameter(String parameter) {
        String s = (String)this.parameters.get(parameter);
        return (null == s) ? "" : s;
    }

    /**
     * 设置参数值
     * @param parameter 参数名称
     * @param parameterValue 参数值
     */
    public void setParameter(String parameter, String parameterValue) {
        String v = "";
        if(null != parameterValue) {
            v = parameterValue.trim();
        }
        this.parameters.put(parameter, v);
    }

    /**
     * 返回所有的参数
     * @return SortedMap
     */
    public SortedMap getAllParameters() {
        return this.parameters;
    }

    /**
     * 是否财付通签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     * @return boolean
     */
    public boolean isTenpaySign() {
        StringBuffer sb = new StringBuffer();
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            if(!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }

        sb.append("key=" + this.getKey());

        //算出摘要
        String enc = TenpayUtil.getCharacterEncoding(this.request, this.response);
        String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();

        String tenpaySign = this.getParameter("sign").toLowerCase();

        return tenpaySign.equals(sign);
    }

    /**
     * 返回处理结果给财付通服务器。
     * @param msg: Success or fail。
     * @throws IOException
     */
    public void sendToCFT(String msg) throws IOException {
        String strHtml = msg;
        PrintWriter out = this.getHttpServletResponse().getWriter();
        out.println(strHtml);
        out.flush();
        out.close();

    }

    /**
     * 获取uri编码
     * @return String
     */
    public String getUriEncoding() {
        return uriEncoding;
    }

    /**
     * 设置uri编码
     * @param uriEncoding
     * @throws UnsupportedEncodingException
     */
    public void setUriEncoding(String uriEncoding)
            throws UnsupportedEncodingException {
        if (!"".equals(uriEncoding.trim())) {
            this.uriEncoding = uriEncoding;

            // 编码转换
            String enc = TenpayUtil.getCharacterEncoding(request, response);
            Iterator it = this.parameters.keySet().iterator();
            while (it.hasNext()) {
                String k = (String) it.next();
                String v = this.getParameter(k);
                v = new String(v.getBytes(uriEncoding.trim()), enc);
                this.setParameter(k, v);
            }
        }
    }

    protected HttpServletRequest getHttpServletRequest() {
        return this.request;
    }

    protected HttpServletResponse getHttpServletResponse() {
        return this.response;
    }

}
  8、财付通请求客户端
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;

/**
 * Created by heqiao on 2017/12/11 0011.
 */
public class TenpayHttpClient {
    /** 请求内容,无论post和get,都用get方式提供 */
    private String reqContent;

    /** 应答内容 */
    private String resContent;

    /** 请求方法 */
    private String method;

    /** 错误信息 */
    private String errInfo;

    /** 超时时间,以秒为单位 */
    private int timeOut;

    /** http应答编码 */
    private int responseCode;

    /** 字符编码 */
    private String charset;

    private InputStream inputStream;

    public TenpayHttpClient() {
        this.reqContent = "";
        this.resContent = "";
        this.method = "POST";
        this.errInfo = "";
        this.timeOut = 30;//30秒

        this.responseCode = 0;
        this.charset = "utf8";

        this.inputStream = null;
    }

    /**
     * 设置请求内容
     * @param reqContent 表求内容
     */
    public void setReqContent(String reqContent) {
        this.reqContent = reqContent;
    }

    /**
     * 获取结果内容
     * @return String
     * @throws IOException
     */
    public String getResContent() {
        try {
            this.doResponse();
        } catch (IOException e) {
            this.errInfo = e.getMessage();
            //return "";
        }

        return this.resContent;
    }

    /**
     * 设置请求方法post或者get
     * @param method 请求方法post/get
     */
    public void setMethod(String method) {
        this.method = method;
    }

    /**
     * 获取错误信息
     * @return String
     */
    public String getErrInfo() {
        return this.errInfo;
    }

    /**
     * 设置超时时间,以秒为单位
     * @param timeOut 超时时间,以秒为单位
     */
    public void setTimeOut(int timeOut) {
        this.timeOut = timeOut;
    }

    /**
     * 获取http状态码
     * @return int
     */
    public int getResponseCode() {
        return this.responseCode;
    }

    protected void callHttp() throws IOException {

        if("POST".equals(this.method.toUpperCase())) {
            String url = HttpClientUtil.getURL(this.reqContent);
            String queryString = HttpClientUtil.getQueryString(this.reqContent);
            byte[] postData = queryString.getBytes(this.charset);
            this.httpPostMethod(url, postData);

            return ;
        }

        this.httpGetMethod(this.reqContent);

    }

    public boolean callHttpPost(String url, String postdata) {
        boolean flag = false;
        byte[] postData;
        try {
            postData = postdata.getBytes(this.charset);
            this.httpPostMethod(url, postData);
            flag = true;
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        return flag;
    }

    /**
     * 以http post方式通信
     * @param url
     * @param postData
     * @throws IOException
     */
    protected void httpPostMethod(String url, byte[] postData)
            throws IOException {

        HttpURLConnection conn = HttpClientUtil.getHttpURLConnection(url);

        this.doPost(conn, postData);
    }

    /**
     * 以http get方式通信
     *
     * @param url
     * @throws IOException
     */
    protected void httpGetMethod(String url) throws IOException {

        HttpURLConnection httpConnection =
                HttpClientUtil.getHttpURLConnection(url);

        this.setHttpRequest(httpConnection);

        httpConnection.setRequestMethod("GET");

        this.responseCode = httpConnection.getResponseCode();

        this.inputStream = httpConnection.getInputStream();

    }

    /**
     * 以https get方式通信
     * @param url
     * @param sslContext
     * @throws IOException
     */
    protected void httpsGetMethod(String url, SSLContext sslContext)
            throws IOException {

        SSLSocketFactory sf = sslContext.getSocketFactory();

        HttpsURLConnection conn = HttpClientUtil.getHttpsURLConnection(url);

        conn.setSSLSocketFactory(sf);

        this.doGet(conn);

    }

    protected void httpsPostMethod(String url, byte[] postData,
                                   SSLContext sslContext) throws IOException {

        SSLSocketFactory sf = sslContext.getSocketFactory();

        HttpsURLConnection conn = HttpClientUtil.getHttpsURLConnection(url);

        conn.setSSLSocketFactory(sf);

        this.doPost(conn, postData);

    }

    /**
     * 设置http请求默认属性
     * @param httpConnection
     */
    protected void setHttpRequest(HttpURLConnection httpConnection) {

        //设置连接超时时间
        httpConnection.setConnectTimeout(this.timeOut * 1000);


        //不使用缓存
        httpConnection.setUseCaches(false);

        //允许输入输出
        httpConnection.setDoInput(true);
        httpConnection.setDoOutput(true);

    }

    /**
     * 处理应答
     * @throws IOException
     */
    protected void doResponse() throws IOException {

        if(null == this.inputStream) {
            return;
        }

        //获取应答内容
        this.resContent=HttpClientUtil.InputStreamTOString(this.inputStream,this.charset);

        //关闭输入流
        this.inputStream.close();

    }

    /**
     * post方式处理
     * @param conn
     * @param postData
     * @throws IOException
     */
    protected void doPost(HttpURLConnection conn, byte[] postData)
            throws IOException {

        // 以post方式通信
        conn.setRequestMethod("POST");

        // 设置请求默认属性
        this.setHttpRequest(conn);

        // Content-Type
        conn.setRequestProperty("Content-Type",
                "application/x-www-form-urlencoded");

        BufferedOutputStream out = new BufferedOutputStream(conn
                .getOutputStream());

        final int len = 1024; // 1KB
        HttpClientUtil.doOutput(out, postData, len);

        // 关闭流
        out.close();

        // 获取响应返回状态码
        this.responseCode = conn.getResponseCode();

        // 获取应答输入流
        this.inputStream = conn.getInputStream();

    }

    /**
     * get方式处理
     * @param conn
     * @throws IOException
     */
    protected void doGet(HttpURLConnection conn) throws IOException {

        //以GET方式通信
        conn.setRequestMethod("GET");

        //设置请求默认属性
        this.setHttpRequest(conn);

        //获取响应返回状态码
        this.responseCode = conn.getResponseCode();

        //获取应答输入流
        this.inputStream = conn.getInputStream();
    }
}
9、财付通Util类
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by heqiao on 2017/12/11 0011.
 */
public class TenpayUtil {
    /**
     * 把对象转换成字符串
     * @param obj
     * @return String 转换成字符串,若对象为null,则返回空字符串.
     */
    public static String toString(Object obj) {
        if(obj == null)
            return "";

        return obj.toString();
    }

    /**
     * 把对象转换为int数值.
     *
     * @param obj
     *            包含数字的对象.
     * @return int 转换后的数值,对不能转换的对象返回0。
     */
    public static int toInt(Object obj) {
        int a = 0;
        try {
            if (obj != null)
                a = Integer.parseInt(obj.toString());
        } catch (Exception e) {

        }
        return a;
    }

    /**
     * 获取当前时间 yyyyMMddHHmmss
     * @return String
     */
    public static String getCurrTime() {
        Date now = new Date();
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String s = outFormat.format(now);
        return s;
    }

    /**
     * 获取当前日期 yyyyMMdd
     * @param date
     * @return String
     */
    public static String formatDate(Date date) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        String strDate = formatter.format(date);
        return strDate;
    }

    /**
     * 取出一个指定长度大小的随机正整数.
     *
     * @param length
     *            int 设定所取出随机数的长度。length小于11
     * @return int 返回生成的随机数。
     */
    public static int buildRandom(int length) {
        int num = 1;
        double random = Math.random();
        if (random < 0.1) {
            random = random + 0.1;
        }
        for (int i = 0; i < length; i++) {
            num = num * 10;
        }
        return (int) ((random * num));
    }

    /**
     * 获取编码字符集
     * @param request
     * @param response
     * @return String
     */
    public static String getCharacterEncoding(HttpServletRequest request,
                                              HttpServletResponse response) {

        if(null == request || null == response) {
            return "gbk";
        }

        String enc = request.getCharacterEncoding();
        if(null == enc || "".equals(enc)) {
            enc = response.getCharacterEncoding();
        }

        if(null == enc || "".equals(enc)) {
            enc = "gbk";
        }

        return enc;
    }

    /**
     * 获取unix时间,从1970-01-01 00:00:00开始的秒数
     * @param date
     * @return long
     */
    public static long getUnixTime(Date date) {
        if( null == date ) {
            return 0;
        }

        return date.getTime()/1000;
    }

    /**
     * 时间转换成字符串
     * @param date 时间
     * @param formatType 格式化类型
     * @return String
     */
    public static String date2String(Date date, String formatType) {
        SimpleDateFormat sdf = new SimpleDateFormat(formatType);
        return sdf.format(date);
    }
    public static  String getIpAddr(HttpServletRequest request)  {
        String ip  =  request.getHeader( " x-forwarded-for " );
        if (ip  ==   null   ||  ip.length()  ==   0   ||   " unknown " .equalsIgnoreCase(ip))  {
            ip  =  request.getHeader( " Proxy-Client-IP " );
        }
        if (ip  ==   null   ||  ip.length()  ==   0   ||   " unknown " .equalsIgnoreCase(ip))  {
            ip  =  request.getHeader( " WL-Proxy-Client-IP " );
        }
        if (ip  ==   null   ||  ip.length()  ==   0   ||   " unknown " .equalsIgnoreCase(ip))  {
            ip  =  request.getRemoteAddr();
        }
        return  ip;
    }
}
10、其他处理Util类
import com.sun.org.apache.bcel.internal.generic.RETURN;
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.hibernate.loader.custom.Return;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jeecgframework.core.util.ResourceUtil;
import org.xml.sax.InputSource;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.StringReader;
import java.security.KeyStore;
import java.util.*;

/**
 * Created by heqiao on 2017/12/11 0011.
 */
public class WXUtil {
    /**
     * 生成随机字符串
     * @return
     */
    public static String getNonceStr() {
        Random random = new Random();
        return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "utf8");
    }
    /**
     * 获取时间戳
     * @return
     */
    public static String getTimeStamp() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }

    /**
     * 获取十位的时间戳
     * @param d 时间
     * @return
     */
    public static String getTimeStamp(Date d) {
        return String.valueOf(d.getTime() / 1000);
    }
    /**
     * https双向签名认证,用于支付申请退款
     *
     * */
    public static String payHttps(String url,String xml) throws Exception {
        //商户id
        String MCH_ID = ConstantUtil.MCH_ID;
        //指定读取证书格式为PKCS12
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        String path = ResourceUtil.getConfigByName("pay.weixin.certificate.localaddress");
        //读取本机存放的PKCS12证书文件
        FileInputStream instream = new FileInputStream(new File(path));
        try {
            //指定PKCS12的密码(商户ID)
            keyStore.load(instream, MCH_ID.toCharArray());
        } finally {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, MCH_ID.toCharArray()).build();
        //指定TLS版本
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,new String[] { "TLSv1" },null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        //设置httpclient的SSLSocketFactory
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        try {
            HttpPost httpost = new HttpPost(url); // 设置响应头信息
            httpost.addHeader("Connection", "keep-alive");
            httpost.addHeader("Accept", "*/*");
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpost.addHeader("Host", "api.mch.weixin.qq.com");
            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpost.addHeader("Cache-Control", "max-age=0");
            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(xml, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                HttpEntity entity = response.getEntity();
                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                EntityUtils.consume(entity);
                return jsonStr;
            }finally {
                response.close();
            }
        }finally {
            httpclient.close();
        }
    }
    /**
     * 获取回调地址
     * @param request
     * @return
     */
    public static String getNotifyUrl(HttpServletRequest request) {
        String url = request.getRequestURL().toString();
        String domain = url.substring(0, url.length()-13);
        //生产环境
        return domain+ConstantUtil.NOTIFY_URL;
    }

    public static Map parseXmlToMap(String xml) {
        //  Map retMap = new HashMap();
        SortedMap<String, String> retMap = new TreeMap<>();
        try {
            StringReader read = new StringReader(xml);
            // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
            InputSource source = new InputSource(read);
            // 创建一个新的SAXBuilder
            SAXBuilder sb = new SAXBuilder();
            // 通过输入源构造一个Document
            Document doc =  sb.build(source);
            Element root = (Element) doc.getRootElement();// 指向根节点
            List<Element> es = root.getChildren();
            if (es != null && es.size() != 0) {
                for (Element element : es) {
                    retMap.put(element.getName(), element.getValue());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return retMap;
    }
    /*public static void main(String[] args){

        System.out.println(getTimeStamp(new Date()));
    }*/
}
11、XML解析类
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.io.ByteArrayInputStream;
public class XMLUtil {
    /**
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    public static Map doXMLParse(String strxml) throws JDOMException, IOException {
        strxml = strxml.replaceFirst("encoding=".*"", "encoding="UTF-8"");
        if(null == strxml || "".equals(strxml)) {
            return null;
        }

        Map m = new HashMap();

        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while(it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if(children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = XMLUtil.getChildrenText(children);
            }
            m.put(k, v);
        }

        //关闭流
        in.close();

        return m;
    }

    /**
     * 获取子结点的xml
     * @param children
     * @return String
     */
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if(!children.isEmpty()) {
            Iterator it = children.iterator();
            while(it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if(!list.isEmpty()) {
                    sb.append(XMLUtil.getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }

        return sb.toString();
    }

    /**
     * 获取xml编码字符集
     * @param strxml
     * @return
     * @throws IOException
     * @throws JDOMException
     */
    public static String getXMLEncoding(String strxml) throws JDOMException, IOException {
        InputStream in = HttpClientUtil.String2Inputstream(strxml);
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        in.close();
        return (String)doc.getProperty("encoding");
    }

    /**
     * 支付成功,返回微信那服务器
     * @param return_code
     * @param return_msg
     * @return
     */
    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>";
    }

    public static String createXML(Map<String,Object> map){
        Set<Entry<String,Object>> set=map.entrySet();
        set.iterator();
        return null;
    }

}
12、支付接口

(生成签名  获取 prePayId) 返回给APP端

此处参数除   均可根据具体业务自定义   只要可获取平台需支付的信息即可

返回参数与前端商量  此处返回的Map  也可返回json字符串  或者后台统一的类型

/**
     * 微信生成预支付订单,获取prepayId
     *
     * @param request
     * @param out_trade_no 订单号
     * @param total_fee    支付金额
     * @param payType      支付类型  1、支付宝   2、微信
     * @param couponId     优惠券id
     * @param addressId    地址id
     * @param response
     * @return
     * @throws Exception , method = RequestMethod.POST
     */
    @ResponseBody
    @RequestMapping(params = "getWeXinOrderString")
    public Map<String, Object> getWeXinOrderString(HttpServletRequest request,
                                                   String out_trade_no,
                                                   Float total_fee,
                                                   String payType,
                                                   String couponId,
                                                   String addressId,
                                                   HttpServletResponse response) throws Exception {
        Map<String, Object> map = new HashMap<>();
        //第一步   判断信息是否有误   根据参数判断要支付的信息是否存在或有误   根据自己业务进行处理
     // 第二步  获取生成预支付订单的请求类
            PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);
            int totalFee = (int) (total_fee * 100);//微信支付是以分为单位的
            System.out.println("total_fee:" + totalFee);
            prepayReqHandler.setParameter("appid", ConstantUtil.APP_ID);
            prepayReqHandler.setParameter("body", ConstantUtil.BODY);
            prepayReqHandler.setParameter("mch_id", ConstantUtil.MCH_ID);
            String nonce_str = WXUtil.getNonceStr();
            prepayReqHandler.setParameter("nonce_str", nonce_str);
            //设置回调地址-获取当前的地址拼接回调地址
            prepayReqHandler.setParameter("notify_url", WXUtil.getNotifyUrl(request));
            String outTradeNo = out_trade_no;//OrderNumUtil.orderDatrNum();//新的订单号   若订单号是实时生成的则在此处修改
            prepayReqHandler.setParameter("out_trade_no", outTradeNo);
            prepayReqHandler.setParameter("spbill_create_ip", TenpayUtil.getIpAddr(request));//request.getRemoteAddr()
            Date timestamp = new Date();//WXUtil.getTimeStamp();  //开始时间和结束时间可不填
            prepayReqHandler.setParameter("time_start", DateUtils.formatDate(timestamp, "yyyyMMddHHmmss"));// 此处时间是微信规定的格式  请自己些工具类转换 格式为 
            prepayReqHandler.setParameter("time_expire", DateUtils.formatDate(DateUtils.getTimeByMinute(10), "yyyyMMddHHmmss"));// 此处是交易结束时间  可自定义
            System.out.println(String.valueOf(total_fee));
            prepayReqHandler.setParameter("total_fee", String.valueOf(totalFee));
            prepayReqHandler.setParameter("trade_type", "APP");
            /**
             * 注意签名(sign)的生成方式,具体见官方文档(传参都要参与生成签名,且参数名按照字典序排序,最后接上APP_KEY,转化成大写)
             */
            prepayReqHandler.setParameter("sign", prepayReqHandler.createMD5Sign());
            prepayReqHandler.setGateUrl(ConstantUtil.GATEURL);
            String prepayid = prepayReqHandler.sendPrepay();
            // 若获取prepayid成功,将相关信息返回客户端
            if (prepayid != null && !prepayid.equals("")) {//修改信息  此处根据业务自行处理  如商品支付信息为支付中 等信息 ,将当前订单号保存起来等
               



//第三步 生成返回给app端的签名 和其他信息
/** * 签名方式与上面类似 */ StringBuffer sb = new StringBuffer(); sb.append("appid=" + ConstantUtil.APP_ID); sb.append("&noncestr=" + nonce_str); sb.append("&package=" + "Sign=WXPay"); sb.append("&partnerid=" + ConstantUtil.PARTNER_ID); sb.append("&prepayid=" + prepayid); String ts = WXUtil.getTimeStamp(timestamp);//此处是十位的时间戳 sb.append("&timestamp=" + ts); sb.append("&key=" + ConstantUtil.APP_KEY); //sign使用自己拼接的字符创定义 String sign = MD5Util.getMessageDigest(sb.toString().getBytes(Charset.forName("utf-8"))).toUpperCase();//MD5Util.MD5Encode(sb.toString(),"").toUpperCase(); map.put("sign", sign); map.put("appId", ConstantUtil.APP_ID); map.put("nonceStr", nonce_str); //与请求prepayId时值一致 map.put("packageValue", "Sign=WXPay"); //固定常量 map.put("partnerId", ConstantUtil.PARTNER_ID); map.put("timeStamp", ts); map.put("code", 0); map.put("out_trade_no", outTradeNo); map.put("info", "success"); map.put("prepayId", prepayid); } else { map.put("code", 1); map.put("info", "获取prepayid失败"); } } //net.sf.json.JSONObject json = net.sf.json.JSONObject.fromObject(map); //json.toString(); // System.out.println("json=========="+json.toString()); return map; }
/**
     * 接收微信支付成功通知   
     * ConstantUtil 中的  NOTIFY_URL
*
@param request * @param response * @throws IOException */ @ResponseBody @RequestMapping(value = "weiXinNotify") public void getnotify(HttpServletRequest request, HttpServletResponse response) throws IOException { System.out.println("微信支付回调"); PrintWriter writer = response.getWriter(); InputStream inStream = request.getInputStream(); ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outSteam.write(buffer, 0, len); } outSteam.close(); inStream.close(); String result = new String(outSteam.toByteArray(), "utf-8"); System.out.println("微信支付通知结果:" + result); Map<String, String> map = null; try { /** * 解析微信通知返回的信息 */ map = XMLUtil.doXMLParse(result); } catch (JDOMException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("=========:" + result); // 若支付成功,则告知微信服务器收到通知 if (map.get("return_code").equals("SUCCESS")) { if (map.get("result_code").equals("SUCCESS")) { String out_trade_no = map.get("out_trade_no"); System.out.println("成功!" + out_trade_no); //判断通知是否已处理,若已处理,则不予处理 // 根据订单号查询订单信息 做订单信息修改和支付信息修改 if (StringUtil.isNotEmpty(out_trade_no)) {
//根据订单号查询订单信息
//修改订单状态等信息   String notifyStr = XMLUtil.setXML("SUCCESS", ""); writer.write(notifyStr); writer.flush(); // return notifyStr;  } } }else{ String notifyStr = XMLUtil.setXML("FALSE", ""); writer.write(notifyStr); writer.flush(); } // return XMLUtil.setXML("FALSE", ""); }
13、去微信端查询支付的订单信息
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * 微信支付查询 操作类
 * Created by heqiao on 2017/12/19 0019.
 */
public class SelectReqHandler {
    /** 网关url地址 */
    private String gateSelectUrl;

    /** 密钥 */
    private String key;

    /** 请求的参数 */
    private SortedMap parameters;

    protected HttpServletRequest request;

    protected HttpServletResponse response;

    /**
     * 构造函数
     * @param request
     * @param response
     */
    public SelectReqHandler(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
        this.gateSelectUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
        this.key = "";
        this.parameters = new TreeMap();
    }

    /**
     *初始化函数。
     */
    public void init() {
        //nothing to do
    }

    /**
     *获取入口地址,不包含参数值
     */
    public String getGateSelectUrl() {
        return gateSelectUrl;
    }
    /**
     *设置入口地址,不包含参数值
     */
    public void setGateSelectUrl(String gateSelectUrl) {
        this.gateSelectUrl = gateSelectUrl;
    }

    /**
     *获取密钥
     */
    public String getKey() {
        return key;
    }

    /**
     *设置密钥
     */
    public void setKey(String key) {
        this.key = key;
    }

    /**
     * 获取参数值
     * @param parameter 参数名称
     * @return String
     */
    public String getParameter(String parameter) {
        String s = (String)this.parameters.get(parameter);
        return (null == s) ? "" : s;
    }

    /**
     * 设置参数值
     * @param parameter 参数名称
     * @param parameterValue 参数值
     */
    public void setParameter(String parameter, Object parameterValue) {
        String v = "";
        if(null != parameterValue) {
            if(parameterValue instanceof String)
                v = ((String) parameterValue).trim();
        }
        this.parameters.put(parameter, v);
    }

    /**
     * 返回所有的参数
     * @return SortedMap
     */
    public SortedMap getAllParameters() {
        return this.parameters;
    }

    /**
     * 获取带参数的请求URL
     * @return String
     * @throws UnsupportedEncodingException
     */
    public String getRequestURL() throws UnsupportedEncodingException {

        this.createSign();

        StringBuffer sb = new StringBuffer();
        String enc = TenpayUtil.getCharacterEncoding(this.request, this.response);
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();

            if(!"spbill_create_ip".equals(k)) {
                sb.append(k + "=" + URLEncoder.encode(v, enc) + "&");
            } else {
                sb.append(k + "=" + v.replace("\.", "%2E") + "&");
            }
        }

        //去掉最后一个&
        String reqPars = sb.substring(0, sb.lastIndexOf("&"));

        return this.getGateSelectUrl() + "?" + reqPars;

    }

    public void doSend() throws UnsupportedEncodingException, IOException {
        this.response.sendRedirect(this.getRequestURL());
    }

    /**
     * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     */
    protected void createSign() {
        StringBuffer sb = new StringBuffer();
        Set es = this.parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            if(null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + this.getKey());
        String enc = TenpayUtil.getCharacterEncoding(this.request, this.response);
        String sign = MD5Util.MD5Encode(sb.toString(), enc).toUpperCase();
        this.setParameter("sign", sign);
    }

    protected HttpServletRequest getHttpServletRequest() {
        return this.request;
    }

    protected HttpServletResponse getHttpServletResponse() {
        return this.response;
    }
}
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * 微信订单查询 退款  等处理信息
 * Created by HQ on 2017/12/11 0011.
 */
public class PreRequestHandler extends SelectReqHandler{
    public PreRequestHandler(HttpServletRequest request,
                             HttpServletResponse response) {
        super(request, response);
    }

    public String createMD5Sign() {
        StringBuffer sb = new StringBuffer();
        Set es = super.getAllParameters().entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            sb.append(k + "=" + v + "&");
        }
        String params=sb.append("key="+ ConstantUtil.APP_KEY).substring(0);
        String sign = MD5Util.MD5Encode(params, "utf8");
        return sign.toUpperCase();
    }

    // 提交
    public  Map<String,String> sendPreSelect() throws Exception {
        Set es=super.getAllParameters().entrySet();
        Iterator it=es.iterator();
        StringBuffer sb = new StringBuffer("<xml>");
        while(it.hasNext()){
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            sb.append("<"+k+">"+v+"</"+k+">");
        }
        sb.append("</xml>");
        String params=sb.substring(0);
        System.out.println("请求参数:"+params);
        String requestUrl = super.getGateSelectUrl();
        System.out.println("请求url:"+requestUrl);
        TenpayHttpClient httpClient = new TenpayHttpClient();
        httpClient.setReqContent(requestUrl);
        String resContent = "";
        if (httpClient.callHttpPost(requestUrl, params)) {
            resContent = httpClient.getResContent();
            System.out.println("获取select的返回值:"+resContent);
            Map<String,String> map=XMLUtil.doXMLParse(resContent);
            return map;
        }
        return null;
    }

    /**
     * xml 参数
     * @return
     * @throws Exception
     */
    public  String sendPreSelectXml() throws Exception {
        Set es=super.getAllParameters().entrySet();
        Iterator it=es.iterator();
        StringBuffer sb = new StringBuffer("<xml>");
        while(it.hasNext()){
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            sb.append("<"+k+">"+v+"</"+k+">");
        }
        sb.append("</xml>");
        System.out.println("退款请求参数:"+sb.substring(0));
        return sb.substring(0);
    }
}
    /**
     * 微信支出订单状态查询
     * 此接口直接去查询支付情况  防止回调不成功无法获取支付状态
     * @param request
     * @param response
     * @return 返回参数见微信支付查询订单
     */
    @RequestMapping(params = "getWeiXinPayOrderSuccess")
    @ResponseBody
    public Page<Map<String, Object>> getWeiXinPayOrderSuccess(HttpServletRequest request,
                                                              HttpServletResponse response,
                                                              @RequestParam(required = false) String transactionId,
                                                              @RequestParam(required = false) String outTradeNo,
                                                              Page<Map<String, Object>> page) {
        try {
            // 获取生成预支付订单的请求类
            PreRequestHandler preSelectReqHandler = new PreRequestHandler(request, response);
            preSelectReqHandler.setParameter("appid", ConstantUtil.APP_ID);
            preSelectReqHandler.setParameter("mch_id", ConstantUtil.MCH_ID);
            String nonce_str = WXUtil.getNonceStr();
            preSelectReqHandler.setParameter("nonce_str", nonce_str);
            if (com.senta.base.utils.StringUtil.isNotEmpty(transactionId)) {
                preSelectReqHandler.setParameter("transaction_id ", transactionId);
            } else {
                preSelectReqHandler.setParameter("out_trade_no", outTradeNo);
            }
            /**
             * 注意签名(sign)的生成方式,具体见官方文档(传参都要参与生成签名,且参数名按照字典序排序,最后接上APP_KEY,转化成大写)
             */
            preSelectReqHandler.setParameter("sign", preSelectReqHandler.createMD5Sign());
            preSelectReqHandler.setGateSelectUrl(ConstantUtil.GATESELECTURL);
            Map<String, String> preSelectMap = preSelectReqHandler.sendPreSelect();
            //判断是否成功
            if (com.senta.base.utils.StringUtil.isNotEmpty(preSelectMap.get("trade_state")) && "SUCCESS".equals(preSelectMap.get("trade_state"))) {
                //处理订单信息  也可不处理 看具体业务
                
                }
                page.setSuccess(true);
            }
            //处理返回参数


            page.setObj(preSelectMap);
        } catch (Exception e) {
            e.printStackTrace();
            page.setMessage("异常!");
            return page;
        }
        return page;
    }
14、退款操作

退款是需要证书的,下载下来放在某个目录

调用 WXUtil.payHttps  方法时修改方法里的

String path = ResourceUtil.getConfigByName("pay.weixin.certificate.localaddress");

这里的path是我在配置文件里配的证书路径   改为自己的证书存放路径

ex: path="D:/weixinZS/apiclient_cert.p12"

app微信支付-java服务端接口 支付-查询-退款第1张

    /**
     * 微信退款
     * 此处用的  自己生成的订单号  就是上面支付中生成的订单号
     * @param request
     * @param response
     * @return 返回参数见微信支付查询订单
     */
    @RequestMapping(params = "weiXinPayOrderRefund")
    @ResponseBody
    public Page<Map<String, Object>> weiXinPayOrderRefund(HttpServletRequest request,
                                                          HttpServletResponse response,
                                                          @RequestParam(required = false) String transactionId,
                                                          @RequestParam(required = false) String outTradeNo,
                                                          Page<Map<String, Object>> page) {
        try {
          //transactionId为微信订单号   我没用这个号
//查询订单信息 根据订单号 这里是我自己的订单信息 此处换成自己 的
PayOrderEntity payOrder
= getPayOrderByNo(outTradeNo);
if (payOrder == null || com.senta.base.utils.StringUtil.isEmpty(payOrder.getId()))
{ page.setMessage(
"订单号有误!"); }
else if (!"1".equals(payOrder.getStatus()))
{ page.setMessage(
"该订单不能进行退款!"); }
else {
// 获取生成预支付订单的请求类 PreRequestHandler preRefundReqHandler = new PreRequestHandler(request, response); preRefundReqHandler.setParameter("appid", ConstantUtil.APP_ID); preRefundReqHandler.setParameter("mch_id", ConstantUtil.MCH_ID); String outRefundNo = payOrder.getOutRefundNo(); if (com.senta.base.utils.StringUtil.isEmpty(outRefundNo)) { payOrder.setOutRefundNo(OrderNumUtil.orderDatrNum()); } preRefundReqHandler.setParameter("out_refund_no", payOrder.getOutRefundNo()); String nonce_str = WXUtil.getNonceStr(); preRefundReqHandler.setParameter("nonce_str", nonce_str); if (com.senta.base.utils.StringUtil.isNotEmpty(transactionId)) { preRefundReqHandler.setParameter("transaction_id ", transactionId); } else { preRefundReqHandler.setParameter("out_trade_no", outTradeNo); } int total_fee = (payOrder.getCost().multiply(new BigDecimal(100))).intValue();//金额以分为单位 preRefundReqHandler.setParameter("total_fee", String.valueOf(total_fee));//订单金额 preRefundReqHandler.setParameter("refund_fee", String.valueOf(total_fee));//退款金额 /** * 注意签名(sign)的生成方式,具体见官方文档(传参都要参与生成签名,且参数名按照字典序排序,最后接上APP_KEY,转化成大写) */ preRefundReqHandler.setParameter("sign", preRefundReqHandler.createMD5Sign()); preRefundReqHandler.setGateSelectUrl(ConstantUtil.GATEREFUNDURL); String preSelectXml = preRefundReqHandler.sendPreSelectXml(); String retur = WXUtil.payHttps(ConstantUtil.GATEREFUNDURL, preSelectXml); Map returnMap = new HashMap(); if (com.senta.base.utils.StringUtil.isNotEmpty(retur)) { returnMap = WXUtil.parseXmlToMap(retur); //判断是否成功 if (com.senta.base.utils.StringUtil.isNotEmpty(returnMap.get("result_code")) && "SUCCESS".equals(returnMap.get("result_code"))) { //处理订单信息 //根据订单号查询订单信息//修改订单信息 修改支付状态 为退款状态 page.setSuccess(true); } } //处理返回参数 也可不处理 这里处理 返回值参考微信文档 page.setObj(returnMap); } } catch (Exception e) { e.printStackTrace(); page.setMessage("异常!"); return page; } return page; }

免责声明:文章转载自《app微信支付-java服务端接口 支付-查询-退款》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Gyp语法规则参考 &amp;amp; 工具的使用Eclipse-离线安装Memory Anlysis Tool下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android随笔之——用shell脚本模拟用户按键、触摸操作

  之前写过两篇关于Android中模拟用户操作的博客(其实用一篇是转载的),现在就来讲讲用shell脚本来模拟用户按键操作。本次的目标是用shell脚本打开微信并在其搜索框中搜索相关内容。   本文的模拟功能主要是用adb的input命令来实现,如果你adb的环境变量配置正确的话,在cmd中输入 adb shell input 就可以看见input的用法...

UE4在Android调用Project Tango

  Project Tango应该说是Google一试水AR的设备,其中Project Tango主要二个功能,一个是获取深度信息,如MS的Kinect,有相当多的设备都有这个功能,二是第一人称相对定位,这个就没那么常见了,如果对这个设备有更深的兴趣,可以看知乎上的这二个链接。   Google Project Tango获取深度信息的原理是什么?   P...

Java高并发网络编程(四)Netty

在网络应用开发的过程中,直接使用JDK提供的NIO的API,比较繁琐,而且想要进行性能提升,还需要结合多线程技术。 由于网络编程本身的复杂性,以及JDK API开发的使用难度较高,所以在开源社区中,涌现出来了很多对JDK NIO进行封装、增强的网络编程框架,比如Netty、Mina等。 一、Netty简介 https://netty.io/官网 Netty...

Java 反射原理

一、Java 反射的定义 反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法或者属性; 二、反射提供的功能: 在运行时判断任意一个对象所属的类; 在运行时构造任意一个类的对象; 在运行时判断任意一个类所具有的成员变量和方法; 在运行时调用任意一个对象的方法; 生成...

使用springcloud gateway搭建网关(分流,限流,熔断)

Spring Cloud Gateway Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。 Spring Cloud Gatewa...

string易错点整理总结

简单说 string 就是char[],本质是一个16位Unicode字符数组,在托管堆,不在GC堆 string 和System.String string 是C#语言的基元类型,类似于int,long等等,简化了语言代码,带来便捷可读性,System.String是FCL的基本类型,和有直接的映射关系,从IL角度看,两者之间没有任何不同 恒定性:...