问题
- 在集群环境中,session需要共享,此时可以借助中间件来操作。我们可以自己实现,通过cookie跟redis的组合来共享集群的session,之前也做过类似的操作https://github.com/yuyufeng1994/SessionShare
- 在Spring中,已经提供了插件——spring-session-data-redis,本文就来记录下此方法的使用(基于SpringBoot)
pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
</dependencies>
redis配置
RedisProperties .class
package top.yuyufeng.sample.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author yuyufeng
* @date 2018/4/19.
*/
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private int database;
/**
* Redis服务器地址
*/
private String host;
/**
* Redis服务器连接端口
*/
private int port;
/**
* Redis服务器连接密码(默认为空)
*/
private String password;
/**
* 连接池最大连接数(使用负值表示没有限制)
*/
private int maxTotal;
/**
* 连接池最大阻塞等待时间(使用负值表示没有限制)
*/
private int maxWaitMillis;
/**
* 连接池中的最大空闲连接
*/
private int maxIdle;
/**
* 连接池中的最小空闲连接
*/
private int minIdle;
/**
* 连接超时时间(毫秒)
*/
private int timeout;
private boolean testOnBorrow;
private boolean testOnReturn;
//setters and getters
}
RedisConfig.class
package top.yuyufeng.sample.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
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;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import redis.clients.jedis.JedisPoolConfig;
import top.yuyufeng.sample.config.properties.RedisProperties;
import java.lang.reflect.Method;
@Configuration
@EnableCaching
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private RedisProperties properties;
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
return template;
}
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
return template;
}
@Bean
public RedisConnectionFactory connectionFactory() {
JedisConnectionFactory jedis = new JedisConnectionFactory();
jedis.setHostName(properties.getHost());
jedis.setPort(properties.getPort());
jedis.setPassword(properties.getPassword());
jedis.setDatabase(properties.getDatabase());
jedis.setPoolConfig(poolCofig());
// 初始化连接pool
jedis.afterPropertiesSet();
return jedis;
}
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager manager = new RedisCacheManager(redisTemplate);
return manager;
}
@Bean
public JedisPoolConfig poolCofig() {
JedisPoolConfig poolCofig = new JedisPoolConfig();
poolCofig.setMaxIdle(properties.getMaxIdle());
poolCofig.setMaxTotal(properties.getMaxTotal());
poolCofig.setMaxWaitMillis(properties.getMaxWaitMillis());
poolCofig.setTestOnBorrow(properties.isTestOnBorrow());
poolCofig.setTestOnReturn(properties.isTestOnReturn());
return poolCofig;
}
@Bean
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
StringBuilder builder = new StringBuilder();
builder.append(o.getClass().getName());
builder.append(method.getName());
for (Object obj : objects) {
if (obj != null) {
builder.append(obj.toString());
} else {
builder.append("null");
}
}
return builder.toString();
}
};
}
}
拦截器层
package top.yuyufeng.sample.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import top.yuyufeng.sample.vo.UserVO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author yuyufeng
* @date 2018/4/19.
*/
public class AuthorityInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
String uri = httpServletRequest.getRequestURI();
if (uri.equals("/info") || uri.equals("/login")) {
return true;
}
Object object = httpServletRequest.getSession().getAttribute("user");
System.out.println("user:" + object);
if (object == null) {
httpServletResponse.sendRedirect("/info");
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
登录对象
package top.yuyufeng.sample.vo;
/**
* @author yuyufeng
* @date 2018/4/19.
*/
public class UserVO {
private String userName;
private String userPassword;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
@Override
public String toString() {
return "UserVO{" +
"userName='" + userName + '\'' +
", userPassword='" + userPassword + '\'' +
'}';
}
}
登录action
package top.yuyufeng.sample.web;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.yuyufeng.sample.vo.UserVO;
import javax.servlet.http.HttpServletRequest;
/**
* @author yuyufeng
* @date 2018/4/19.
*/
@RestController
public class LoginController {
@RequestMapping(value = "login")
String doLogin(HttpServletRequest request) {
UserVO user = new UserVO();
user.setUserName("yyf");
user.setUserPassword("12345");
System.out.println(user);
request.getSession().setAttribute("user", user.toString());
return "登录成功";
}
@RequestMapping(value = "quit")
String doQuit(HttpServletRequest request) {
request.getSession().removeAttribute("user");
return "退出成功";
}
}
启动
package top.yuyufeng.sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import top.yuyufeng.sample.interceptor.AuthorityInterceptor;
/**
* @author yuyufeng
* @date 2018/4/19.
*/
@SpringBootApplication
@EnableRedisHttpSession(maxInactiveIntervalInSeconds= 360) //maxInactiveIntervalInSeconds为SpringSession的过期时间(单位:秒)
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthorityInterceptor());
}
}
application.yml
server:
port: 8080
spring:
session:
store-type: redis
redis:
database: 0
host: 127.0.0.1
port: 6379
password: 12345
maxTotal: 1000
maxWaitMillis: 5000
maxIdle: 500
minIdle: 0
timeout: 1000
调试
启动两个端口,8080、8081,会看到,在一个页面登录了,调到另一个页面也是登录的。可以打开cookie看下,session是同一个key,
然后,可以去redis中查看下对于的value
代码地址
https://gitee.com/mryyf/sample-springboot-session-redis