除了使用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