我的不怎麼看得懂微信的文檔,看了不少前輩的寫法,終於調通了,在這裏作一下記錄。前端
首先來定義各類處理類(微信支付不須要特殊jar包,不少處理須要本身封裝,固然也能夠本身寫完打個jar包)java
參數要用jdom解析 自行導入jar包 git
或者在maven pom.xml中導入 apache
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1.3</version>
</dependency>
version根據本身maven庫中版本號進行設置
/** * 微信支付請求常量 * 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";
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("\r\n"); } 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); }
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 "異常"; } } }
四、訂單號生成類 這個能夠自行判斷要不要(只要不重複就行) 我是提早有個訂單信息 前端直接給我訂單號,固然訂單號也是用這個類生成的。json
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; } }
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; } }
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; } }
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; } }
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(); } }
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; } }
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())); }*/ }
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; } }
(生成簽名 獲取 prePayId) 返回給APP端api
此處參數除 都可根據具體業務自定義 只要可獲取平臺需支付的信息便可數組
返回參數與前端商量 此處返回的Map 也可返回json字符串 或者後臺統一的類型緩存
/** * 微信生成預支付訂單,獲取prepayId * * @param request * @param out_trade_no 訂單號 * @param total_fee 支付金額 * @param payType 支付類型 一、支付寶 二、微信 * @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("×tamp=" + 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", ""); }
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; }
退款是須要證書的,下載下來放在某個目錄服務器
調用 WXUtil.payHttps 方法時修改方法裏的微信
String path = ResourceUtil.getConfigByName("pay.weixin.certificate.localaddress");
這裏的path是我在配置文件裏配的證書路徑 改成本身的證書存放路徑
ex: path="D:/weixinZS/apiclient_cert.p12"
/** * 微信退款 * 此處用的 本身生成的訂單號 就是上面支付中生成的訂單號 * @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; }