刚刚做了一个微信的分享。因为微信现在是很普及的APP,几乎是每个人都会有微信号,用户量何其大!!!!所以我写了一个简单的连接微信的工具类,其中包含获取token,ticket,等等。。。

1、微信通用的工具类

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
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、验证,进行签名的工具类。这个是官方提供。(不建议自己写)

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
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 +
              "&timestamp=" + 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类。主要是做存储。因为官方微信有一个次数的限制,和有效期限制。。。所以这里用到了一个存储类。做缓存使用

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
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;
    }
}

原文地址:https://blog.csdn.net/qq_37228713/article/details/83107534?ops_request_misc=&request_id=1dc8ed900c9e4624a6d881ce17781e11&biz_id=&utm_medium=distribute.pc_search_result.none-task-blog-2~all~koosearch~default-9-83107534-null-null.142^v88^insert_down28v1,239^v2^insert_chatgpt&utm_term=java%E4%BC%98%E5%8C%96