spring、redis集成session共享以及与spring缓存注解@CacheConfig、@CachePut、@CacheEvict配合使用
步骤:
1.maven项目导入pom.xml jar包
org.springframework.data
spring-data-redis
1.8.4.RELEASE
redis.clients
jedis
2.9.0
org.springframework.session
spring-session
1.3.1.RELEASE
org.springframework.session
spring-session-data-redis
1.3.1.RELEASE
2.添加配置文件spring-redis.xml
3.添加属性文件redis.properties
redis.host=
redis.port=6379
redis.password=
redis.session.db=1
redis.comm.db=3
cookie.domainName=localhost
cookie.cookieName=DTL_SESSION_ID
cookie.cookiePath=/
4.配置web.xml
contextConfigLocation
classpath:/spring/spring-redis.xml
springSessionRepositoryFilter
org.springframework.web.filter.DelegatingFilterProxy
springSessionRepositoryFilter
/*
5.创建spring-redis.xml配置中相关重新写的redis公共类
5.1创建公用的RedisTemplate.java类用于自己注入调用
package com.zxjt.crm.base.cache.redis;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;
import redis.clients.jedis.exceptions.JedisException;
/**
* @autor sunll
* Redis模板工具类
*/
public class RedisTemplate {
private JedisPool jedisPool;
/**
* 设置缓存
* @param key
* @param value
* @return
*/
public String set(String key ,String value){
String result = null;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.set(key, value);
} catch (Exception e) {
closeResource(jedis);
e.printStackTrace();
} finally {
closeResource(jedis);
}
return result;
}
/**
* 修改缓存
* @param key
* @param value
* @return
*/
public String update(String key ,String value){
String result = null;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.rename(key, value);
} catch (Exception e) {
closeResource(jedis);
e.printStackTrace();
} finally {
closeResource(jedis);
}
return result;
}
/**
* 设置缓存,超时
* @param key 键
* @param value 值
* @param cacheSeconds 超时时间,0为不超时
* @return
*/
public String setExpire(String key, String value, int cacheSeconds) {
String result = null;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.set(key, value);
if (cacheSeconds != 0) {
jedis.expire(key, cacheSeconds);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeResource(jedis);
}
return result;
}
/**
* 获取缓存
* @param key 键
* @return 值
*/
public String get(String key) {
String value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
value = jedis.get(key);
value = StringUtils.isNotBlank(value)
&& !"nil".equalsIgnoreCase(value) ? value : null;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeResource(jedis);
}
return value;
}
/**
* 获取缓存
* @param key 键
* @return 值
*/
public JSONObject getObject(String key) {
String value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
value = jedis.get(key);
value = StringUtils.isNotBlank(value)
&& !"nil".equalsIgnoreCase(value) ? value : null;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeResource(jedis);
}
JSONObject jsStr = JSONObject.fromObject(value);
return jsStr;
}
/**
* 获取缓存
* @param key 键
* @return 值
*/
public void delete(String key) {
Jedis jedis = null;
try {
jedis = getResource();
jedis.del(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeResource(jedis);
}
}
/**
* 获取资源
* @return
* @throws JedisException
*/
public Jedis getResource() throws JedisException {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
} catch (JedisException e) {
e.printStackTrace();
closeResource(jedis);
throw e;
}
return jedis;
}
/**
* 释放资源
* @param jedis
*/
public void closeResource(Jedis jedis) {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
public JedisPool getJedisPool() {
return jedisPool;
}
public void setJedisPool(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
}
5.2创建session共享cookie类重写其中的一部分方法
package com.zxjt.crm.base.cache.redis;
import org.apache.xerces.impl.dv.util.Base64;
import org.springframework.session.web.http.CookieSerializer;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by sunll on 2017/3/28.
*/
public class ClientCookieSerializer implements CookieSerializer {
private String cookieName = "SESSION";
private Boolean useSecureCookie;
private boolean useHttpOnlyCookie = this.isServlet3();
private String cookiePath;
private int cookieMaxAge = -1;
private String domainName;
private Pattern domainNamePattern;
private String jvmRoute;
private boolean useBase64Encoding;
private String rememberMeRequestAttribute;
public ClientCookieSerializer() {
}
public List readCookieValues(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
ArrayList matchingCookieValues = new ArrayList();
if(cookies != null) {
Cookie[] var4 = cookies;
int var5 = cookies.length;
for(int var6 = 0; var6 < var5; ++var6) {
if (var6 != 0 || var5 == 1) {
Cookie cookie = var4[var6];
if (this.cookieName.equals(cookie.getName())) {
String sessionId = this.useBase64Encoding ? this.base64Decode(cookie.getValue()) : cookie.getValue();
if (sessionId != null) {
if (this.jvmRoute != null && sessionId.endsWith(this.jvmRoute)) {
sessionId = sessionId.substring(0, sessionId.length() - this.jvmRoute.length());
}
matchingCookieValues.add(sessionId);
}
}
}
}
}
return matchingCookieValues;
}
public void writeCookieValue(CookieValue cookieValue) {
HttpServletRequest request = cookieValue.getRequest();
HttpServletResponse response = cookieValue.getResponse();
String requestedCookieValue = cookieValue.getCookieValue();
String actualCookieValue = this.jvmRoute == null?requestedCookieValue:requestedCookieValue + this.jvmRoute;
Cookie sessionCookie = new Cookie(this.cookieName, this.useBase64Encoding?this.base64Encode(actualCookieValue):actualCookieValue);
sessionCookie.setSecure(this.isSecureCookie(request));
sessionCookie.setPath(this.getCookiePath(request));
String domainName = this.getDomainName(request);
if(domainName != null) {
sessionCookie.setDomain(domainName);
}
if(this.useHttpOnlyCookie) {
sessionCookie.setHttpOnly(true);
}
if("".equals(requestedCookieValue)) {
sessionCookie.setMaxAge(0);
} else if(this.rememberMeRequestAttribute != null && request.getAttribute(this.rememberMeRequestAttribute) != null) {
sessionCookie.setMaxAge(2147483647);
} else {
sessionCookie.setMaxAge(this.cookieMaxAge);
}
response.addCookie(sessionCookie);
}
private String base64Decode(String base64Value) {
try {
byte[] e = Base64.decode(base64Value);
return new String(e);
} catch (Exception var3) {
return null;
}
}
private String base64Encode(String value) {
String encodedCookieBytes = Base64.encode(value.getBytes());
return new String(encodedCookieBytes);
}
public void setUseSecureCookie(boolean useSecureCookie) {
this.useSecureCookie = Boolean.valueOf(useSecureCookie);
}
public void setUseHttpOnlyCookie(boolean useHttpOnlyCookie) {
if(useHttpOnlyCookie && !this.isServlet3()) {
throw new IllegalArgumentException("You cannot set useHttpOnlyCookie to true in pre Servlet 3 environment");
} else {
this.useHttpOnlyCookie = useHttpOnlyCookie;
}
}
private boolean isSecureCookie(HttpServletRequest request) {
return this.useSecureCookie == null?request.isSecure():this.useSecureCookie.booleanValue();
}
public void setCookiePath(String cookiePath) {
this.cookiePath = cookiePath;
}
public void setCookieName(String cookieName) {
if(cookieName == null) {
throw new IllegalArgumentException("cookieName cannot be null");
} else {
this.cookieName = cookieName;
}
}
public void setCookieMaxAge(int cookieMaxAge) {
this.cookieMaxAge = cookieMaxAge;
}
public void setDomainName(String domainName) {
if(this.domainNamePattern != null) {
throw new IllegalStateException("Cannot set both domainName and domainNamePattern");
} else {
this.domainName = domainName;
}
}
public void setDomainNamePattern(String domainNamePattern) {
if(this.domainName != null) {
throw new IllegalStateException("Cannot set both domainName and domainNamePattern");
} else {
this.domainNamePattern = Pattern.compile(domainNamePattern, 2);
}
}
public void setJvmRoute(String jvmRoute) {
this.jvmRoute = "." + jvmRoute;
}
public void setUseBase64Encoding(boolean useBase64Encoding) {
this.useBase64Encoding = useBase64Encoding;
}
public void setRememberMeRequestAttribute(String rememberMeRequestAttribute) {
if(rememberMeRequestAttribute == null) {
throw new IllegalArgumentException("rememberMeRequestAttribute cannot be null");
} else {
this.rememberMeRequestAttribute = rememberMeRequestAttribute;
}
}
private String getDomainName(HttpServletRequest request) {
if(this.domainName != null) {
return this.domainName;
} else {
if(this.domainNamePattern != null) {
Matcher matcher = this.domainNamePattern.matcher(request.getServerName());
if(matcher.matches()) {
return matcher.group(1);
}
}
return null;
}
}
private String getCookiePath(HttpServletRequest request) {
if (this.cookiePath == null) {
// 此处改为返回根路径
return "/";
}
return this.cookiePath;
}
private boolean isServlet3() {
try {
ServletRequest.class.getMethod("startAsync", new Class[0]);
return true;
} catch (NoSuchMethodException var2) {
return false;
}
}
}
5.3创建 RedisCache redis自定义的工具类,自定义redis的key生成规则
package com.zxjt.crm.base.cache.redis;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
/**
* 开启redis缓存注解
* @author sunll
*/
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
protected final static Logger log = LoggerFactory.getLogger(RedisCacheConfig.class);
private volatile JedisConnectionFactory mJedisConnectionFactory;
private volatile RedisTemplate mRedisTemplate;
private volatile RedisCacheManager mRedisCacheManager;
public RedisCacheConfig() {
super();
}
public RedisCacheConfig(JedisConnectionFactory mJedisConnectionFactory, RedisTemplate mRedisTemplate, RedisCacheManager mRedisCacheManager) {
super();
this.mJedisConnectionFactory = mJedisConnectionFactory;
this.mRedisTemplate = mRedisTemplate;
this.mRedisCacheManager = mRedisCacheManager;
}
public JedisConnectionFactory redisConnectionFactory() {
return mJedisConnectionFactory;
}
public RedisTemplate redisTemplate(RedisConnectionFactory cf) {
return mRedisTemplate;
}
public CacheManager cacheManager(RedisTemplate, ?> redisTemplate) {
return mRedisCacheManager;
}
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method,
Object... params) {
//规定 本类名+方法名+参数名 为key
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName()+"_");
sb.append(method.getName()+"_");
for (Object obj : params) {
sb.append(obj.toString()+",");
}
return sb.toString();
}
};
}
}
6.测试创建controller方法
package com.zxjt.crm.controller.channel;
import com.zxjt.crm.base.cache.redis.RedisTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/channel")
public class ChannelController {
@Autowired
RedisTemplate redisTemplate;
@ResponseBody
@RequestMapping(value = "/s")
@Cacheable(value="myUser",key = "#userName")
public String selectList(String userName) {;
System.out.println("没有使用缓存s");
return "a";
}
@ResponseBody
@RequestMapping(value = "/s1")
@CacheEvict(value="myUser",key = "#userName")
public String del(String userName) {;
System.out.println("没有使用缓存s1");
return "afafasfafaf";
}
@ResponseBody
@RequestMapping(value = "/s2")
@CacheEvict(value="myUser")
public String update() {;
System.out.println("没有使用缓存s2");
return "af";
}
@ResponseBody
@RequestMapping(value = "/s3")
@Cacheable(value="myUser")
public String selectList3() {;
System.out.println("没有使用缓存s3");
return "s3";
}
@ResponseBody
@RequestMapping(value = "/s4")
@Cacheable(value="myCach")
public String selectList4() {;
System.out.println("没有使用缓存s4");
return "s4";
}
@ResponseBody
@RequestMapping(value = "/s5")
public String selectList5() {;
redisTemplate.set("sunll","测试自定义的redis数据");
return redisTemplate.get("sunll");
}
}
7.总结:
到此为止所有的spring、redis以及session共享和spring注解缓存集成完成
8.备注:
相关参数解释:
JedisPoolConfig jedis连接池配置对象
JedisConnectionFactory jedis连接工厂,生成连接对象
RedisTemplate RedisTemplate 对 RedisConnection 进行了封装。提供连接管理,序列化等功能,它对 Redis 的交互进行了更高层次的抽象,极大的方便和简化了 Redis 的操作
RedisCacheManager 做为 redis 统一的调度和管理者
RedisCacheConfig RedisCacheConfig extends org.springframework.cache.annotation.CachingConfigurerSupport,自定义redis的key生成规则,如果不在注解参数中注明key=“”的话,就采用这个类中的key生成规则生成key
spring缓存注解@CacheConfig、@CachePut、@CacheEvict使用方法
最后给出这几个注解的具体参数以及使用相关配图参考。
参考自:http://blog.csdn.net/sanjay_f/article/details/47372967
表 1. @Cacheable 作用和配置方法
@Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@Cacheable 主要的参数 |
value |
缓存的名称,缓存中具体哪个数据库,在 spring 配置文件中定义,必须指定至少一个 |
例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”} |
key |
缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合,或者方法参数列表中的任意一个参数,或者字符串+参数组合 |
例如: @Cacheable(value=”testcache”,key=”#userName”) @Cacheable(value=”testcache”,key=” '字符串'+#userName”) |
condition |
缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 |
例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
表 2. @CachePut 作用和配置方法
@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用
@CachePut 主要的参数 |
value |
缓存的名称,在 spring 配置文件中定义,必须指定至少一个 |
例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”} |
key |
缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 |
例如: @Cacheable(value=”testcache”,key=”#userName”) |
condition |
缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 |
例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
表 3. @CacheEvict 作用和配置方法
@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空
@CacheEvict 主要的参数 |
value |
缓存的名称,在 spring 配置文件中定义,必须指定至少一个 |
例如: @CachEvict(value=”mycache”) 或者 @CachEvict(value={”cache1”,”cache2”} |
key |
缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 |
例如: @CachEvict(value=”testcache”,key=”#userName”) |
condition |
缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存 |
例如: @CachEvict(value=”testcache”, condition=”#userName.length()>2”) |
allEntries |
是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 |
例如: @CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation |
是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 |
例如: @CachEvict(value=”testcache”,beforeInvocation=true) |
spEL表达式的使用方法:http://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/expressions.html
关于注解实现Redis缓存的方法,只有将key设计的合理且强大,整个的缓存在项目中才能通用且高效。
想要使用@CachEvic去清除固定的key缓存需要和注解@Cacheable中的key一致,如何不设置key和allEntries则无法清除缓存,allEntries=ture为清除value=“”相同的所有的缓存