微信網頁分享獲取token
阿新 • • 發佈:2019-02-12
前段時間幫朋友搞微信分享獲取token資料,今天跟大家分享一下。
基於java servlet、接受請求並返回 微信js介面驗證需要的三個引數noncestr、timestamp、signature
GetSignServlet
package com.himalpha;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.himalpha.cache.CacheUtils;
import com.himalpha.utils.HttpClientGet;
import com.himalpha.utils.Sha1;
import com.himalpha.utils.WechatContranst;
import net.sf.json.JSONObject;
/**
* Servlet implementation class GetSignServlet
*/
@WebServlet("/getSign")//前端訪問地址,需要傳過來分享的url地址
public class GetSignServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public GetSignServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Map<String, String> params =null;
JsonParser jsonParser = new JsonParser();
JsonObject jsonMap = null;
String xml = null;
String linkUrl = request.getParameter("url").toString();
Iterator<String> it;
//快取獲取access_token
String access_token = CacheUtils.getTokenCache().get("access_token");
if(access_token==null) {
//請求獲取
params = new HashMap<String, String>();
params.put("grant_type", "client_credential");
params.put("appid","你的APPID");
params.put("secret","你的secret" );
xml = HttpClientGet.sendGet(WechatContranst.tokenUrl,params);
xml = xml.trim();
jsonMap = jsonParser.parse(xml).getAsJsonObject();
access_token = jsonMap.get("access_token").getAsString();
CacheUtils.getTokenCache().put("access_token", access_token);
}
System.out.println("access_token=" + access_token);
//快取獲取ticket
String jsapi_ticket = CacheUtils.getTokenCache().get("jsapi_ticket");
if(jsapi_ticket==null) {
params.clear();
params.put("access_token",access_token);
params.put("type", "jsapi");
xml = HttpClientGet.sendGet(WechatContranst.ticketUrl,params);
xml = xml.trim();
jsonMap = jsonParser.parse(xml).getAsJsonObject();
jsapi_ticket = jsonMap.get("ticket").getAsString();
CacheUtils.getTokenCache().put("jsapi_ticket",jsapi_ticket);
}
//獲取簽名signature
String noncestr = UUID.randomUUID().toString();
String timestamp = Long.toString(System.currentTimeMillis() / 1000);
String url="http://mp.weixin.qq.com";
String str = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + noncestr +
"×tamp=" + timestamp +
"&url=" + linkUrl;
//sha1加密
String signature = Sha1.SHA1(str);
//最終獲得呼叫微信js介面驗證需要的三個引數noncestr、timestamp、signature
Map<String, String> map = new HashMap<>();
map.put("noncestr", noncestr);
map.put("timestamp", timestamp);
map.put("signature", signature);
String result = new Gson().toJson(map);
response.setContentType("application/json");
response.getWriter().print(result);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
因為微信token每天的獲取次數有限,且每次獲取的token有時效性,所以需要對它作快取處理,下面是servlet裡會用到的其他類
CacheUtil類 封裝了token快取技術
package com.himalpha.cache;
public class CacheUtils {
public static LRUCache<String, String> lruCache;
public static LRUCache<String, String> getTokenCache(){
if (lruCache==null) {
lruCache = new LRUCache<String, String>(2048,3600000);//第一引數是快取資料的最大值(單位:位元組),第二個引數是快取的時間(單位:毫秒)
return lruCache;
}
return lruCache;
}
}
Cache介面
package com.himalpha.cache;
public interface Cache<K,V> {
/**
* 返回當前快取的大小
*
* @return
*/
int size();
/**
* 返回預設存活時間
*
* @return
*/
long getDefaultExpire();
/**
* 向快取新增value物件,其在快取中生存時間為預設值
*
* @param key
* @param value
*/
void put(K key ,V value) ;
/**
* 向快取新增value物件,並指定存活時間
* @param key
* @param value
* @param expire 過期時間
*/
void put(K key ,V value , long expire ) ;
/**
* 查詢快取物件
* @param key
* @return
*/
V get(K key);
/**
* 淘汰物件
*
* @return 被刪除物件大小
*/
int eliminate();
/**
* 快取是否已經滿
* @return
*/
boolean isFull();
/**
* 刪除快取物件
*
* @param key
*/
void remove(K key);
/**
* 清除所有快取物件
*/
void clear();
/**
* 返回快取大小
*
* @return
*/
int getCacheSize();
/**
* 快取中是否為空
*/
boolean isEmpty();
}
package com.himalpha.cache;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 預設實現
*/
public abstract class AbstractCacheMap<K,V> implements Cache<K,V> {
class CacheObject<K2,V2> {
CacheObject(K2 key, V2 value, long ttl) {
this.key = key;
this.cachedObject = value;
this.ttl = ttl;
this.lastAccess = System.currentTimeMillis();
}
final K2 key;
final V2 cachedObject;
long lastAccess; // 最後訪問時間
long accessCount; // 訪問次數
long ttl; // 物件存活時間(time-to-live)
boolean isExpired() {
if (ttl == 0) {
return false;
}
return lastAccess + ttl < System.currentTimeMillis();
}
V2 getObject() {
lastAccess = System.currentTimeMillis();
accessCount++;
return cachedObject;
}
}
protected Map<K,CacheObject<K,V>> cacheMap;
private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
private final Lock readLock = cacheLock.readLock();
private final Lock writeLock = cacheLock.writeLock();
protected int cacheSize; // 快取大小 , 0 -> 無限制
protected boolean existCustomExpire ; //是否設定預設過期時間
public int getCacheSize() {
return cacheSize;
}
protected long defaultExpire; // 預設過期時間, 0 -> 永不過期
public AbstractCacheMap(int cacheSize ,long defaultExpire){
this.cacheSize = cacheSize ;
this.defaultExpire = defaultExpire ;
}
public long getDefaultExpire() {
return defaultExpire;
}
protected boolean isNeedClearExpiredObject(){
return defaultExpire > 0 || existCustomExpire ;
}
public void put(K key, V value) {
put(key, value, defaultExpire );
}
public void put(K key, V value, long expire) {
writeLock.lock();
try {
CacheObject<K,V> co = new CacheObject<K,V>(key, value, expire);
if (expire != 0) {
existCustomExpire = true;
}
if (isFull()) {
eliminate() ;
}
cacheMap.put(key, co);
}
finally {
writeLock.unlock();
}
}
/**
* {@inheritDoc}
*/
public V get(K key) {
readLock.lock();
try {
CacheObject<K,V> co = cacheMap.get(key);
if (co == null) {
return null;
}
if (co.isExpired() == true) {
cacheMap.remove(key);
return null;
}
return co.getObject();
}
finally {
readLock.unlock();
}
}
public final int eliminate() {
writeLock.lock();
try {
return eliminateCache();
}
finally {
writeLock.unlock();
}
}
/**
* 淘汰物件具體實現
*
* @return
*/
protected abstract int eliminateCache();
public boolean isFull() {
if (cacheSize == 0) {//o -> 無限制
return false;
}
return cacheMap.size() >= cacheSize;
}
public void remove(K key) {
writeLock.lock();
try {
cacheMap.remove(key);
}
finally {
writeLock.unlock();
}
}
public void clear() {
writeLock.lock();
try {
cacheMap.clear();
}
finally {
writelock.unlock();
}
}
public int size() {
return cacheMap.size();
}
public boolean isEmpty() {
return size() == 0;
}
}
抽象cache的LRU演算法實現package com.himalpha.cache;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* LRU 實現
* @author Wen
*
* @param <K>
* @param <V>
*/
public class LRUCache<K, V> extends AbstractCacheMap<K, V> {
public LRUCache(int cacheSize, long defaultExpire) {
super(cacheSize , defaultExpire) ;
//linkedHash已經實現LRU演算法 是通過雙向連結串列來實現,當某個位置被命中,通過調整連結串列的指向將該位置調整到頭位置,新加入的內容直接放在連結串列頭,如此一來,最近被命中的內容就向連結串列頭移動,需要替換時,連結串列最後的位置就是最近最少使用的位置
this.cacheMap = new LinkedHashMap<K, CacheObject<K, V>>( cacheSize +1 , 1f,true ) {
@Override
protected boolean removeEldestEntry(
Map.Entry<K, CacheObject<K, V>> eldest) {
return LRUCache.this.removeEldestEntry(eldest);
}
};
}
private boolean removeEldestEntry(Map.Entry<K, CacheObject<K, V>> eldest) {
if (cacheSize == 0)
return false;
return size() > cacheSize;
}
/**
* 只需要實現清除過期物件就可以了,linkedHashMap已經實現LRU
*/
@Override
protected int eliminateCache() {
if(!isNeedClearExpiredObject()){ return 0 ;}
Iterator<CacheObject<K, V>> iterator = cacheMap.values().iterator();
int count = 0 ;
while(iterator.hasNext()){
CacheObject<K, V> cacheObject = iterator.next();
if(cacheObject.isExpired() ){
iterator.remove();
count++ ;
}
}
return count;
}
}
下面是工具類
傳送get請求的工具類
package com.himalpha.utils;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import com.himalpha.cache.CacheUtils;
public class HttpClientGet {
public static String sendGet(String url,Map<String, String> map) {
try {
StringBuilder sendUrl = new StringBuilder();
sendUrl.append(url+"?");
for (String key : map.keySet()) {
sendUrl.append(key +"="+map.get(key)+"&");
}
String send = sendUrl.substring(0,sendUrl.length()-1);
URL urls = new URL(send);
URLConnection connection = urls.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestProperty("Content-length","1024");
connection.setRequestProperty("Access-Control-Allow-Origin", "*");
connection.setRequestProperty("ContentType", "application/json;charset=utf-8");
InputStream inputStream = connection.getInputStream();
byte[] buffer = new byte[1024];
inputStream.read(buffer);
String string = new String(buffer);
return string;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
}
sha1加密工具類package com.himalpha.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Sha1 {
public static String SHA1(String str) {
try {
MessageDigest digest = java.security.MessageDigest
.getInstance("SHA-1"); //傳入加密型別
digest.update(str.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexStr = new StringBuffer();
// 位元組陣列轉換為 十六進位制 數
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexStr.append(0);
}
hexStr.append(shaHex);
}
return hexStr.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}
常量類,防止微信公眾號介面更改package com.himalpha.utils;
public class WechatContranst {
public static String tokenUrl ="https://api.weixin.qq.com/cgi-bin/token";
public static String ticketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
}
希望對正在搞 呼叫微信js介面驗證需要的三個引數noncestr、timestamp、signature 的朋友有幫助