spring+shiro+reids+ehcache實現session管理
前兩天,在專案中遇到需要對session管理的 一個需求,查詢了各種資料,也遇到了各種問題,不過,最後還是實現了需求,在此,也總結一下實現的過程,方便以後查閱。文中借鑑了很多其他文章內容,如有不當敬請諒解,一切以學習為主。
專案需求
- 統計檢視線上人數
- 控制線上人數,管理員可下線某線上使用者
- 控制使用者線上時長
保證同一使用者只能在同一客戶端登入
基於需求分析,考慮使用redis快取session的方案:
1.使用redis可方便的設定快取的有限期,這樣可控制使用者的線上時長問題。使用者登入,前端操作均會更新快取資料。
2.redis效能毋庸置疑,同時,redis的java api也能方便操作redis中的資料
專案依賴
<properties>
<!-- 主要依賴庫的版本定義 -->
<springside.version>4.2.3-GA</springside.version>
<spring.version>4.0.5.RELEASE</spring.version>
<shiro.version>1.2.3</shiro.version>
</properties>
<dependency>
<groupId> org.springside</groupId>
<artifactId>springside-core</artifactId>
<version>${springside.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version> ${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.1.1.RELEASE</version>
<type>pom</type>
</dependency
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>2.4.6</version>
</dependency>
web.xml配置filter,載入shiro和其他配置檔案
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:/applicationContext.xml,
classpath*:/applicationContext-shiro.xml,
classpath*:/applicationContext-session.xml
</param-value>
</context-param>
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
shiro配置檔案applicationContext-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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"
default-lazy-init="true">
<description>Shiro安全配置</description>
<!-- 專案自定義的Realm -->
<bean id="shiroRealm" class="com.sinosoft.bi.base.security.ShiroRealm"></bean>
<!-- Shiro's main business-tier object for web-enabled applications -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroRealm" />
<property name="sessionManager" ref="sessionManager"></property>
<property name="cacheManager" ref="shiroEhcacheManager" />
</bean>
<!-- Shiro Filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/" />
<property name="unauthorizedUrl" value="/unauthorized" />
<property name="filterChainDefinitions">
<value>
/login = authc
/logout = logout
/static/** = anon
/admin/** = roles[admin]
/** = user
</value>
</property>
</bean>
<!-- 使用者授權資訊Cache, 採用EhCache -->
<bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache/ehcache-shiro.xml" />
</bean>
<!-- 保證實現了Shiro內部lifecycle函式的bean執行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<!--開啟Shiro的註解-->
<!-- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean> -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="sessionDAO" ref="sessionDao"></property>
<property name="globalSessionTimeout" value="60000" />
<property name="deleteInvalidSessions" value="true"></property>
<!-- 刪除失效session -->
<property name="sessionValidationSchedulerEnabled" value="true" />
<property name="sessionListeners" ref="myShiroSessionListener"></property>
<!-- sessionIdCookie的實現,用於重寫覆蓋容器預設的JSESSIONID -->
<!-- <property name="sessionIdCookie" ref="sharesession" /> -->
</bean>
<!-- sessionIdCookie的實現,用於重寫覆蓋容器預設的JSESSIONID -->
<!-- <bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg name="name" value="SHAREJSESSIONID" />
<property name="path" value="/" />
<property name="httpOnly" value="true"/>
</bean> -->
<!-- Session ID 生成器 -->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"></bean>
<!-- session 監聽器 -->
<bean id="myShiroSessionListener" class="com.sinosoft.bi.base.security.MyShiroSessionListener"></bean>
<bean id="sessionDao" class="com.sinosoft.bi.base.security.SessionDao">
<property name="redisUtil" ref="redisUtil"></property>
<property name="sessionIdGenerator" ref="sessionIdGenerator"></property>
</bean>
</beans>
applicationContext-session.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" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"
default-lazy-init="true">
<!-- redis連線池配置-->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" >
<!--最大空閒數-->
<property name="maxIdle" value="${redis.maxIdle}" />
<!--連線池的最大資料庫連線數 -->
<property name="maxTotal" value="${redis.maxTotal}" />
<!--最大建立連線等待時間-->
<property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
<!--逐出連線的最小空閒時間 預設1800000毫秒(30分鐘)-->
<property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" />
<!--每次逐出檢查時 逐出的最大數目 如果為負數就是 : 1/abs(n), 預設3-->
<property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" />
<!--逐出掃描的時間間隔(毫秒) 如果為負數,則不執行逐出執行緒, 預設-1-->
<property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" />
<!--是否在從池中取出連線前進行檢驗,如果檢驗失敗,則從池中去除連線並嘗試取出另一個-->
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
<!--在空閒時檢查有效性, 預設false -->
<property name="testWhileIdle" value="${redis.testWhileIdle}" />
</bean >
<!-- redis叢集配置 哨兵模式 -->
<!-- <bean id="sentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<property name="master">
<bean class="org.springframework.data.redis.connection.RedisNode">
這個值要和Sentinel中指定的master的值一致,不然啟動時找不到Sentinel會報錯的
<property name="name" value="mymaster"></property>
</bean>
</property>
記住了,這裡是指定Sentinel的IP和埠,不是Master和Slave的
<property name="sentinels">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.sentinel.host1}"></constructor-arg>
<constructor-arg name="port" value="${redis.sentinel.port1}"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.sentinel.host2}"></constructor-arg>
<constructor-arg name="port" value="${redis.sentinel.port2}"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.sentinel.host3}"></constructor-arg>
<constructor-arg name="port" value="${redis.sentinel.port3}"></constructor-arg>
</bean>
</set>
</property>
</bean>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
</bean> -->
<!--redis連線工廠 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="poolConfig" ref="jedisPoolConfig"></property>
<!-- <property name="hostName" value="${redis.hostName}"></property>
<property name="port" value="${redis.port}"></property> -->
<property name="hostName" value="127.0.0.1"></property>
<!--埠號 -->
<property name="port" value="6379"></property>
<!--如果Redis設定有密碼 -->
<!-- <property name="password" value="${redis.password}" /> -->
<!--客戶端超時時間單位是毫秒 -->
<property name="timeout" value="${redis.timeout}"></property>
</bean>
<!--redis操作模版,使用該物件可以操作redis -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
<property name="connectionFactory" ref="jedisConnectionFactory" />
<!--如果不配置Serializer,那麼儲存的時候預設使用String,如果用User型別儲存,那麼會提示錯誤User can't cast to String!! 這裡配置之前啟動時,遇到的坑比較大,序列化之後,反序列化出現了問題,報了一個異常,找尋很久,才發現是這裡的配置出現了問題 -->
<property name="keySerializer" >
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer" >
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
</property>
<!--開啟事務 -->
<property name="enableTransactionSupport" value="true"></property>
</bean >
</beans>
redis配置檔案redis.properties
redis.hostName=127.0.0.1
redis.port=6379
#redis.password=123456
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true
ehcache-shiro.xml
<ehcache updateCheck="false" name="shiroCache">
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
</ehcache>
User實體
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private String userID;
private String username;
private String password;
...getter and setter
}
序列化和反序列化工具
public class SerializeUtils {
/**
* 序列化
*
* @param object
* @return
* @throws Exception
*/
public static byte[] serialize(Object object) throws Exception {
if(object == null) return null;
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {
throw e;
}
}
/**
* 反序列化
*
* @param bytes
* @return
* @throws Exception
*/
public static Object unSerialize(byte[] bytes) throws Exception {
if(bytes == null) return null;
ByteArrayInputStream bais = null;
try {
// 反序列化
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
// 把session物件轉化為byte儲存到redis中
public static byte[] sessionToByte(Session session){
ByteArrayOutputStream bo = null;
byte[] bytes = null;
ObjectOutput oo = null;
try {
bo = new ByteArrayOutputStream();
oo = new ObjectOutputStream(bo);
oo.writeObject(session);
bytes = bo.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(null != oo){
oo.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(null != bo){
bo.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return bytes;
}
// 把byte還原為session
public static Session byteToSession(byte[] bytes){
ObjectInputStream in = null;
Session session = null;
try {
in = new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(bytes)));
session = (Session) in.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return session;
}
}
redis工具類
/**
* @author myj
* 基於spring和redis的redisTemplate工具類
* 針對所有的hash 都是以h開頭的方法
* 針對所有的Set 都是以s開頭的方法 不含通用方法
* 針對所有的List 都是以l開頭的方法
*/
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<Serializable, Object> redisTemplate;
public void setRedisTemplate(RedisTemplate<Serializable, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
// =============================common============================
/**
* 指定快取失效時間
*
* @param key
* 鍵
* @param time
* 時間(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根據key 獲取過期時間
*
* @param key
* 鍵 不能為null
* @return 時間(秒) 返回0代表為永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判斷key是否存在
*
* @param key
* 鍵
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
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;
}
public List<String> keys(){
Set<Serializable> values = redisTemplate.keys("*");
List<String> list = new LinkedList<String>();
for (Object object : values) {
list.add((String)object);
}
return list;
}
/**
* 刪除快取
*
* @param key
* 可以傳一個值 或多個
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
/**
* 刪除對應的value
*
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判斷快取中是否有對應的value
*
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 批量刪除對應的value
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量刪除key
*
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern);
if (keys.size() > 0)
redisTemplate.delete(keys);
}
// ============================String=============================
/**
* 普通快取放入並設定時間
* @param key
* 鍵
* @param value
* 值
* @param time
* 時間(秒) time要大於0 如果time小於等於0 將設定無限期
* @return true成功 false 失敗
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 讀取快取
*
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 寫入快取
*
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 寫入快取
*
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 遞增
*
* @param key
* 鍵
* @param by
* 要增加幾(大於0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("遞增因子必須大於0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 遞減
*
* @param key
* 鍵
* @param by
* 要減少幾(小於0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("遞減因子必須大於0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ================================Map=================================
/**
* HashGet
*
* @param key
* 鍵 不能為null
* @param item
* 項 不能為null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 獲取hashKey對應的所有鍵值
*
* @param key
* 鍵
* @return 對應的多個鍵值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key
* 鍵
* @param map
* 對應多個鍵值
* @return true 成功 false 失敗
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 並設定時間
*
* @param key
* 鍵
* @param map
* 對應多個鍵值
* @param time
* 時間(秒)
* @return true成功 false失敗
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一張hash表中放入資料,如果不存在將建立
*
* @param key
* 鍵
* @param item
* 項
* @param value
* 值
* @return true 成功 false失敗
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一張hash表中放入資料,如果不存在將建立
*
* @param key
* 鍵
* @param item
* 項
* @param value
* 值
* @param time
* 時間(秒) 注意:如果已存在的hash表有時間,這裡將會替換原有的時間
* @return true 成功 false失敗
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 刪除hash表中的值
*
* @param key
* 鍵 不能為null
* @param item
* 項 可以使多個 不能為null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判斷hash表中是否有該項的值
*
* @param key
* 鍵 不能為null
* @param item
* 項 不能為null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash遞增 如果不存在,就會建立一個 並把新增後的值返回
*
* @param key
* 鍵
* @param item
* 項
* @param by
* 要增加幾(大於0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash遞減
*
* @param key
* 鍵
* @param item
* 項
* @param by
* 要減少記(小於0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================set=============================
/**
* 根據key獲取Set中的所有值
*
* @param key
* 鍵
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根據value從一個set中查詢,是否存在
*
* @param key
* 鍵
* @param value
* 值
*
相關推薦
spring+shiro+reids+ehcache實現session管理
前兩天,在專案中遇到需要對session管理的 一個需求,查詢了各種資料,也遇到了各種問題,不過,最後還是實現了需求,在此,也總結一下實現的過程,方便以後查閱。文中借鑑了很多其他文章內容,如有不當敬請諒解,一切以學習為主。
專案需求
統計檢視線上人數
spring-shiro-reids 叢集採用redis做session儲存
package com.iss.rdp.extension.web.shiro.cluster;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import
Spring Session實現Session管理的原理與詳細配置
原理請參考這篇文章很詳細:點選檢視
以下是我的在開發中使用配置
如果是maven工程,加入如下依賴:
<!-- spring-session -->
<dependency>
<groupId>
細說shiro之六:session管理
log sub href del 通過 tin image pre 整合 官網:https://shiro.apache.org/
- org.apache.shiro.session.Session
- org.apache.shiro.session.mgt
spring系統學習--spirngMVC之session管理
繼續把spirngmvc的關於session管理的筆記記一下。
第一步: 新建相關處理邏輯的控制器:
package com.automannn.springMVC_practice.controller;
import org.springframe
spring boot 使用ehcache 實現快取
所謂快取是一種儲存機制,可將資料儲存在某一個地方,並以一種更快的方式為以後的請求提供服務
spring 對於快取提供了宣告式快取註解 ,並提供了四種類型的宣告式快取註解(同樣是使用了AOP 技術實現),這些註解定義了那些 方法的返回值將要被快取或者從快取儲存器中移除 ,需要注意的是,
shiro框架之六-------session管理
官網:https://shiro.apache.org/
我們先來看一下shiro中關於Session和Session Manager的類圖。
如上圖所示,shiro自己定義了一個新的Session介面,用於統一操作介面,並通過SessionManager實現Session管理。 其中的3
shiro-shiroFilter,Realm實現,會話管理,securityManager
大家推薦個靠譜的公眾號程式設計師探索之路,大家一起加油,這個公眾號已經接入圖靈
最近一個小夥伴需要用到shiro我就順變弄了一份,還有很多需要完善的地方,以後慢慢完善。目前可以實現使用者角色,許可權,自定義realm,會話管理的功能
shiro配置檔案
&
spring boot 整合 EHcache 實現本地快取
需要的依賴如下,pom檔案新增
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-
shiro學習分享(四)——session管理以及單使用者登陸限制(網頁應用版)
session管理以及併發使用者登陸限制(網頁應用版)
首先講一下博主在shiro中對session和cookie使用的理解吧。
在每一次使用者成功登陸後,shiro都會自動的建立一個session並儲存在服務端,該session會包含Subject的基本資訊
Spring Boot 整合 log4j2 實現日誌管理
摘要:上一篇,我們講了Spring Boot 整合 log4j實現日誌管理,這一篇接著說一下Spring Boot 整合 log4j2,。
一:還是新建一個java工程:
二:增加log4j2的pom.xml配置,如下:
<project xmlns="htt
shiro 攔截器實現session過期攔截ajax請求的處理
攔截器程式碼:
package com.xlqh.outlook.shirofilter;
import java.io.IOException;
import org.apache.shiro.
spring security 在沒實現session共享的叢集環境下 防止使用者多次登入的 實現思路
背景
專案採用阿里雲負載均衡,基於cookie的會話保持。
沒有實現叢集間的session共享。
專案採用spring security 並且配置了session策略如下:
<bean
class="or
Spring Boot整合Druid實現資料來源管理與監控
1. 引言
在程式設計師的日常工作中, 經常需要編寫資料庫操作相關的程式,而這就需要資料連線池中介軟體用於管理資料庫連線。資料庫連線池負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是再重新建立一個;釋放空閒時間超過最大空閒時間
Spring Boot 整合 log4j 實現日誌管理報錯:java.lang.IllegalArgumentException: LoggerFactory is not a Logback
問題:
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Log
Spring Boot 整合 log4j 實現日誌管理
摘要:最近有時間,系統的學習了一下Spring Boot框架,感覺Spring Boot很好的集成了各種框架和元件,之前我們用Spring的時候,要配置好的依賴和xml檔案,現在使用Spring Boot,只需要一些少量的配置就可以實現。今天我們來看下Spring Boot
Spring AOP攔截Service實現日誌管理(自定義註解的方式)
最近專案中用到AOP方式進行Service操作方法日誌管理,特為之記!
1、先說理論和採用的方法
採用註解的方式,其中包括以下註解:@Aspect(類註解)和@AfterReturning(方法註解),其中需要用的Maven庫如下:
"org.aspectj:aspect
android http請求實現session管理
session一般儲存在Cookie當中,首先我們瞭解一下session和cookie
Cookie和Session都為了用來儲存狀態資訊,都是儲存客戶端狀態的機制,它們都是為了解決HTTP無狀態的問題而所做的努力。
Session可以用Cookie來實現,也可
spring-boot整合ehcache實現快取機制
EhCache 是一個純Java的程序內快取框架,具有快速、精幹等特點,是Hibernate中預設的CacheProvider。
ehcache提供了多種快取策略,主要分為記憶體和磁碟兩級,所以無需擔心容量問題。
spring-boot是一個快速的整合框架,其設計目的
008-shiro與spring web項目整合【二】認證、授權、session管理
添加 ner != efi ebs ref private date err 一、認證
1、添加憑證匹配器
添加憑證匹配器實現md5加密校驗。
修改applicationContext-shiro.xml:
<!-- realm -->