个人不怎么看得懂微信的文档,看了很多前辈的写法,终于调通了,在这里做一下记录。
首先来定义各种处理类(微信支付不需要特殊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("×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", ""); }
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"
/** * 微信退款 * 此处用的 自己生成的订单号 就是上面支付中生成的订单号 * @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; }