app.myoss.wechat.mp.api.impl.WeChatMpDynamicConfigInRedisStorage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wechat-starter-mp Show documentation
Show all versions of wechat-starter-mp Show documentation
myoss open source project, wechat-starter written in Java
/*
* Copyright 2018-2018 https://github.com/myoss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package app.myoss.wechat.mp.api.impl;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.client.RestTemplate;
import app.myoss.cloud.cache.lock.LockService;
import app.myoss.cloud.cache.lock.functions.LockFunction;
import app.myoss.cloud.cache.lock.functions.LockFunctionGeneric;
import app.myoss.cloud.core.exception.BizRuntimeException;
import app.myoss.wechat.mp.api.WeChatMpDynamicConfigStorage;
import app.myoss.wechat.mp.autoconfigure.WeChatMpProperties.WeChatMp;
import lombok.Getter;
import me.chanjar.weixin.common.WxType;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.mp.api.WxMpService;
/**
* 微信公众号 "动态配置"(如:access_token)使用 Redis 存储
*
* @author Jerry.Chen
* @since 2018年8月28日 上午11:01:48
*/
@Getter
public class WeChatMpDynamicConfigInRedisStorage implements WeChatMpDynamicConfigStorage {
private static final String ACCESS_TOKEN_KEY = "wechat_mp_access_token_";
/**
* 微信公众号的属性配置
*/
private WeChatMp weChatMp;
/**
* Http RestTemplate
*/
private RestTemplate restTemplate;
/**
* 缓存锁服务接口
*/
private LockService lockService;
/**
* 锁的过期时间
*/
private int lockTime;
/**
* Spring RedisTemplate
*/
private StringRedisTemplate redisTemplate;
/**
* 每个公众号生成独有的存储key
*/
private String accessTokenKey;
/**
* 微信公众号 "动态配置"(如:access_token)使用 Redis 存储
*
* @param weChatMp 微信公众号的属性配置
* @param restTemplate Http RestTemplate
* @param lockService 缓存锁服务接口
* @param lockTime 锁的过期时间
* @param redisTemplate String RedisTemplate
*/
public WeChatMpDynamicConfigInRedisStorage(WeChatMp weChatMp, RestTemplate restTemplate, LockService lockService,
int lockTime, StringRedisTemplate redisTemplate) {
this.weChatMp = weChatMp;
this.restTemplate = restTemplate;
this.lockService = lockService;
this.lockTime = lockTime;
this.redisTemplate = redisTemplate;
this.accessTokenKey = ACCESS_TOKEN_KEY.concat(weChatMp.getAppId());
}
@Override
public String getAccessToken(boolean forceRefresh) {
if (!forceRefresh && !isAccessTokenExpired()) {
return this.redisTemplate.opsForValue().get(this.accessTokenKey);
}
String lockKey = "getAccessTokenLockKey_" + this.accessTokenKey;
return lockService.executeByLock(lockKey, getLockTime(), new LockFunctionGeneric() {
@Override
public String onLockSuccess() {
return getAccessTokenFromWxMpService();
}
@Override
public String onLockFailed() {
throw new BizRuntimeException("getAccessToken lock failed");
}
});
}
/**
* 从微信公众号服务获取 access_token 值
*
* @return access_token 值
*/
public String getAccessTokenFromWxMpService() {
WeChatMp weChatMp = getWeChatMp();
String url = String.format(getAccessTokenUrl(), weChatMp.getAppId(), weChatMp.getAppSecret());
String resultContent = restTemplate.getForObject(url, String.class);
WxError error = WxError.fromJson(resultContent, WxType.MP);
if (error.getErrorCode() != 0) {
throw new BizRuntimeException(error.toString());
}
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
return accessToken.getAccessToken();
}
/**
* 从微信公众号服务获取 access_token 值的请求 url
*
* @return access_token 服务 url
*/
public String getAccessTokenUrl() {
return WxMpService.GET_ACCESS_TOKEN_URL;
}
@Override
public String getAccessToken() {
return getAccessToken(false);
}
@Override
public boolean isAccessTokenExpired() {
Long expire = this.redisTemplate.getExpire(this.accessTokenKey);
return expire == null || expire < 2;
}
@Override
public long getExpiresTime() {
Long expire = this.redisTemplate.getExpire(this.accessTokenKey);
return (expire != null ? expire : -2);
}
@Override
public void updateAccessToken(String accessToken, int expiresInSeconds) {
String lockKey = "updateAccessTokenLockKey_" + this.accessTokenKey;
lockService.executeByLock(lockKey, getLockTime(), new LockFunction() {
@Override
public void onLockSuccess() {
redisTemplate.opsForValue().set(accessTokenKey, accessToken, expiresInSeconds - 200, TimeUnit.SECONDS);
}
@Override
public void onLockFailed() {
throw new BizRuntimeException("updateAccessToken lock failed");
}
});
}
@Override
public void expireAccessToken() {
String lockKey = "expireAccessTokenLockKey_" + this.accessTokenKey;
lockService.executeByLock(lockKey, getLockTime(), new LockFunction() {
@Override
public void onLockSuccess() {
redisTemplate.expire(accessTokenKey, 0, TimeUnit.SECONDS);
}
@Override
public void onLockFailed() {
throw new BizRuntimeException("expireAccessToken lock failed");
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy