分布式session解决——Spring-data-redis
1.如果没有集成shiro来管理session,可以直接使用spring-session
2.若集成了shiro,需要Spring-data-redis (或 shiro-redis)
3.nginx设置
a.下载nginx
b.解压后,在conf目录下修改nginx.conf文件,配置反向代理
upstream tomcat_server{ server localhost:8080; } upstream tomcat_server2{ server localhost:8081; } server { listen 80; server_name localhost; location /blogproject { proxy_pass http://tomcat_server; } location /testnginx { proxy_pass http://tomcat_server2; } #location / { # proxy_pass http://tomcat_server; #} error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
c.在nginx根目录下打开cmd界面(shift+鼠标右键,选择在此处打开命令窗口)
d.nginx指令启动nginx:
#启动 start nginx #快速停止 nginx -s stop #正常停止 nginx -s quit #重装载 nginx -s reload
4.安装redis
a.由于官方是没有Windows版的,所以我们需要下载微软开发的redis,网址:https://github.com/MicrosoftArchive/redis/releases
b.解压后,在redis根目录打开cmd界面,输入:redis-server.exe redis.windows.conf,启动redis(关闭cmd窗口即停止)
5.shiro整合redis
a.导入依赖
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.4.1.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.5.2</version> </dependency>
b.新建spring-redis.xml 和 redis.properties
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}"></property> <property name="maxTotal" value="${redis.maxTotal}"></property> <property name="maxWaitMillis" value="${redis.maxWaitMillis}"></property> <property name="testOnBorrow" value="${redis.testOnBorrow}"></property> </bean> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="usePool" value="${redis.pooled}"></property> <property name="hostName" value="${redis.host}"></property> <property name="port" value="${redis.port}"></property> <property name="poolConfig" ref="jedisPoolConfig"></property> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory"></property> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean> </property> <!-- 解决读取int类型value值报错的问题 --> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean> </property> </bean> </beans>
redis.host=localhost
redis.port=6379
redis.maxIdle=30
redis.maxTotal=100
redis.maxWaitMillis=1000
redis.testOnBorrow=true
redis.pooled=true
注意:redis.properties 需要用 <context:property-placeholder /> 导入,但是全xml有且仅能有有个<context:property-placeholder />
<!-- 导入配置文件 --> <context:property-placeholder location="classpath:jdbc.properties,classpath:solr.properties,classpath:redis.properties"/>
c.新建类RedisManager
@Component public class RedisManager { @Resource private RedisTemplate<String, Session> redisTemplate; private static final String KEY = "shareSessionMap"; public void hadd(String sessionId, byte[] bytes){ redisTemplate.boundHashOps(KEY).put(sessionId, bytes); } public void hadd(String sessionId, Session session){ redisTemplate.boundHashOps(KEY).put(sessionId, session); } public void hdelete(String sessionId){ redisTemplate.boundHashOps(KEY).delete(sessionId); } public Session hget(String sessionId){ return (Session) redisTemplate.boundHashOps(KEY).get(sessionId); } public List<Session> hmget(){ List<Session> list = new ArrayList<Session>(); List<Object> values = redisTemplate.boundHashOps(KEY).values(); for (Object object : values) { list.add((Session) object); } return list; } }
d.新建类SessionDao,继承AbstractSessionDAO,重写方法
@Component public class SessionDao extends AbstractSessionDAO { @Resource private RedisManager redisManager; @Override public void delete(Session session) { if(session == null || session.getId() == null){ System.out.println("Session为空"); return; } redisManager.hdelete(session.getId().toString()); } @Override public Collection<Session> getActiveSessions() { List<Session> list = redisManager.hmget(); return list; } @Override public void update(Session session) throws UnknownSessionException { if(session == null || session.getId() == null){ System.out.println("Session为空"); return; } Serializable sessionId = session.getId(); redisManager.hadd(sessionId.toString(), session); } @Override protected Serializable doCreate(Session session) { Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId); //添加进redis redisManager.hadd(sessionId.toString(), session); return sessionId; } @Override protected Session doReadSession(Serializable sessionId) { return redisManager.hget(sessionId.toString()); } }
e.spring-shiro.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 使用spring组件扫描@service --> <context:component-scan base-package="com.wode.service"/> <!-- 自定义域realm --> <bean id="custom_Realm" class="com.wode.realm.CustomRealm"> <property name="credentialsMatcher" > <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="MD5"></property> <property name="hashIterations" value="1"></property> </bean> </property> </bean> <!-- 安全管理器 ref对象--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="custom_Realm"/> <!-- session管理 --> <property name="sessionManager" ref="sessionManager"></property> </bean> <!-- shiro filter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 安全管理器必须的 --> <property name="securityManager" ref="securityManager"/> <!-- 身份认证失败 认证提交的地址 --> <property name="loginUrl" value="/"/> <!-- 权限认证失败 没有权限认证提交的地址 --> <property name="unauthorizedUrl" value="/unauthorized"/> <!-- Shiro连接约束配置,即过滤链的定义 --> <property name="filterChainDefinitions"> <value> <!-- 对静态资源设置匿名访问 --> / = anon /login = anon /go2RegisterPage = anon /register = anon /static/** = anon <!-- 必须要管理员角色才能访问 --> /admin/** = roles[admin] <!-- 所有url都必须认证通过才可以访问 --> /** = authc </value> </property> </bean> <!-- Shiro生命周期处理器 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> <!-- Session ID 生成器 --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"></bean> <!-- SessionDao实现类 --> <bean id="sessionDAO" class="com.wode.session.SessionDao"> <property name="sessionIdGenerator" ref="sessionIdGenerator"></property> </bean> <!-- session管理 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000"></property> <property name="deleteInvalidSessions" value="true"></property> <property name="sessionDAO" ref="sessionDAO"></property> <!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID --> <property name="sessionIdCookie" ref="sharesession" /> </bean> <!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID --> <bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie"> <!-- cookie的name,对应的默认是 JSESSIONID --> <constructor-arg name="name" value="SHAREJSESSIONID" /> <!-- jsessionId的path为 / 用于多个系统共享jsessionId --> <property name="path" value="/" /> <property name="httpOnly" value="true"/> </bean> </beans>