6.springboot2.X整合redis-cache-shiro
阿新 • • 發佈:2020-02-28
1.案例中shrio 邏輯認證會頻繁的查詢資料庫,消耗效能
2.改造一下,把之前學習的快取中介軟體拿來用
<!--shiro整合redis快取,和之前的快取不同-->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>2.4.2.1-RELEASE</version>
</dependency>
這種整合方式沒有搞懂 會爆錯
具體原因是springboot2.X預設是lettuce客戶端
百度了很多都是沒用的,所以懶得看了
導依賴 commons-pool2 spring-boot-starter-data-redis spring-boot-starter-cache
<!--spring2.0整合redis所需common-pool2--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.4.2</version> </dependency> <!-- redis依賴,2.0以上使用這個依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 快取依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
配置檔案
#redis #第幾個資料庫,由於redis中資料庫不止一個 spring.redis.database=2 # 也可指定為127.0.0.1 spring.redis.host=127.0.0.1 # 預設埠 spring.redis.port=6379 spring.redis.password= #預設為空 # springboot2.x以上如此配置,由於2.x的客戶端是lettuce # 單位要帶上 spring.redis.lettuce.pool.max-active=8 spring.redis.lettuce.pool.min-idle=1 spring.redis.lettuce.pool.max-idle=8 spring.redis.lettuce.pool.max-wait=10000ms spring.redis.lettuce.shutdown-timeout=100ms
redis快取的一些配置
>@Slf4j
@Configuration
@EnableCaching
public class RedisCache extends CachingConfigurerSupport {
// 自定義key生成器
@Bean
public KeyGenerator keyGenerator() {
return (o,method,params) -> {
StringBuilder sb = new StringBuilder ( );
sb.append (o.getClass ( ).getName ( )); // 類目
sb.append (method.getName ( )); // 方法名
for (Object param : params) {
sb.append (param.toString ( )); // 引數名
}
return sb.toString ( );
};
}
// 配置快取管理器
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig ( )
.entryTtl (Duration.ofSeconds (60 * 60 * 24 * 3)) // 快取*秒失效
// 設定key的序列化方式
.serializeKeysWith (RedisSerializationContext.SerializationPair.fromSerializer (keySerializer ( )))
// 設定value的序列化方式
.serializeValuesWith (RedisSerializationContext.SerializationPair.fromSerializer (valueSerializer ( )))
// 不快取null值
.disableCachingNullValues ( );
RedisCacheManager redisCacheManager = RedisCacheManager.builder (connectionFactory)
.cacheDefaults (config)
.transactionAware ( )
.build ( );
log.info ("自定義RedisCacheManager載入完成");
return redisCacheManager;
}
// key鍵序列化方式
private RedisSerializer<String> keySerializer() {
return new StringRedisSerializer ( );
}
// value值序列化方式
private GenericJackson2JsonRedisSerializer valueSerializer() {
return new GenericJackson2JsonRedisSerializer ( );
}
}
開啟快取 使用註解@EnableCaching
>@EnableCaching
@SpringBootApplication
public class ShiroApplication {
public static void main(String[] args) {
SpringApplication.run (ShiroApplication.class,args);
}
}
快取註解,在業務層呼叫
@Cacheable在方法上 注意key如果定義了沒有的鍵或值會報500,預設是引數作為simplekey
許可權和角色一般都不會變 假如變更了 使用@CacheEvict移除一個或者多個快取 詳情百度
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
@Override
@Cacheable(cacheNames = "users",key ="#name")
public User getPwdByName(String name) {
System.out.println(name+":資料庫查詢使用者中.....");
return userDao.getPwdByName (name);
}
@Override
@Cacheable(cacheNames = "roles",key = "#name")
public List<String> listRoles(String name) {
System.out.println(name+":資料庫查詢角色中.....");
return userDao.listRoles (name);
}
@Override
@Cacheable(cacheNames = "Permissions",key = "#name")
public List<String> listPermissions(String name) {
System.out.println(name+":資料庫查詢使用者許可權中");
return userDao.listPermissions (name);
}
測試:
正確輸入賬號密碼都可以使用 但是出現一個Bug 輸入錯誤的登陸會跳出error500 顯然之前設定的出錯跳轉回登陸頁失效了
原因是你輸入了錯誤的資訊資料庫查詢不到內容 key為使用者名稱 value為null 快取策略是value為空不快取
IllegalArgumentException: Cache ‘users’ does not allow ‘null’ values. Avoid storing null via ‘@Cacheable(unless="#result == null")’ or configure RedisCache to allow ‘null’ via RedisCacheConfiguration.
所以爆了500
解決:
方案1:
@Controller public class LoginController {
//表單提交,處理後返回首頁
@PostMapping("/tologin")
String tologin(String name,String password,Model model) {
//處理邏輯
/**使用Shiro編寫認證操作*/
//1.獲取Subject
Subject subject = SecurityUtils.getSubject ( );
//2.封裝使用者資料
UsernamePasswordToken token = new UsernamePasswordToken (name,password);
//執行登陸方法
try {
subject.login (token);
//登陸資訊會交給Realm去執行認證邏輯,比如去資料庫對比使用者,密碼
//然後會設定角色,許可權
} catch (UnknownAccountException e) {
model.addAttribute ("msg","使用者名稱不存在");
return "/login";
} catch (IncorrectCredentialsException e) {
model.addAttribute ("msg","密碼錯誤");
return "/login";
}catch (Exception e){
//redis 資料庫沒查到值
model.addAttribute ("msg","使用者名稱不存在");
return "/login";
}
//這裡的請求不能返回"/index"這是返回index.html了 沒有經過mvc攔截到
// 必須使用"redirect:/index" 或者"forward:/index"
//catch塊可以跳轉是因為我的頁面就叫login.html 請求也是/login
return "redirect:/index";
}
方案2:
設定快取條件:unless="#result == null" 快取到redis 除非結果是空
@Override
@Cacheable(cacheNames = "users",key ="#name",unless="#result == null")
public User getPwdByName(String name) {
System.out.println(name+":資料庫查詢使用者中.....");
return userDao.getPwdByName (name);
}
shrio整合結束,如有錯誤多多指正~