除了使用properties和servlet方式之外还有好的方法,希望读者朋友留言分享经验。
示例使用SpringMVC+Redis方式,逻辑流程适用于memcached,这里用到了spring-data-redis-1.7.5.RELEASE.jar包
Spring的配置省略,并非本节重点,主要开启注解配置,并在其Spring-context.xml中引用到spring-redis.xml
<!-- 引入同文件夹下的redis属性配置 --> <import resource="spring-redis.xml"/>
以下就是redis配置,并设置AccessToken的源码了
redis.properties
redis.host=127.0.0.1 redis.port=6379 redis.pass=ibloger.net_redis redis.maxIdle=200 redis.maxTotal=512 redis.maxWaitMillis=3000 redis.testOnBorrow=true
spring-redis.xml配置
<!-- 扫描redis.properties文件-->
<context:property-placeholder location="classpath:config/redis.properties" />
<!-- 读取redis开始 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.maxTotal}" /> <!--最大分配的对象数 -->
<property name="maxIdle" value="${redis.maxIdle}" /> <!--最大能够保持idel空闲状态的对象数 -->
<property name="maxWaitMillis" value="${redis.maxWaitMillis}" /> <!--最大等待时间ms -->
<property name="testOnBorrow" value="${redis.testOnBorrow}" /> <!-- 当调用borrow Object方法时,在获取连接的时候是否进行检查有效性 -->
</bean>
<!-- redis连接工厂类 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}" p:port="${redis.port}" p:pool-config-ref="jedisPoolConfig" />
<!-- redis模板类 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="jedisConnectionFactory" />RedisBaseDao基类
package net.ibloger.wechat.redis.dao;
/**
* 设置一个Redis基类,根据泛型+反射整理,实现通用方法
* <br>
* keyId代表Class类名全路径 + "_" + keyId 例如:key为id,那么到实现类中,就是 net.ibloger.demo.User_id
* <br>
* 两个方法没有提供
* 一:没有提供修改方法,set中key相同替换相当于更新
* 二:没有提供添加集合方法,因为 T 不能确定某一个参数值,所以集合可以在自定义的dao中实现
* @param <T>
*/
public interface RedisBaseDao<T>{
/**
* 根据keyId查询实体
* @param cls
* @param keyId 以什么参数作为keyid
* @return
*/
public T getEntityByKey(final Class<T> cls, final String keyId);
/**
* 新增实体
* @param entity
* @param keyId
*/
public void addEntity(final T entity, final String keyId);
/**
* 新增实体(设置过期时间)
* @param entity
* @param keyId
* @param seconds 多少秒后过期
*/
public void addEntity(final T entity, final String keyId, long seconds);
/**
* 根据keyId删除实体
* @param cls
* @param keyId
*/
public void deleteEntityByKey(final Class<T> cls, final String keyId);
}RedisBaseDaoImpl实现类
package net.ibloger.wechat.redis.dao;
import java.io.Serializable;
import javax.annotation.Resource;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.Assert;
import com.google.gson.Gson;
/**
* 实现Redis通用基类
*
* @author http://www.ibloger.net
* @param <T>
*/
public class RedisBaseDaoImpl<T> implements RedisBaseDao<T> {
@Resource
protected RedisTemplate<Serializable, Serializable> redisTemplate;
/**
* 获取 RedisSerializer
*/
protected RedisSerializer<String> getStringSerializer() {
return redisTemplate.getStringSerializer();
}
@Override
public T getEntityByKey(final Class<T> cls, final String keyId) {
return redisTemplate.execute(new RedisCallback<T>() {
@Override
public T doInRedis(RedisConnection connection) throws DataAccessException {
byte[] key = getStringSerializer().serialize(cls.getName() + "_" + keyId);
if (connection.exists(key)) {
byte[] value = connection.get(key);
String json = getStringSerializer().deserialize(value);
return new Gson().fromJson(json, cls);
}
return null;
}
});
}
@Override
public void addEntity(final T entity, final String keyId) {
Assert.notNull(entity);
redisTemplate.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte[] key = getStringSerializer().serialize(entity.getClass().getName() + "_" + keyId);
byte[] name = getStringSerializer().serialize(new Gson().toJson(entity));
connection.set(key,name);
return null;
}
});
}
@Override
public void addEntity(final T entity, final String keyId, final long seconds) {
Assert.notNull(entity);
redisTemplate.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte[] key = getStringSerializer().serialize(entity.getClass().getName() + "_" + keyId);
byte[] name = getStringSerializer().serialize(new Gson().toJson(entity));
connection.setEx(key, seconds, name);
System.out.println("connection.getClientName(): "+connection.getClientName());
return null;
}
});
}
@Override
public void deleteEntityByKey(Class<T> cls, String keyId) {
redisTemplate.delete(cls.getName() + "_" + keyId);
}
}RedisKeyConfig,保存key配置
package net.ibloger.wechat.redis;
/**
* Redis服务器存储Key的配置
* @author X-rapido
*
*/
public class RedisKeyConfig {
/**
* 微信消息AccessToken
*/
public static String WX_Message_Access_Token = "WX_M_A_T";
}AccessToken基类
package net.ibloger.wechat.core.token;
import java.io.Serializable;
/**
* 微信通用接口凭证
*
* @author X-rapido
* @description
*/
public class AccessToken implements Serializable{
private static final long serialVersionUID = -8906695447214573189L;
private String token; // 获取到的凭证
private int expiresIn; // 凭证有效时间,单位:秒
private long invalidDate; // 失效时间
public AccessToken(){}
public AccessToken(String token, int expiresIn){
this.token = token;
this.expiresIn = expiresIn;
}
// 省略getter和setter
@Override
public String toString() {
return "AccessToken [token=" + token + ", expiresIn=" + expiresIn + ", invalidData=" + invalidDate + "]";
}
}AccessTokenDao
package net.ibloger.wechat.core.token;
public interface AccessTokenDao {
/**
* 添加token到redis缓存中(设置过期)
* @param accessToken
* @param seconds (秒)
* @return
*/
void addAccessToken(AccessToken accessToken, long seconds);
/**
* 从redis中删除token
*/
void deleteAccessToken();
/**
* 从redis缓存中获取token
* @return AccessToken
*/
AccessToken getAccessToken();
}AccessTokenDaoImpl
package net.ibloger.wechat.core.token;
import org.springframework.stereotype.Repository;
import net.ibloger.wechat.redis.RedisKeyConfig;
import net.ibloger.wechat.redis.dao.RedisBaseDaoImpl;
@Repository(value = "AccessTokenDao")
public class AccessTokenDaoImpl extends RedisBaseDaoImpl<AccessToken> implements AccessTokenDao{
@Override
public void deleteAccessToken() {
deleteEntityByKey(AccessToken.class, RedisKeyConfig.WX_Message_Access_Token);
}
@Override
public AccessToken getAccessToken() {
return getEntityByKey(AccessToken.class, RedisKeyConfig.WX_Message_Access_Token);
}
@Override
public void addAccessToken(AccessToken accessToken, long seconds) {
addEntity(accessToken, RedisKeyConfig.WX_Message_Access_Token, seconds);
}
}AccessTokenService
package net.ibloger.wechat.core.token;
import java.util.Date;
import javax.annotation.Resource;
import net.ibloger.wechat.core.WeChatConfig;
import net.ibloger.wechat.utils.DateUtils;
import net.ibloger.wechat.utils.HttpProxyUtil;
import net.ibloger.wechat.utils.SpringUtil;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
/**
* AccessToken服务类
* @author X-rapido
* @description 获取AccessToken对象,将对象保存在redis缓存中处理
*/
@Service(value="accessTokenService")
public class AccessTokenService {
private static Logger logger = Logger.getLogger(AccessTokenService.class);
@Resource(name = "AccessTokenDao")
private AccessTokenDao accessTokenDao;
/**
* 获取AccessToken对象
* @return
*/
public AccessToken getAccessToken(){
return getAccessToken(false);
}
/**
* 重新获取AccessToken对象
* @return
*/
public AccessToken getReqAccessToken(){
return getAccessToken(true);
}
/**
* 获取AccessToken对象
* @param reReq 是否重新请求AccessToken,在过期时候调用,默认为false
* @return
*/
public AccessToken getAccessToken(boolean reReq){
if(reReq){
logger.info("重新获取AccessToken");
return reqAccessToken();
}else {
AccessToken accessToken = accessTokenDao.getAccessToken();
// 判断时间是否过期
if (accessToken != null && (accessToken.getInvalidDate() > System.currentTimeMillis())) {
logger.info("缓存获取AccessToken,失效时间为:"+DateUtils.getStrByDate(new Date(accessToken.getInvalidDate()),"yyyy-MM-dd HH:mm:ss"));
return accessToken;
}else {
logger.info("缓存过期,重新获取AccessToken");
return reqAccessToken();
}
}
}
/**
* 获取服务器的AccessToken对象并存储在redis缓存中, 默认生效2小时,GET方式,限200(次/天)
* @return
*/
private AccessToken reqAccessToken() {
try {
String api_url = WeChatConfig.access_token_url.replace("{appid}", WeChatConfig.app_id).replace("{secret}", WeChatConfig.app_secret);
String result = HttpProxyUtil.sendGet(api_url);
if (StringUtils.isNotEmpty(result)) {
JSONObject jsonObject = JSONObject.fromObject(result);
AccessToken accessToken = new AccessToken();
accessToken.setToken(jsonObject.get("access_token").toString());
accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
accessToken.setInvalidDate(System.currentTimeMillis()+accessToken.getExpiresIn()*1000); // 取毫秒设置过期时间
accessTokenDao.addAccessToken(accessToken,accessToken.getExpiresIn()); // 添加设置到redis缓存中
return accessToken;
}
} catch (Exception e) {
logger.error("获取服务器的accessToken失败 "+ e.getMessage());
}
return null;
}
public static void main(String[] args) {
// 获取accessToken服务类
AccessTokenService service = (AccessTokenService) SpringUtil.getBean("accessTokenService");
String token = service.getAccessToken().getToken();
if (null != token) {
System.out.println("token: " + token);
}
}
}未经允许请勿转载:程序喵 » 微信公众号开发教程第19篇——使用Spring+Redis方式保存access_token
程序喵