一、access_toekn获取说明
|
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
公众平台的API调用所需的access_token的使用及生成方式说明:
1、建议公众号开发者使用中控服务器统一获取和刷新access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务;
2、目前access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器可对外继续输出的老access_token,此时公众平台后台会保证在5分钟内,新老access_token都可用,这保证了第三方业务的平滑过渡;
3、access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。
4、对于可能存在风险的调用,在开发者进行获取 access_token调用时进入风险调用确认流程,需要用户管理员确认后才可以成功获取。具体流程为:
开发者通过某IP发起调用->平台返回错误码[89503]并同时下发模板消息给公众号管理员->公众号管理员确认该IP可以调用->开发者使用该IP再次发起调用->调用成功。
如公众号管理员第一次拒绝该IP调用,用户在1个小时内将无法使用该IP再次发起调用,如公众号管理员多次拒绝该IP调用,该IP将可能长期无法发起调用。平台建议开发者在发起调用前主动与管理员沟通确认调用需求,或请求管理员开启IP白名单功能并将该IP加入IP白名单列表。
公众号和小程序均可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。**调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。**小程序无需配置IP白名单。
|
|
|
二、接口说明
|
接口
|
|
|
参数
|
appid和APPSECRET
|
|
接口方式
|
get
|
|
正确返回
|
{"access_token":"ACCESS_TOKEN","expires_in":7200}
|
|
错误返回
|
{"errcode":40013,"errmsg":"invalid appid"}
|
三、封装代码
|
token类
|
public class Token {
private String appId;//access_token对应的AppId
private String access_token;//访问token
public long expires_in;
private Date crea_time;//创建时间,如果当前时间比创建时间只差少于商量名,则要重新从服务器生成
}
|
|
tokenFatory
|
public class TokenFactory {
private static final Logger log = LoggerFactory
.getLogger(TokenFactory.class);
public static final String token_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";//toke访问地址
public static final String token_method="GET";
private static Map<String,Token> orgTokenMap=null;//key为appid,支持多个公众号
private static TokenFactory factory=null;
private TokenFactory(){
init();
}
public static TokenFactory instanceOf(){
if( factory==null)
factory=new TokenFactory();
return factory;
}
private void init(){
orgTokenMap=new HashMap<String,Token>();
}
/**
* 获得token
* @param appId
* @param appSecret
* @return
*/
public Token getToken(String appId,String appSecret){
XBUtil.NullException(appId, "appId");
appId=appId.trim();
Token token=null;
token=orgTokenMap.get(appId);//从缓存获取
if(token==null || toeknFailure(token)){//没有值或者token失效,则重新获取
token=refreshToken(appId,appSecret);
}
return token;
}
/**
* 判断token是否失效
* @return
*/
private boolean toeknFailure(Token token){
boolean ret=true;
if(token==null)
return true;
long expires_in=token.getExpires_in();//得到有效时间长度
expires_in=expires_in-SysConstant.refresh_times;//减去提前时间
long jgTime=DateUtil.getDateBetween(new Date(), token.getCrea_time(), DateUtil.seconds);//当前日期和创建token的时间只差
if(expires_in>jgTime){//预期间隔日期大于实际间隔日期
ret=false;
}
return ret;
}
/**
* 刷新token
* @param org_id
*/
private Token refreshToken(String appId,String appSecret){
Token token=null;
//读取toekn
String url=token_URL.replace("APPID", appId).replace("APPSECRET", appSecret);
String json=WxUtil.HttpsRequest(url,token_method,null);
token=XBUtil.jsonToBean(json, Token.class);
if(token.getAccess_token()==null || token.getAccess_token().trim().length()==0)
throw new RuntimeException("获取token出错:"+json);
token.setCrea_time(new Date());//设置创建时间
orgTokenMap.remove(appId);
orgTokenMap.put(appId, token);
return token;
}
}
|
辅助类
1.读取https url反馈的内容
|
读取https的url传递参数,并解析url输出的内容
/**
* 处理https的请求
* @param requsetURL 请求的地址
* @param requestMethod 请求方法 GET POST
* @param requestParam 传递过去的参数
* @return 返回的json字符串
*/
public static String HttpsRequest(String requsetURL,String requestMethod,String requestParam){
String retJson="";
InputStream is=null;
InputStreamReader isr=null;
BufferedReader br=null;
HttpsURLConnection con=null;
try{
//创建SSLContext上下文
SSLContext context=SSLContext.getInstance("SSL", "SunJSSE");
TrustManager[] tm={new MyX509TrustManager()};
context.init(null, tm, new java.security.SecureRandom());
//创建SSLSocketFactory工厂类
SSLSocketFactory ssf=context.getSocketFactory();
//打开网络连接
URL url=new URL(requsetURL);
con=(HttpsURLConnection)url.openConnection();
con.setRequestMethod(requestMethod);
con.setSSLSocketFactory(ssf);
con.setDoInput(true);
con.setDoOutput(true);
con.connect();
//写内容
if(requestParam!=null){
OutputStream os=con.getOutputStream();
os.write(requestParam.getBytes("utf-8"));
os.close();
}
//读取内容
is=con.getInputStream();
isr=new InputStreamReader(is,"utf-8");
br=new BufferedReader(isr);
StringBuffer sb=new StringBuffer();
String line=null;
while((line=br.readLine())!=null){
sb.append(line);
}
retJson= sb.toString();
}
catch(Exception e){
throw new RuntimeException("微信接口"+requsetURL+"读取出错:"+e);
}
finally{
//释放支援
try{
if(br!=null)
br.close();
if(isr!=null)
isr.close();
if(is!=null)
is.close();
if(con!=null){
InputStream xx = con.getInputStream();
if(xx!=null)xx.close();
con.disconnect();
}
}
catch(Exception e){
e.printStackTrace();
}
}
return retJson;
}
|
2.vo与json解析
|
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.5</version>
</dependency>
|
|
/**
* json转换为bean
* @return
* @return
*/
public static <T extends Object> T jsonToBean(String json,Class<T> cls){
Gson gson=new Gson();
return gson.fromJson(json, cls);
}
|
通用类说明
如果在分布式系统中,access_token应存储在redis里面,有效期低于7200毫秒
注意:获取toekn和服务器通信配置无关