当前位置: 首页 > 工具软件 > j2cache-shiro > 使用案例 >

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

倪灿
2023-12-01

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整合结束,如有错误多多指正~

 类似资料: