1.access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token,所以这个数据是非常的重要的,首先阅读以下微信开发文档,对于access_token是这样写的。
根据文档的指示,我们的access_token的需求如下:单一获取和刷新access_token的值,全局保存,用到的都去这个地方去拿。定时去刷新(现在是2个小时刷新一次)
2.我们使用redis来全局缓存access_token的值,需要用到access_token的时候就去redis当中去取。并且,这个值每两个小时刷新一次。
//刷新access_token 100分钟刷新一次,服务器启动的时候刷新一次(access_token有效期是120分钟,我设置的是每100分钟刷新一次) @Scheduled(initialDelay = 1000, fixedDelay = 100*60*1000) public void get_access_token() { try { String appid = "填上你公众号的appid"; String appsecret = "填上你公众号的appsecret"; String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; requestUrl = requestUrl.replace("APPID",appid).replace("APPSECRET",appsecret); JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl,"GET",null); if(jsonObject.getString("access_token")!=null){ Jedis jedis = jedisPool.getResource(); try { Map<String,String> map = new HashMap<String,String>(); map.put("access_token",jsonObject.getString("access_token")); jedis.hmset(appid, map); } catch(Exception e){ if(jedis != null){ jedis.close(); jedis = null; } e.printStackTrace(); } finally { if(jedis != null){ jedis.close(); } } } else{ logger.info("定时刷新access_token失败,微信返回的信息是"+jsonObject.toJSONString()); } } catch (Exception e){ logger.info("更新access_token的过程当中发生了异常,异常的信息是"+e.getMessage()); } }
/** * 发送https请求 * * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) */ public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; 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 conn = (HttpsURLConnection) url.openConnection(); //HttpURLConnection con= url.openConnection(); conn.setSSLSocketFactory(ssf); //2017年9月15日16:21:40 //新设置的,可能是一直在链接导致的程序死亡 conn.setConnectTimeout(10 * 1000); conn.setReadTimeout(50 * 1000); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // 设置请求方式(GET/POST) conn.setRequestMethod(requestMethod); // 当outputStr不为null时向输出流写数据 if (null != outputStr) { OutputStream outputStream = conn.getOutputStream(); // 注意编码格式 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 从输入流读取返回内容 InputStream inputStream = conn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } // 释放资源 bufferedReader.close(); inputStreamReader.close(); inputStream.close(); inputStream = null; conn.disconnect(); jsonObject = JSONObject.parseObject(buffer.toString()); } catch (ConnectException ce) { System.out.println("连接超时:{}" + ce); } catch (Exception e) { System.out.println("https请求异常:{}" + e); //log.error("https请求异常:{}", e); } return jsonObject; }
public class MyX509TrustManager implements X509TrustManager { // 检查客户端证书 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } // 检查服务器端证书 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } // 返回受信任的X509证书数组 public X509Certificate[] getAcceptedIssuers() { return null; } }
其中jedisPool的配置如下:
@Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.timeout}") private int timeout; @Value("${spring.redis.poolMaxIdle}") private int maxIdle; @Value("${spring.redis.poolMaxWait}") private long maxWaitMillis; /*@Value("${spring.redis.password}") private String password;*/ @Bean @Scope("singleton") public JedisPool redisPoolFactory() { System.out.println("jedispool"); JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, null); logger.info("host:"+host); logger.info("port:"+port); logger.info("timeout:"+timeout); return jedisPool; }
这样,我们就把access_token全局进行了缓存,在其他需要使用到access_token的时候,就去redis当中获取数据,调用其他的接口。我们满足了微信开发文档的三点要求
1.全局唯一获取刷新access_token ,全局缓存,需要的都去redis当中去取。
2.定时刷新access_token,不会出现access_token过期的情况
3.access_token有效时间可能会在未来有调整,到时候我们只需要改一下定时器的时间即可。