與微信通信常用工具(xml傳輸和解析)
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;
}
}
對 https 請求需要的輔助類
/**
* <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;
}
}