1. 程式人生 > 資料庫 >6.springboot2.X整合redis-cache-shiro

6.springboot2.X整合redis-cache-shiro

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客戶端

而報錯是jedis出來XXX問題,不知道怎麼解決
百度了很多都是沒用的,所以懶得看了


導依賴 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整合結束,如有錯誤多多指正~