package com.iamberry.wechat.utils; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.ConnectException; import java.net.URL; import java.net.URLEncoder; import java.util.Date; import java.util.logging.Logger; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import net.sf.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.iamberry.app.tool.log.RatFWLogger; import com.iamberry.wechat.core.entity.wx.AccessToken; import com.iamberry.wechat.core.entity.wx.ITTempLate; import com.iamberry.wechat.core.entity.wx.Menu; import com.iamberry.wechat.core.entity.wx.QRCJson; import com.iamberry.wechat.core.entity.wx.Ticket; import com.iamberry.wechat.core.entity.wx.Token; import com.iamberry.wechat.face.wechat.TokenService; import com.iamberry.wechat.tools.MyX509TrustManager; import com.iamberry.wechat.tools.NameUtils; /** * @company 深圳爱贝源科技有限公司 * @website www.iamberry.com * @author 献 * @tel 18271840547 * @date 2016年11月3日 * @explain 微信公众平台通用接口工具类 */ @Component public class WeixinUtil { @Autowired private RatFWLogger logger; @Autowired private TokenService tokenService; private static String sendTemplate = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="; /** * 网页授权获取access_token * * @param code * @return */ public JSONObject getParamByOauth2(String code) { JSONObject jsonObject = null; // 得到access_token和openid jsonObject = httpRequest(NameUtils.oauth2_getToken_url.replaceAll("CODE", code).replaceAll("APPID", NameUtils.appId).replaceAll("SECRET", NameUtils.appSecret), "GET", null); if (null != jsonObject) { return jsonObject; } // 获取token失败 return null; } /** * 发起https请求并获取结果 * * @param requestUrl * 请求地址 * @param requestMethod * 请求方式(GET/POST) * @param outputStr * 提交的数据 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) * java.lang.ClassCastException: * sun.net.www.protocol.http.HttpURLConnection cannot be cast to * javax.net.ssl.HttpsURLConnection */ public JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; 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(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); httpUrlConn.setUseCaches(false); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); if ("GET".equalsIgnoreCase(requestMethod)) 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); } bufferedReader.close(); inputStreamReader.close(); // 释放资源 inputStream.close(); inputStream = null; httpUrlConn.disconnect(); jsonObject = JSONObject.fromObject(buffer.toString()); } catch (ConnectException ce) { Logger.getAnonymousLogger().info("Weixin server connection timed out."); } catch (Exception e) { Logger.getAnonymousLogger().info("信任管理器请求时..." + e); Logger.getAnonymousLogger().info("jsonObject..." + jsonObject); } return jsonObject; } /** * 获取access_token * @param appid 凭证 * @param appsecret 密钥 * @return */ public AccessToken getAccessToken(String appid, String appsecret) { // 查询缓存,如果是第一次,绝对为空 Token accessTokenMemory = StaticCacheMemory.getAccessToken(); if (accessTokenMemory != null) { if (new Date().getTime() < accessTokenMemory.getEndDate().getTime()) { AccessToken accessToken = new AccessToken(); accessToken.setExpiresIn(7200); accessToken.setToken(accessTokenMemory.getToken()); return accessToken; } } // 根据public No查询access_token Token token = tokenService.selectOne(NameUtils.pubNo); // 查询到了植入环境中 StaticCacheMemory.setAccessToken(token); AccessToken accessToken = null; //判断数据库中是否存在token if (token != null) { //判断token是否失效 Date date = new Date(); if (date.getTime() < token.getEndDate().getTime()) { accessToken = new AccessToken(); accessToken.setExpiresIn(7200); accessToken.setToken(token.getToken()); return accessToken; } else { String requestUrl = NameUtils.access_token_url.replace("APPID", NameUtils.appId).replace("APPSECRET", NameUtils.appSecret); JSONObject jsonObject = httpRequest(requestUrl, "GET", null); // 如果请求成功 if (null != jsonObject) { try { accessToken = new AccessToken(); accessToken.setToken(jsonObject.getString("access_token")); accessToken.setExpiresIn(jsonObject.getInt("expires_in")); token.setToken(accessToken.getToken()); token.setEndDate(new Date(date.getTime() + 6500000)); token.setAppid(NameUtils.pubNo); try { tokenService.updateToken(token); StaticCacheMemory.setAccessToken(token); } catch (Exception e) { System.out.println("更新token失败:" + e.getMessage()); } return accessToken; } catch (Exception e) { e.printStackTrace(); accessToken = null; // 获取token失败 Logger.getAnonymousLogger().info("获取token失败 errcode:{} errmsg:{}" + jsonObject.getInt("errcode") + jsonObject.getString("errmsg")); } } } } else { String requestUrl = NameUtils.access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret); JSONObject jsonObject = httpRequest(requestUrl, "GET", null); // 如果请求成功 if (null != jsonObject) { try { accessToken = new AccessToken(); accessToken.setToken(jsonObject.getString("access_token")); accessToken.setExpiresIn(jsonObject.getInt("expires_in")); token = new Token(); token.setToken(accessToken.getToken()); token.setEndDate(new Date(new Date().getTime() + 6500000)); token.setAppid(NameUtils.pubNo); try { tokenService.updateToken(token); StaticCacheMemory.setAccessToken(token); } catch (Exception e) { // 更新失败 } return accessToken; } catch (Exception e) { accessToken = null; // 获取token失败 Logger.getAnonymousLogger().info("获取token失败 errcode:{} errmsg:{}" + jsonObject.getInt("errcode") + jsonObject.getString("errmsg")); } } } return accessToken; } /** * 获取jsapi_ticket(jsapi_ticket的有效期为7200秒) * @param token * @return */ public Ticket getTicket(String token) { Ticket ticket = null; String requestUrl = NameUtils.jsapi_ticket_url.replace("ACCESS_TOKEN", token); JSONObject jsonObject = httpRequest(requestUrl, "GET", null); if (null == jsonObject) { // 网络异常 return null; } try { ticket = new Ticket(); ticket.setTicket(jsonObject.getString("ticket")); ticket.setExpiresIn(jsonObject.getInt("expires_in")); } catch (Exception e) { // 获取token失败 Logger.getAnonymousLogger().info("获取ticket失败 errcode:{} errmsg:{}" + jsonObject.getInt("errcode") + jsonObject.getString("errmsg")); // 判断错误信息是否为 access_token 失效的问题,只有access失效,我们才重新获取,否则每次获取可能导致access_token资源耗尽 if (jsonObject.getInt("errcode") != 40001) return null; // 强制刷新access_token,存在多线程安全隐患! requestUrl = NameUtils.access_token_url.replace("APPID", NameUtils.appId).replace("APPSECRET", NameUtils.appSecret); JSONObject accessTokenJsonObject = httpRequest(requestUrl, "GET", null); // 报错access_token信息,不管报错与否 Token wechatToken = new Token(); wechatToken.setEndDate(new Date(new Date().getTime() + 6500000)); wechatToken.setAppid(NameUtils.pubNo); wechatToken.setToken(accessTokenJsonObject.getString("access_token")); tokenService.updateToken(wechatToken); StaticCacheMemory.setAccessToken(wechatToken); // 重新获取一次 requestUrl = NameUtils.jsapi_ticket_url.replace("ACCESS_TOKEN", wechatToken.getToken()); jsonObject = httpRequest(requestUrl, "GET", null); ticket = new Ticket(); ticket.setTicket(jsonObject.getString("ticket")); ticket.setExpiresIn(jsonObject.getInt("expires_in")); } return ticket; } /** * 创建菜单 * @param menu 菜单实例 * @param accessToken 有效的access_token * @return 0表示成功,其他值表示失败 */ public int createMenu(Menu menu, String accessToken) { int result = 0; // 拼装创建菜单的url String url = NameUtils.menu_create_url.replace("ACCESS_TOKEN", accessToken); // 将菜单对象转换成json字符串 String jsonMenu = JSONObject.fromObject(menu).toString(); // 调用接口创建菜单 JSONObject jsonObject = httpRequest(url, "POST", jsonMenu); if (null != jsonObject) { if (0 != jsonObject.getInt("errcode")) { result = jsonObject.getInt("errcode"); Logger.getAnonymousLogger().info("创建菜单失败 errcode:{} errmsg:{}" + jsonObject.getInt("errcode") + jsonObject.getString("errmsg")); } } return result; } /** * 创建菜单 * @param jsonMenu * @param accessToken */ public int createMenu(String jsonMenu, String accessToken) { int result = 0; // 拼装创建菜单的url String url = NameUtils.menu_create_url.replace("ACCESS_TOKEN", accessToken); // 调用接口创建菜单 JSONObject jsonObject = httpRequest(url, "POST", jsonMenu); if (null != jsonObject) { if (0 != jsonObject.getInt("errcode")) { result = jsonObject.getInt("errcode"); Logger.getAnonymousLogger().info("创建菜单失败 errcode:{} errmsg:{} " + jsonObject.getInt("errcode") + jsonObject.getString("errmsg")); } } return result; } /** * 创建二维码 * @param qrCode * @return */ public QRCJson createQrcode(String json) { AccessToken at = this.getAccessToken(NameUtils.appId, NameUtils.appSecret); if (at == null) { return null; } String token = at.getToken(); JSONObject jsonObject = httpRequest(NameUtils.get_token_url.replaceAll("TOKEN", token), "POST", json); if (jsonObject == null) { return null; } QRCJson qrcJson = new QRCJson(); String ticket = null; try { ticket = URLEncoder.encode(jsonObject.getString("ticket"), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } qrcJson.setTicket(ticket); qrcJson.setUrl(NameUtils.show_qrcode_url + ticket); if (json.contains("expire_seconds")) {// 临时二维码才有过期时间 qrcJson.setExpire_seconds(jsonObject.getString("expire_seconds")); } return qrcJson; } /** * 生成网页授权链接 * * @param type * @param redirectURI */ public String getOauth2Url(String type, String redirectURI) { String url = ""; try { redirectURI = URLEncoder.encode(redirectURI, "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } if ("snsapi_base".equals(type)) { url = NameUtils.oauth2_url.replace("SCOPE", "snsapi_base").replace("APPID", NameUtils.appId).replace("REDIRECT_URI", redirectURI); } else { url = NameUtils.oauth2_url.replace("SCOPE", "snsapi_userinfo").replace("APPID", NameUtils.appId).replace("REDIRECT_URI", redirectURI); } return url; } /** * (网页授权)拉取用户信息 * * @param code * @param type * @return */ public JSONObject getUserInfoByOauth2(String code, String type) { JSONObject jsonObject = null; String openid = "", access_token = ""; // 得到access_token和openid jsonObject = httpRequest(NameUtils.oauth2_getToken_url.replaceAll("CODE", code).replaceAll("APPID", NameUtils.appId).replaceAll("SECRET", NameUtils.appSecret), "GET", null); if (null == jsonObject) { return null; } openid = jsonObject.getString("openid"); access_token = jsonObject.getString("access_token"); // 获取用户信息 if ("info".equals(type) && !"".equals(openid) && !"".equals(access_token)) { jsonObject = null; jsonObject = httpRequest(NameUtils.oauth2_getUserInfo_url.replaceAll("ACCESS_TOKEN", access_token).replaceAll("OPENID", openid), "GET", null); if (jsonObject != null) return jsonObject; } return jsonObject; } /** * 拉取用户信息 * * @param code * @param appid * @param secret */ public String[] getOpenId(String code, String appid, String secret) { String[] strs = new String[2]; String url = "", openid = "", access_token = ""; Logger.getAnonymousLogger().info("code = " + code + ", appid = " + appid + ", secret = " + secret); // 得到access_token和openid url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; JSONObject jsonObject = httpRequest(url.replaceAll("CODE", code).replaceAll("APPID", appid).replaceAll("SECRET", secret), "GET", null); if (null == jsonObject) { return null; } openid = jsonObject.getString("openid"); access_token = jsonObject.getString("access_token"); strs[0] = openid; strs[1] = access_token; return strs; } /** * 根据openid拉取用户信息 * @param openid * @return */ public JSONObject getUserInfo(String openid) { AccessToken token = this.getAccessToken(NameUtils.appId, NameUtils.appSecret); if (token == null) { // 此处如果出错,只能说明程序逻辑改变,存在多线程安全隐患 return null; } // 获取信息 JSONObject jsonObject = httpRequest(NameUtils.userinfo_url.replaceAll("ACCESS_TOKEN", token.getToken()).replaceAll("OPENID", openid), "GET", null); if (null == jsonObject) { // 网络错误 return null; } // 对数据进行get(防止出现问题,能够让程序及时补救), 如果抛出异常,表示access_token可能失效,强制获取一次。 try { jsonObject.getString("sex"); } catch (Exception e) { // 记录日志 logger.error(this, "getUserInfo method throw exception:" + e.getMessage() + "[" + jsonObject + "]"); // 判断错误信息是否为 access_token 失效的问题,只有access失效,我们才重新获取,否则每次获取可能导致access_token资源耗尽 if (jsonObject.getInt("errcode") != 40001) return jsonObject; // 强制刷新access_token,存在多线程安全隐患! String requestUrl = NameUtils.access_token_url.replace("APPID", NameUtils.appId).replace("APPSECRET", NameUtils.appSecret); JSONObject accessTokenJsonObject = httpRequest(requestUrl, "GET", null); // 报错access_token信息,不管报错与否 Token wechatToken = new Token(); wechatToken.setEndDate(new Date(new Date().getTime() + 6500000)); wechatToken.setAppid(NameUtils.pubNo); wechatToken.setToken(accessTokenJsonObject.getString("access_token")); tokenService.updateToken(wechatToken); StaticCacheMemory.setAccessToken(wechatToken); // 再次获取用户信息 return httpRequest(NameUtils.userinfo_url.replaceAll("ACCESS_TOKEN", wechatToken.getToken()).replaceAll("OPENID", openid), "GET", null); } return jsonObject; } /** * 发送模板消息 appId 公众账号的唯一标识 appSecret 公众账号的密钥 openId 用户标识 */ public boolean sendTemplateMessage(String appId, String appSecret, String openId, String template_id, Object data, String redirectUrl) { // 准备数据 AccessToken token = this.getAccessToken(appId, appSecret); String access_token = token.getToken(); String url = sendTemplate + access_token; //json格式转换 String jsonObj = JSONObject.fromObject(data).toString(); data = "="+jsonObj.toString()+"="; // 准备模版 ITTempLate temp = new ITTempLate(); temp.setTouser(openId); temp.setTemplate_id(template_id); temp.setUrl(redirectUrl); temp.setData(data); // format String jsonString = JSONObject.fromObject(temp).toString(); jsonString = jsonString.replace("\"=", "").replace("=\"", "").replaceAll("\\\\", ""); // send JSONObject jsonObject = httpRequest(url, "POST", jsonString); if (null == jsonObject) { return false; } if (0 != jsonObject.getInt("errcode")) { logger.info("错误 errcode:{} errmsg:{}" + jsonObject.getInt("errcode") + jsonObject.getString("errmsg")); return false; } return true; } }