与微信通信常用工具(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;
}
}