微信網頁分享獲取token

前段時間幫朋友搞微信分享獲取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  的朋友有幫助





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章