第一次做微信支付,阅读完开发文档后,下了个官方deml,摸索了好久,期间也出现了好多问题,终于是实现生成预支付订单以及支付成功后接收微信服务器通知,不多说了,直接上代码:
一、工具类
ConstantUtil.java
public class ConstantUtil { /** * 微信开发平台应用ID */ public static final String APP_ID="wx0a3242424aae13c6"; /** * 应用对应的凭证 */ public static final String APP_SECRET="1d29d733ewrewrfwed1b58968cce"; /** * 应用对应的密钥 */ public static final String APP_KEY="dfsfdvdfvgk32423423oGdfsfdsvBO66"; /** * 微信支付商户号 */ public static final String MCH_ID="1469dfsf02"; /** * 商品描述 */ public static final String BODY="QQ游戏-账户充值"; /** * 商户号对应的密钥 */ public static final String PARTNER_key="123466"; /** * 商户id */ public static final String PARTNER_ID="14698sdfs402dsfdew402"; /** * 常量固定值 */ 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 NOTIFY_URL="http://www.bairuoheng.cn/app/notify"; }
Md5Util.java
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" }; }
HttpClientUtil.java
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 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 trustFile * @param trustPasswd * @param keyFile * @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); } }
TenpayUtil.java
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); } }
WXUtil.java
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); } }
UUID.java
public class UUID { 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 long 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 Long.parseLong(str); } private UUID(){ } }
二、请求响应处理以及客户端处理类
ResponseHandler.java
/** * 应答处理类 * 应答处理类继承此类,重写isTenpaySign方法即可。 * */ 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; } }
RequestHandler.java
/** * 请求处理类 * 请求处理类继承此类,重写createSign方法即可。 * */ 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; } }
ClientRequestHandler.java
public class ClientRequestHandler extends PrepayIdRequestHandler { public ClientRequestHandler(HttpServletRequest request, HttpServletResponse response) { super(request, response); // TODO Auto-generated constructor stub } public String getXmlBody() { 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(); if (!"appkey".equals(k)) { sb.append("<" + k + ">" + v + "<" + k + ">" + "\r\n"); } } return sb.toString(); } }
PaypreIdRequestHandler.java
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; } }
TenpayHttpClient.java
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(); } }
ClientResponseHandler.java
public class ClientResponseHandler { /** 应答原始内容 */ private String content; /** 应答的参数 */ private SortedMap parameters; /** 密钥 */ private String key; /** 字符集 */ private String charset; public ClientResponseHandler() { this.content = ""; this.parameters = new TreeMap(); this.key = ""; this.charset = "utf8"; } public String getContent() { return content; } public void setContent(String content) throws Exception { this.content = content; this.doParse(); } /** * 获取参数值 * @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; } /** *获取密钥 */ public String getKey() { return key; } /** *设置密钥 */ public void setKey(String key) { this.key = key; } public String getCharset() { return this.charset; } public void setCharset(String charset) { this.charset = charset; } /** * 是否财付通签名,规则是:按参数名称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 sign = MD5Util.MD5Encode(sb.toString(), this.charset).toLowerCase(); String tenpaySign = this.getParameter("sign").toLowerCase(); return tenpaySign.equals(sign); } /** * 是否财付通签名 * @param signParameterArray 签名的参数数组 * @return boolean */ protected boolean isTenpaySign(String signParameterArray[]) { StringBuffer signPars = new StringBuffer(); for(int index = 0; index < signParameterArray.length; index++) { String k = signParameterArray[index]; String v = this.getParameter(k); if(null != v && !"".equals(v)) { signPars.append(k + "=" + v + "&"); } } signPars.append("key=" + this.getKey()); //算出摘要 String sign = MD5Util.MD5Encode( signPars.toString(), this.charset).toLowerCase(); String tenpaySign = this.getParameter("sign").toLowerCase(); return tenpaySign.equals(sign); } /** * 解析XML内容 */ protected void doParse() throws JDOMException, IOException { String xmlContent = this.getContent(); //解析xml,得到map Map m = XMLUtil.doXMLParse(xmlContent); //设置参数 Iterator it = m.keySet().iterator(); while(it.hasNext()) { String k = (String) it.next(); String v = (String) m.get(k); this.setParameter(k, v); } } }
三、控制类的实现
TenpayController.java
@Controller @Scope("prototype") public class TenPayController { @Autowired private PayRecordService payRecordService; @Autowired private AppCustomerService appCustomerService; private String out_trade_no = ""; /** * 生成预支付订单,获取prepayId * @param request * @param response * @return * @throws Exception */ @Auth @RequestMapping(value = "/app/tenpay/prepay", method = RequestMethod.POST) public @ResponseBody Map<String, Object> getOrder(HttpServletRequest request, HttpServletResponse response) throws Exception { Map<String, Object> map = new HashMap<String, Object>(); // 获取生成预支付订单的请求类 PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response); String totalFee = request.getParameter("total_fee"); int total_fee=(int) (Float.valueOf(totalFee)*100); System.out.println("total:"+total_fee); System.out.println("total_fee:" + total_fee); 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", ConstantUtil.NOTIFY_URL); out_trade_no = String.valueOf(UUID.next()); prepayReqHandler.setParameter("out_trade_no", out_trade_no); prepayReqHandler.setParameter("spbill_create_ip", "127.0.0.1"); String timestamp = WXUtil.getTimeStamp(); prepayReqHandler.setParameter("time_start", timestamp); System.out.println(String.valueOf(total_fee)); prepayReqHandler.setParameter("total_fee", String.valueOf(total_fee)); 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("")) { PayRecord payRecord=new PayRecord(); AppCustomer appCustomer=(AppCustomer) request.getSession().getAttribute("appCustomer"); payRecord.setPhone(appCustomer.getPhone()); payRecord.setSerialId(Long.valueOf(out_trade_no)); payRecord.setType((byte)2); payRecord.setGenerateTime(new Date()); payRecord.setTotalAmount(Float.valueOf(total_fee)/100); payRecordService.insert(payRecord); String signs = "appid=" + ConstantUtil.APP_ID + "&noncestr=" + nonce_str + "&package=Sign=WXPay&partnerid=" + ConstantUtil.PARTNER_ID + "&prepayid=" + prepayid + "×tamp=" + timestamp + "&key=" + ConstantUtil.APP_KEY; map.put("code", 0); map.put("info", "success"); map.put("prepayid", prepayid); /** * 签名方式与上面类似 */ map.put("sign", MD5Util.MD5Encode(signs, "utf8").toUpperCase()); map.put("appid", ConstantUtil.APP_ID); map.put("timestamp", timestamp); //等于请求prepayId时的time_start map.put("noncestr", nonce_str); //与请求prepayId时值一致 map.put("package", "Sign=WXPay"); //固定常量 map.put("partnerid", ConstantUtil.PARTNER_ID); } else { map.put("code", 1); map.put("info", "获取prepayid失败"); } return map; } /** * 接收微信支付成功通知 * @param request * @param response * @throws IOException */ @Auth @RequestMapping(value = "/app/tenpay/notify") 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")) { System.out.println("充值成功!"); PayRecord payRecord=payRecordService.get(Long.valueOf(map.get("out_trade_no"))); System.out.println("订单号:"+Long.valueOf(map.get("out_trade_no"))); System.out.println("payRecord.getPayTime():"+payRecord.getPayTime()==null+","+payRecord.getPayTime()); //判断通知是否已处理,若已处理,则不予处理 if(payRecord.getPayTime()==null){ System.out.println("通知微信后台"); payRecord.setPayTime(new Date()); String phone=payRecord.getPhone(); AppCustomer appCustomer=appCustomerService.getByPhone(phone); float balance=appCustomer.getBalance(); balance+=Float.valueOf(map.get("total_fee"))/100; appCustomer.setBalance(balance); appCustomerService.update(appCustomer); payRecordService.update(payRecord); String notifyStr = XMLUtil.setXML("SUCCESS", ""); writer.write(notifyStr); writer.flush(); } } } } }