NutzCN Logo
问答 微信获得access_token放到哪里去了
发布于 2719天前 作者 1037424761 2975 次浏览 复制 上一个帖子 下一个帖子
标签: nutzwk
protected WxResp call(String URL, METHOD method, String body) {
		String token = getAccessToken();
		if (log.isInfoEnabled()) {
			log.info("wxapi call: " + URL);
			if (log.isDebugEnabled()) {
				log.debug(body);
			}
		}

		int retry = retryTimes;
		WxResp wxResp = null;
		while (retry >= 0) {
			try {
				String sendUrl = null;
				if (!URL.startsWith("http"))
					sendUrl = base + URL;
				if (URL.contains("?")) {
					sendUrl += "&access_token=" + token;
				} else {
					sendUrl += "?access_token=" + token;
				}
				Request req = Request.create(sendUrl, method);
				if (body != null)
					req.setData(body);
				Response resp = Sender.create(req).send();
				if (!resp.isOK())
					throw new IllegalArgumentException("resp code=" + resp.getStatus());
				wxResp = Json.fromJson(WxResp.class, resp.getReader("UTF-8"));
				// 处理微信返回  40001 invalid credential
				if (wxResp.errcode() != 40001) {
					break;//正常直接返回
				} else {
					log.warnf("wxapi of access_token request [%s] finished, but the return code is 40001, try to reflush access_token right now, surplus retry times : %s" ,URL ,retry);
					// 强制刷新一次acess_token
					reflushAccessToken();
				}
			} catch (Exception e) {
				if (retryTimes >= 0) {
					log.warn("reflushing access_token... " + retry + " retries left.", e);
				} else {
					log.errorf("%s times attempts to get a wx access_token , but all failed!", retryTimes);
					throw Lang.wrapThrow(e);
				}
			} finally {
				retry--;
			}
		}
		return wxResp;
	}
24 回复

看getAccessToken()里面的逻辑

@Override
	public String getAccessToken() {
		WxAccessToken at = accessTokenStore.get();
		if (at == null || at.getExpires() < (System.currentTimeMillis() - at.getLastCacheTimeMillis()) / 1000) {
			synchronized (lock) {
				//FIX多线程更新token的问题
				WxAccessToken at_forupdate = accessTokenStore.get();
				if (at_forupdate == null || at_forupdate.getExpires() < (System.currentTimeMillis() - at_forupdate.getLastCacheTimeMillis()) / 1000) {
					reflushAccessToken();
				}
			}
		}
		return accessTokenStore.get().getToken();
	}

WxAccessToken at = accessTokenStore.get();
每次获得的都是null,这是为啥?

accessTokenStore用了哪个实现? nutzwx是最新版吗?

用的是nutzwx-1.r.60.jar

换成

org.nutz
nutzwx
1.r.61.r2

也一样啊?

<dependency>
      <groupId>org.nutz</groupId>
      <artifactId>nutzwx</artifactId>
      <version>1.r.61.r2</version>
  </dependency>

跟踪一下reflushAccessToken

protected void reflushAccessToken() {
		String url = String.format("%s/token?grant_type=client_credential&appid=%s&secret=%s", base, appid, appsecret);
		if (log.isDebugEnabled())
			log.debugf("ATS: reflush access_token send: %s", url);

		Response resp = Http.get(url);
		if (!resp.isOK())
			throw new IllegalArgumentException("reflushAccessToken FAIL , openid=" + openid);
		String str = resp.getContent();

		if (log.isDebugEnabled())
			log.debugf("ATS: reflush access_token done: %s", str);

		NutMap re = Json.fromJson(NutMap.class, str);
		String token = re.getString("access_token");
		int expires = re.getInt("expires_in") - 200;//微信默认超时为7200秒,此处设置稍微短一点
		accessTokenStore.save(token, expires, System.currentTimeMillis());
	}

然后调用save

public class MemoryAccessTokenStore implements WxAccessTokenStore {
	
	private static final Log log = Logs.get();

	WxAccessToken at;

	@Override
	public WxAccessToken get() {
		return at;
	}

	@Override
	public void save(String token, int time, long lastCacheTimeMillis) {
		at = new WxAccessToken();
		at.setToken(token);
		at.setExpires(time);
		at.setLastCacheTimeMillis(lastCacheTimeMillis);
		log.debugf("new wx access token generated : \n %s", Json.toJson(at, JsonFormat.nice()));
	}

}

然而没有存成功的样子,下次过来,还是null

是不是每次都new WxApi2Impl了??

 @At
    @Ok("json")
    @SLog(tag = "获取模板列表", msg = "")
    //@RequiresPermissions("wx.tpl.list.get")
    public Object getDo(@Param("wxid") String wxid, HttpServletRequest req) {
        try {
            WxApi2 wxApi2 = wxConfigService.getWxApi2(wxid);
            WxResp wxResp = wxApi2.get_all_private_template();
            List<Wx_tpl_list> lists = wxResp.getList("template_list", Wx_tpl_list.class);
            for (Wx_tpl_list o : lists) {
                o.setWxid(wxid);
                wxTplListService.insert(o);
            }
            return Result.success("system.success");
        } catch (Exception e) {
            return Result.error("system.error");
        }
    }

在这里直接用了WxApi2Impl的方法

  WxResp wxResp = wxApi2.get_all_private_template();

没看到哪里new对象了。。。

/**
 * Created by wizzer on 2016/7/2.
 */
@IocBean(args = {"refer:dao"})
public class WxConfigService extends Service<Wx_config> {
    public WxConfigService(Dao dao) {
        super(dao);
    }

    public WxApi2 getWxApi2(String wxid) {
        Wx_config appInfo = this.fetch(Cnd.where("id", "=", wxid));
        WxApi2Impl wxApi2 = new WxApi2Impl();
        wxApi2.setAppid(appInfo.getAppid());
        wxApi2.setAppsecret(appInfo.getAppsecret());
        wxApi2.setEncodingAesKey(appInfo.getEncodingAESKey());
        wxApi2.setToken(appInfo.getToken());
        return wxApi2;
    }
}

有new的操作,是这里有问题吗?

是的, 用个map缓存起来,不能每次都new的

我试试,就

 WxApi2Impl wxApi2 = new WxApi2Impl();

缓存起来,对吗?其他不变

以wxid为key, 以WxApi2Impl2为value

@1037424761 看最新版的NutzWk WxConfigService

如果启用了redis最好用redis来存:

@IocBean(args = {"refer:dao"})
public class WxConfigServiceImpl extends BaseServiceImpl<Wx_config> implements WxConfigService {
    @Inject
    private JedisPool jedisPool;
    public WxConfigServiceImpl(Dao dao) {
        super(dao);
    }

    public WxApi2 getWxApi2(String wxid) {
        Wx_config appInfo = this.fetch(Cnd.where("id", "=", wxid));
        RedisAccessTokenStore redisAccessTokenStore = new RedisAccessTokenStore();
        redisAccessTokenStore.setTokenKey("WxToken:" + wxid);
        redisAccessTokenStore.setJedisPool(jedisPool);
        WxApi2Impl wxApi2 = new WxApi2Impl();
        wxApi2.setAppid(appInfo.getAppid());
        wxApi2.setAppsecret(appInfo.getAppsecret());
        wxApi2.setEncodingAesKey(appInfo.getEncodingAESKey());
        wxApi2.setToken(appInfo.getToken());
        wxApi2.setAccessTokenStore(redisAccessTokenStore);
        return wxApi2;
    }

}

没看明白

public WxApi2 getWxApi2(String wxid) {
        Wx_config appInfo = this.fetch(Cnd.where("id", "=", wxid));
        RedisAccessTokenStore redisAccessTokenStore = new RedisAccessTokenStore();
        redisAccessTokenStore.setTokenKey("WxToken:" + wxid);
        redisAccessTokenStore.setJedisPool(jedisPool);
        WxApi2Impl wxApi2 = new WxApi2Impl();
        wxApi2.setAppid(appInfo.getAppid());
        wxApi2.setAppsecret(appInfo.getAppsecret());
        wxApi2.setEncodingAesKey(appInfo.getEncodingAESKey());
        wxApi2.setToken(appInfo.getToken());
        wxApi2.setAccessTokenStore(redisAccessTokenStore);
        return wxApi2;
    }

中这3句话

 RedisAccessTokenStore redisAccessTokenStore = new RedisAccessTokenStore();
        redisAccessTokenStore.setTokenKey("WxToken:" + wxid);
        redisAccessTokenStore.setJedisPool(jedisPool);

添加进来,在哪里用?

@IocBean(args = {"refer:dao"})
public class WxConfigService extends Service<Wx_config> {
	
	WxApi2Impl wxApi2 = new WxApi2Impl();
	
	
    public WxConfigService(Dao dao) {
        super(dao);
    }
    
    public WxApi2 getWxApi2(String wxid) {
        Wx_config appInfo = this.fetch(Cnd.where("id", "=", wxid));
        wxApi2.setAppid(appInfo.getAppid());
        wxApi2.setAppsecret(appInfo.getAppsecret());
        wxApi2.setEncodingAesKey(appInfo.getEncodingAESKey());
        wxApi2.setToken(appInfo.getToken());
        return wxApi2;
    }
}

我把new的实例放到外面,发现有用,但是总感觉用什么地方不对。

@IocBean(args = {"refer:dao"})
public class WxConfigService extends Service<Wx_config> {
	
	Map<String, WxApi2Impl> apis = new HashMap<String, WxApi2Impl>();
	
	
    public WxConfigService(Dao dao) {
        super(dao);
    }
    
    public synchronized WxApi2 getWxApi2(String wxid) {
       WxApi2Impl wxApi2 = apis.get(wxid);
       if (wxApi2 == null) {
           wxApi2 = new WxApi2Impl();
           Wx_config appInfo = this.fetch(Cnd.where("id", "=", wxid));
           wxApi2.setAppid(appInfo.getAppid());
           wxApi2.setAppsecret(appInfo.getAppsecret());
           wxApi2.setEncodingAesKey(appInfo.getEncodingAESKey());
           wxApi2.setToken(appInfo.getToken());
       }
        return wxApi2;
    }
}

redis

 @Aop("redis")
    public void clearCache() {
        Set<String> set = jedis().keys("data:wx_api_*");
        for (String it : set) {
            jedis().del(it.getBytes());
        }
    }

    @Aop("redis")
    public synchronized WxApi2 getWxApi2(String wxid) {
        WxApi2Impl wxApi2;
        byte[] bt = jedis().get(("data:wx_api_impl_" + wxid).getBytes());
        if (bt != null) {
            wxApi2 = Lang.fromBytes(bt, WxApi2Impl.class);
        } else {
            Wx_config appInfo = this.fetch(Cnd.where("id", "=", wxid));
            RedisAccessTokenStore redisAccessTokenStore = new RedisAccessTokenStore();
            redisAccessTokenStore.setTokenKey("data:wx_api_token_" + wxid);
            redisAccessTokenStore.setJedisPool(jedisPool);
            wxApi2 = new WxApi2Impl();
            wxApi2.setAppid(appInfo.getAppid());
            wxApi2.setAppsecret(appInfo.getAppsecret());
            wxApi2.setEncodingAesKey(appInfo.getEncodingAESKey());
            wxApi2.setToken(appInfo.getToken());
            wxApi2.setAccessTokenStore(redisAccessTokenStore);
            jedis().set(("data:wx_api_impl_" + wxid).getBytes(), Lang.toBytes(wxApi2));
        }
        return wxApi2;
    }

采用dao方式的话,会自动建表吗? 没看到哪里有建表的代码啊

启动的时候在Setup统一建表嘛

DaoAccessTokenStore.java里的实现,只有fetch和update
private String fetch = "select access_token,access_token_expires,access_token_lastat from wx_config where id=@id";
private String update = "update wx_config set access_token=@access_token, access_token_expires=@access_token_expires, access_token_lastat=@access_token_lastat where id=@id";

我是自己写一个wx_config表的model,再手动插入一个数据?
还是在其它地方有自动建表和插入数据的代码?

哦(´-ω-`),搜一下源码吧

添加回复
请先登陆
回到顶部