刚刚做了一个微信的分享。因为微信现在是很普及的APP,几乎是每个人都会有微信号,用户量何其大!!!!所以我写了一个简单的连接微信的工具类,其中包含获取token,ticket,等等。。。
1、微信通用的工具类
package com.solian.web.util;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
import com.solian.web.bean.Token;
import com.solian.web.bean.WinXinEntity;
import net.sf.json.JSONObject;
/**
* 微信通用工具类
*
* @author wukaikai
*
*/
public class WeiXinUtils {
// 获取access_token的接口地址(GET) 限2000(次/天)
public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
// 获取jsapi_ticket的接口地址(GET) 限2000(次/天)
public final static String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
// 缓存添加的时间
public static String cacheAddTime = null;
// token,ticket缓存
public static Map<String, Token> TOKEN_TICKET_CACHE = new HashMap<String, Token>();
// token对应的key
private static final String TOKEN = "token";
// ticket对应的key
private static final String TICKET = "ticket";
public static WinXinEntity getWinXinEntity(String url) {
WinXinEntity wx = new WinXinEntity();
String access_token = getToken("APPID", "AppSecret");
String ticket = getTicket(access_token);
Map<String, String> ret = Sign.sign(ticket, url);
System.out.println(ret.toString());
wx.setTicket(ret.get("jsapi_ticket"));
wx.setSignature(ret.get("signature"));
wx.setNoncestr(ret.get("nonceStr"));
wx.setTimestamp(ret.get("timestamp"));
wx.setStr(ret.get("url"));
return wx;
}
/**
* 获得Token
*
* @return
*/
public static String getToken(String appId, String secret) {
Token accessTocken = getToken(appId, secret, System.currentTimeMillis() / 1000);
return accessTocken.getToken();
}
/**
* 获得ticket
*
* @return
*/
public static String getTicket(String token) {
Token accessTocken = getTicket(token, System.currentTimeMillis() / 1000);
return accessTocken.getTicket();
}
/**
* 获取access_token
*
* @param appid
* @param appsecret
* @param currentTime
* @return
*/
public static Token getToken(String appid, String appsecret, long currentTime) {
Token tokenTicketCache = getTokenTicket(TOKEN);
Token token = null;
if (tokenTicketCache != null && (currentTime - tokenTicketCache.getAddTime() <= tokenTicketCache.getExpiresTime())) {
System.out.println("==========缓存中token已获取时长为:" + (currentTime - tokenTicketCache.getAddTime()) + "毫秒,可以重新使用");
return tokenTicketCache;
}
System.out.println("==========缓存中token不存在或已过期===============正在重新请求===========");
String token_url = access_token_url.replaceAll("APPID", appid).replaceFirst("APPSECRET", appsecret);
JSONObject jsonObject = httpRequest(token_url, "GET", null);
if (null != jsonObject) {
token = new Token();
token.setToken(jsonObject.getString("access_token"));
token.setExpiresTime(jsonObject.getLong(("expires_in"))/2);// 正常过期时间是7200秒,此处设置3600秒读取一次
System.out.println("==========tocket缓存过期时间为:" + token.getExpiresTime() + "毫秒");
token.setAddTime(currentTime);
updateToken(TOKEN, token);
}
return token;
}
/**
* 获取ticket
*
* @param token
* @return
*/
private static Token getTicket(String token, long currentTime) {
Token tockenTicketCache = getTokenTicket(TICKET);
Token Token = null;
if (tockenTicketCache != null && (currentTime - tockenTicketCache.getAddTime() <= tockenTicketCache.getExpiresTime())) {// 缓存中有ticket
System.out.println("==========缓存中ticket已获取时长为:" + (currentTime - tockenTicketCache.getAddTime()) + "毫秒,可以重新使用");
return tockenTicketCache;
}
System.out.println("==========缓存中ticket不存在或已过期===============");
String requestUrl = jsapi_ticket_url.replace("ACCESS_TOKEN", token);
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
// 如果请求成功
if (null != jsonObject) {
Token = new Token();
Token.setTicket(jsonObject.getString("ticket"));
Token.setExpiresTime(jsonObject.getLong("expires_in") / 2);// 正常过期时间是7200秒,此处设置3600秒读取一次
System.out.println("==========ticket缓存过期时间为:" + Token.getExpiresTime() + "毫秒");
Token.setAddTime(currentTime);
updateToken(TICKET, Token);
}
return Token;
}
/**
* 从缓存中读取token或者ticket
*
* @return
*/
private static Token getTokenTicket(String key) {
if (TOKEN_TICKET_CACHE != null && TOKEN_TICKET_CACHE.get(key) != null) {
System.out.println("==========从缓存中获取到了" + key + "成功===============");
return TOKEN_TICKET_CACHE.get(key);
}
return null;
}
/**
* 更新缓存中token或者ticket
*
* @return
*/
private static void updateToken(String key, Token accessTocken) {
if (TOKEN_TICKET_CACHE != null && TOKEN_TICKET_CACHE.get(key) != null) {
TOKEN_TICKET_CACHE.remove(key);
System.out.println("==========从缓存中删除" + key + "成功===============");
}
TOKEN_TICKET_CACHE.put(key, accessTocken);
cacheAddTime = String.valueOf(accessTocken.getAddTime());// 更新缓存修改的时间
System.out.println("==========更新缓存中" + key + "成功===============");
}
/**
* 发起https请求并获取结果
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
private static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try {
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
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) {
System.out.println("Weixin server connection timed out.");
} catch (Exception e) {
System.out.println("https request error:{}" + e.getMessage());
}
return jsonObject;
}
}
2、验证,进行签名的工具类。这个是官方提供。(不建议自己写)
package com.solian.web.util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
class Sign {
public static Map<String, String> sign(String jsapi_ticket, String url) {
Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String string1;
String signature = "";
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + nonce_str +
"×tamp=" + timestamp +
"&url=" + url;
System.out.println(string1);
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
ret.put("url", url);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
return ret;
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
3.Token类。主要是做存储。因为官方微信有一个次数的限制,和有效期限制。。。所以这里用到了一个存储类。做缓存使用
package com.solian.web.bean;
/**
* @author wukaikai
* 微信通用(限制为每日只可以调取2000次)
* token(有效期2个小时7200秒)获取和ticket缓存
* 为了减少频繁的刷微信,导致微信那边限制。给项目带来不必要的损失
*
*/
public class Token {
/**
* token
*/
private String token;
/**
* 生成的ticket
*/
private String ticket;
/**
* 过期时间,自己定义为了不影响项目的正常运行,我这里定位3600秒
*/
private Long expiresTime;
/**
* 增加时间
*/
private Long addTime;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public Long getExpiresTime() {
return expiresTime;
}
public void setExpiresTime(Long expiresTime) {
this.expiresTime = expiresTime;
}
public Long getAddTime() {
return addTime;
}
public void setAddTime(Long addTime) {
this.addTime = addTime;
}
}