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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章