java 微信開發 常用工具類(xml傳輸和解析 json轉換物件)
阿新 • • 發佈:2019-01-04
package com.lownsun.wechatOauth.utl; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.lownsun.wechatOauth.dm.domain.bean.WeiXinPrePay; public class WeiXinPayUtil { private static Logger log = Logger.getLogger(WeiXinPayUtil.class);//日記類記錄日記 /** * * 傳送xml資料,獲取返回結果封裝為map集合 * @param requestUrl 請求介面地址 * @param requestMethod 請求方式(get或post) * @param outputStr 預支付xml(封裝資料) * @return map集合 */ public static Map<String, Object> httpXmlRequest(String requestUrl, String requestMethod, String outputStr) { // 將解析結果儲存在HashMap中 Map<String, Object> map = new HashMap<String, Object>(); try { TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 從上述SSLContext物件中得到SSLSocketFactory物件 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); // 代表一個絕對地址 HttpsURLConnection httpUrlConn = (HttpsURLConnection) url .openConnection(); // 返回一個url物件 httpUrlConn.setSSLSocketFactory(ssf); // 設定當此例項為安全 https URL // 連線建立套接字時使用的 httpUrlConn.setDoOutput(true); // 以後就可以使用conn.getOutputStream().write() httpUrlConn.setDoInput(true); // 以後就可以使用conn.getInputStream().read(); httpUrlConn.setUseCaches(false); // 請求不可以使用快取 // 設定請求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); // 設定請求方式 資料從引數傳來 if ("post".equalsIgnoreCase(requestMethod)) // 判斷是否為get請求 httpUrlConn.connect(); // 連線 // 當有資料需要提交時 if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 獲取輸出流 // 注意編碼格式,防止中文亂碼 outputStream.write(outputStr.getBytes("UTF-8")); // 向物件輸出流寫出資料,這些資料將存到記憶體緩衝區中 outputStream.close(); // 關閉流 } // 將返回的輸入流轉換成字串 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); // 讀取輸入流 SAXReader reader = new SAXReader(); Document document = reader.read(inputStreamReader); // 得到xml根元素 Element root = document.getRootElement(); // 得到根元素的所有子節點 @SuppressWarnings("unchecked") List<Element> elementList = root.elements(); // 遍歷所有子節點 for (Element e : elementList) { map.put(e.getName(), e.getText()); } inputStreamReader.close(); inputStream.close(); inputStream = null; httpUrlConn.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); log.error(e.getMessage()); } catch (IOException e) { e.printStackTrace(); log.error(e.getMessage()); } catch (Exception e) { e.printStackTrace(); log.error(e.getMessage()); } return map; } /** * 解析微信發來的請求(XML) * * @param inputStream * @return * @throws Exception */ @SuppressWarnings("unchecked") public static Map<String, String> parseXml(InputStream inputStream) throws Exception { if (inputStream == null){ return null; } Map<String, String> map = new HashMap<String, String>();// 將解析結果儲存在HashMap中 SAXReader reader = new SAXReader();// 讀取輸入流 Document document = reader.read(inputStream); Element root = document.getRootElement();// 得到xml根元素 List<Element> elementList = root.elements();// 得到根元素的所有子節點 for (Element e : elementList) { // 遍歷所有子節點 map.put(e.getName(), e.getText()); } inputStream.close(); // 釋放資源 inputStream = null; return map; } /** * 對傳輸資料封裝 * @param nonce 隨機數 * @param opid 關注使用者的opendid * @param orderDate 訂單日期 * @param orderNo 訂單號 * @param notify_url 回撥連結 * @param body 商品簡單描述 * @param integer 金額 * @param attach 商家資料包(原樣返回) * @param mchid 商戶號 * @param appid 公眾號 * @param string ip地址 * */ public WeiXinPrePay getBean(String appid, String mchid, String attach, Integer integer, String body, String notify_url, String orderNo, String orderDate, String opid, String nonce, String string){ WeiXinPrePay weiXinPrePay = new WeiXinPrePay(); weiXinPrePay.setAppid(appid); weiXinPrePay.setMchId(mchid); weiXinPrePay.setAttach(attach); weiXinPrePay.setTotalFee(integer*100); weiXinPrePay.setBody(body); weiXinPrePay.setNotifyUrl(notify_url); weiXinPrePay.setOutTradeNo(orderNo); weiXinPrePay.setTimeStart(orderDate); weiXinPrePay.setOpenid(opid); weiXinPrePay.setNonceStr(nonce); weiXinPrePay.setSpbillCreateIp(string); // 地址 return weiXinPrePay; } /** * 生成預支付XML * @param weiXinPrePay 預支付實體類 * @param partnerKey 支付密匙 * @return */ public static String getPrePayXml(WeiXinPrePay weiXinPrePay,String partnerKey){ /**生成預支付請求籤名 (並封裝 sign)*/ getPrePaySign(weiXinPrePay, partnerKey); StringBuilder sb = new StringBuilder(); sb.append("<xml><appid>").append(weiXinPrePay.getAppid()).append("</appid>"); //公眾賬號ID sb.append("<attach>").append(weiXinPrePay.getAttach()).append("</attach>"); //附加資料 sb.append("<body>").append(weiXinPrePay.getBody()).append("</body>"); //商品描述 sb.append("<mch_id>").append(weiXinPrePay.getMchId()).append("</mch_id>"); sb.append("<nonce_str>").append(weiXinPrePay.getNonceStr()).append("</nonce_str>"); //隨機數 sb.append("<notify_url>").append(weiXinPrePay.getNotifyUrl()).append("</notify_url>"); //回撥地址 sb.append("<openid>").append(weiXinPrePay.getOpenid()).append("</openid>"); //使用者表示符 sb.append("<out_trade_no>").append(weiXinPrePay.getOutTradeNo()).append("</out_trade_no>"); //訂單號 sb.append("<spbill_create_ip>").append(weiXinPrePay.getSpbillCreateIp()).append("</spbill_create_ip>"); //終端ip sb.append("<total_fee>").append(weiXinPrePay.getTotalFee()).append("</total_fee>"); //總金額 sb.append("<trade_type>").append(weiXinPrePay.getTrade_type()).append("</trade_type>"); //交易型別 sb.append("<sign>").append(weiXinPrePay.getSign()).append("</sign>"); //簽名 sb.append("</xml>"); return sb.toString(); } /** * 獲取預支付請求籤名 * @param weiXinPrePay 預支付實體類 * @param partnerKey 支付key * @return 簽名 */ private static void getPrePaySign(WeiXinPrePay weiXinPrePay,String partnerKey){ Map<String, Object> prePayMap = new HashMap<String, Object>(); prePayMap.put("appid", weiXinPrePay.getAppid());// 公眾賬號ID prePayMap.put("attach", weiXinPrePay.getAttach()); prePayMap.put("body", weiXinPrePay.getBody()); // 商品描述 prePayMap.put("mch_id", weiXinPrePay.getMchId()); // 商戶號 prePayMap.put("nonce_str", weiXinPrePay.getNonceStr()); // 隨機字串 prePayMap.put("notify_url", weiXinPrePay.getNotifyUrl()); // 支付成功跳轉的面頁 prePayMap.put("openid",weiXinPrePay.getOpenid()); prePayMap.put("out_trade_no", weiXinPrePay.getOutTradeNo()); // 商戶訂單號 prePayMap.put("spbill_create_ip", weiXinPrePay.getSpbillCreateIp()); // 終端IP prePayMap.put("total_fee", weiXinPrePay.getTotalFee()); // 總金額 prePayMap.put("trade_type", weiXinPrePay.getTrade_type()); //########################### 上面是需要簽名的資料 ######################################## String argPreSign = getStringByMap(prePayMap) + "&key=" + partnerKey; String preSign = MD5Util.encode(argPreSign).toUpperCase(); System.out.println("統一下單簽名"+preSign); weiXinPrePay.setSign(preSign);//封裝sign } /** * js面頁 簽名 * @param packageParams 集合(appid,timeStamp,nonceStr,Package,signType) * @param key 密匙(支付密匙) * @return 返回簽名 */ public static String createSign(SortedMap<String, String> packageParams ,String key) { StringBuffer sb = new StringBuffer(); Set es = packageParams.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=" + key); System.out.println("md5 sb:" + sb+"key="+key); //加密簽名 String sign = MD5Util.encode(sb.toString()).toUpperCase(); System.out.println("packge 面頁簽名:" + sign); return sign; } /** * 面頁js(介面需要)時間戳 */ public static String getTimeStamp() { return String.valueOf(System.currentTimeMillis() / 1000); } /** * 隨機數(時間戳+5位隨機數) */ public static String getTime(){ long timeMillis = System.currentTimeMillis(); int run = (int) Math.ceil(((Math.random()*9+1)*10000)); String round= timeMillis+""+run; return round; } /** * 根據Map獲取排序拼接後的字串(排序) * @param map * @return */ public static String getStringByMap(Map<String, Object> map) { SortedMap<String, Object> smap = new TreeMap<String, Object>(map); StringBuffer sb = new StringBuffer(); for (Map.Entry<String, Object> m : smap.entrySet()) { sb.append(m.getKey()).append("=").append(m.getValue()).append("&"); } sb.delete(sb.length() - 1, sb.length()); return sb.toString(); } public static String getStringByStringMap(Map<String, String> map) { SortedMap<String, Object> smap = new TreeMap<String, Object>(map); StringBuffer sb = new StringBuffer(); for (Map.Entry<String, Object> m : smap.entrySet()) { sb.append(m.getKey()).append("=").append(m.getValue()).append("&"); } sb.delete(sb.length() - 1, sb.length()); return sb.toString(); } /** * 判斷是否來自微信, 5.0 之後的支援微信支付 * @param request * @return */ public static boolean isWeiXin(HttpServletRequest request) { String userAgent = request.getHeader("User-Agent"); if (StringUtils.isNotBlank(userAgent)) { Pattern p = Pattern.compile("MicroMessenger/(\\d+).+"); Matcher m = p.matcher(userAgent); String version = null; if (m.find()) { version = m.group(1); } return (null != version && NumberUtils.toInt(version) >= 5); } return false; } /** * 獲取客戶端的IP地址 * * @return */ public static String getIpAddr(HttpServletRequest request) { String ipAddress = null; ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) { // 根據網絡卡取本機配置的IP InetAddress inet = null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { log.error("未知主機",e); } ipAddress = inet.getHostAddress(); } } // 對於通過多個代理的情況,第一個IP為客戶端真實IP,多個IP按照','分割 if (ipAddress != null && ipAddress.length() > 15) { if (ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } return ipAddress; } /** * 給微信返回值 * @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>"; } /** * 發起https請求並獲取結果 * @author Administrator * requesturl 請求地址 * requestMethod 請求方法 * outpustr 返回資料 */ public static String httpRequest(String requestUrl, String requestMethod, String outputStr) { Logger logger = Logger.getLogger(WeixinUtil.class);//日記類記錄日記 StringBuffer buffer = new StringBuffer(); // 拼接字串 try { // 建立SSLContext物件,並使用我們指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 從上述SSLContext物件中得到SSLSocketFactory物件 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); // 代表一個絕對地址 HttpsURLConnection httpUrlConn = (HttpsURLConnection) url .openConnection(); // 返回一個url物件 httpUrlConn.setSSLSocketFactory(ssf); // 設定當此例項為安全 https URL // 連線建立套接字時使用的 httpUrlConn.setDoOutput(true); // 以後就可以使用conn.getOutputStream().write() httpUrlConn.setDoInput(true); // 以後就可以使用conn.getInputStream().read(); httpUrlConn.setUseCaches(false); // 請求不可以使用快取 // 設定請求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); // 設定請求方式 資料從引數傳來 if ("GET".equalsIgnoreCase(requestMethod)) // 判斷是否為get請求 httpUrlConn.connect(); // 連線 // 當有資料需要提交時 if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 獲取輸出流 // 注意編碼格式,防止中文亂碼 outputStream.write(outputStr.getBytes("UTF-8")); // 向物件輸出流寫出資料,這些資料將存到記憶體緩衝區中 outputStream.close(); // 關閉流 } // 將返回的輸入流轉換成字串 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader( inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader( inputStreamReader); String str = null; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); // 把讀進來的資料新增到append } bufferedReader.close(); // 關閉管道 inputStreamReader.close(); // 關閉流 // 釋放資源 inputStream.close(); // 關閉流 inputStream = null; // 設定為空 httpUrlConn.disconnect(); } catch (ConnectException ce) { logger.error("Weixin server connection timed out.",ce); // 連接出錯列印日記 } catch (Exception e) { logger.error("https request error:{}", e); // 連接出錯列印日記 } return buffer.toString(); // 返回拼接的資料(返回的是json資料) } } ////////////////////微信常用介面的實現////////////////////////////////////// public class RemoteWeixinMethodIimp implements RemoteWeixinMethodI{ private static Logger log = Logger.getLogger(RemoteWeixinMethodIimp.class); /**檢查授權是否有效*/ @Override public WechatMsg checkAccessToken(String access_token, String openid) { String requestMethod = "GET"; //get方法呼叫 String outputStr = ""; String url = WeiXinOpenConstants.WEB_CHECK_OAUTH.replace( "access_token", access_token).replace("openid", openid); String httpmsg = WeixinUtil.httpRequest(url, requestMethod, outputStr); //返回json資料(狀態碼) System.out.println("檢驗授權憑證==" + httpmsg); Gson gson = new Gson(); //json資料轉換為物件 WechatMsg msg = gson.fromJson(httpmsg, WechatMsg.class); return msg; //返回一個物件 } /**通過網頁授權*/ @Override public AccessTokenModel getAccessToken(String AppID, String AppSecret, String coode) { String Code = coode; if (Code != null) { //使用者通用授權返回資料 String requestMethod = "GET"; String outputStr = ""; String url = WeiXinOpenConstants.WEB_OAUTH_ACCESSTOKEN_URL .replace("APPID", AppID).replace("SECRET", AppSecret) .replace("CODE", Code); String http = WeixinUtil.httpRequest(url, requestMethod,outputStr); //返回json資料(網頁授權) Gson gson = new Gson(); AccessTokenModel msg = gson.fromJson(http, AccessTokenModel.class); //json封裝物件 return msg; } else { //request.getRequestDispatcher("index.jsp").forward(request, response); //轉到授權失敗面頁 return null; } } /**獲取使用者資訊(授權)*/ @Override public WechatUser getUseInfo(AccessTokenModel userinfo) { String requestMethod = "GET"; String outputStr=""; String url = WeiXinOpenConstants.WEB_USE_INFO.replace("ACCESS_TOKEN", userinfo.getAccess_token()).replace("ACCESS_TOKEN", userinfo.getOpenid()); String http= WeixinUtil.httpRequest(url, requestMethod, outputStr); //返回json資料(使用者基本資訊) Gson gson = new Gson(); //json資料轉換為物件 WechatUser msg=gson.fromJson(http, WechatUser.class); return msg; } /**重新整理憑證*/ @Override public AccessTokenModel refreshToken(String appid) { String requestMethod = "GET"; String outputStr=""; String url = WeiXinOpenConstants.WEB_REFRESH_TOKEN.replace("appid", appid); String http = WeixinUtil.httpRequest(url, requestMethod, outputStr); //返回json資料(網頁授權) Gson gson = new Gson(); AccessTokenModel msg=gson.fromJson(http, AccessTokenModel.class);//封裝物件 return msg; } /**獲取關注使用者基本資訊(關注)*/ @Override public Wxuser getUserInfo(String access_token, String openid) { String requestMethod="GET"; String outputStr=""; String url= WeiXinOpenConstants.WEB_USE_INFO.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid); String http = WeixinUtil.httpRequest(url, requestMethod, outputStr); //返回json資料(使用者資訊) Gson gson=new Gson(); Wxuser wxuser =gson.fromJson(http, Wxuser.class);//封裝物件 return wxuser; } }
package com.lownsun.wechatOauth.utl; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import javax.servlet.http.HttpSession; public class WeixinSampleUtil { /** * 隨機數生成驗證碼 * @return 驗證碼 */ public static String creatNumber(){ int number = (int)Math.ceil((Math.random()*10000));//4位隨機數向上取整 return number+""; } /** * 傳送簡訊 * @param phone 使用者的手機號碼 * @param content 簡訊內容 * @return */ public static String sendMess(String phone , String content){ String Username = "ycjl"; //在簡訊寶註冊的使用者名稱 String Password = "weiyudns"; //在簡訊寶註冊的密碼 StringBuffer httpArg = new StringBuffer(); httpArg.append("u=").append(Username).append("&"); httpArg.append("p=").append(md5(Password)).append("&"); httpArg.append("m=").append(phone).append("&"); httpArg.append("c=").append(encodeUrlString(content, "UTF-8")); String httpUrl=WeiXinOpenConstants.SAMPLE; String result = request(httpUrl, httpArg.toString()); return result; } /** * 傳送連結 * @param httpUrl 介面連結 * @param httpArg 拼接引數 * @return */ public static String request(String httpUrl, String httpArg) { BufferedReader reader = null; String result = null; StringBuffer sbf = new StringBuffer(); httpUrl = httpUrl + "?" + httpArg; try { URL url = new URL(httpUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.connect(); InputStream is = connection.getInputStream(); reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); String strRead = reader.readLine(); if (strRead != null) { sbf.append(strRead); while ((strRead = reader.readLine()) != null) { sbf.append("\n"); sbf.append(strRead); } } reader.close(); result = sbf.toString(); } catch (Exception e) { e.printStackTrace(); } return result; } /** * md5加密 * @param plainText 密碼 * @return */ public static String md5(String plainText) { StringBuffer buf = null; try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(plainText.getBytes()); byte b[] = md.digest(); int i; buf = new StringBuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) i += 256; if (i < 16) buf.append("0"); buf.append(Integer.toHexString(i)); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return buf.toString(); } /** * 對內容進行encodeUrl編碼 * @param str 傳送內容 * @param charset 編碼型別“utf-8” * @return */ public static String encodeUrlString(String str, String charset) { String strret = null; if (str == null) return str; try { strret = java.net.URLEncoder.encode(str, charset); } catch (Exception e) { e.printStackTrace(); return null; } return strret; } }
/** * <b>功能說明:MD5簽名工具類 */ public class MD5Util { private static final Logger LOG = LoggerFactory.getLogger(MD5Util.class); /** * 私有構造方法,將該工具類設為單例模式. */ private MD5Util() { } private static final String[] hex = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; public static String encode(String password) { try { MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] byteArray = md5.digest(password.getBytes("utf-8")); String passwordMD5 = byteArrayToHexString(byteArray); return passwordMD5; } catch (Exception e) { LOG.error(e.toString()); } return password; } private static String byteArrayToHexString(byte[] byteArray) { StringBuffer sb = new StringBuffer(); for (byte b : byteArray) { sb.append(byteToHexChar(b)); } return sb.toString(); } private static Object byteToHexChar(byte b) { int n = b; if (n < 0) { n = 256 + n; } int d1 = n / 16; int d2 = n % 16; return hex[d1] + hex[d2]; } } /** * 證書信任管理器(用於https請求) * @author Administrator * */ public class MyX509TrustManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }