Springboot2.x+shiro+redis(Lettuce)整合填坑

主要记录关键和有坑的地方html

前提:java

一、SpringBoot+shiro已经集成完毕,若是没有集成,先查阅以前的Springboot2.0 集成shiro权限管理redis

二、redis已经安装完成spring

三、redis客户端使用Lettuce,这也是sprinboot2.0后默认的,与jedis的区别,自行百度apache

四、json使用springboot默认的json

1、依赖缓存

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    //在用使用shiro的状况下集成redis,能够带这个依赖,shiro-redis已经实现了shiro的redis缓存和session管理
    //若是shiro和redis集成可是不交互,能够不引入,能够自定义 <dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis</artifactId> <version>3.1.0</version> </dependency>

链接池:springboot

<!--链接池,redis依赖-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

 

 

必须注销:session

<!--与reids缓存冲突-->
        <!--<dependency>-->
            <!--<groupId>org.springframework.boot</groupId>-->
            <!--<artifactId>spring-boot-devtools</artifactId>-->
            <!--<optional>true</optional>-->
        <!--</dependency>-->

2、Application.ymlapp

 
  
spring:
...省略

cache:
redis:
time-to-live: 60s
type: redis
redis:
host: 127.0.0.1
port: 6379
password: 123456@abc.com
timeout: 10000
lettuce:
pool:
max-idle: 10
max-active: 10
min-idle: 5
max-wait: 10000
database: 0

 

3、redis配置类

@Configuration @EnableCaching //开启Springboot缓存,重要!!! public class RedisConfig extends CachingConfigurerSupport { @Resource private LettuceConnectionFactory lettuceConnectionFactory; private Duration timeToLive = Duration.ofSeconds(60); @Bean //在没有指定缓存Key的状况下,key生成策略 public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuffer sb = new StringBuffer(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } // 缓存管理器 使用Lettuce,和jedis有很大不一样
 @Bean public CacheManager cacheManager() {
//关键点,spring cache的注解使用的序列化都从这来,没有这个配置的话使用的jdk本身的序列化,实际上不影响使用,只是打印出来不适合人眼识别 RedisCacheConfiguration config
= RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))//key序列化方式 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))//value序列化方式 .disableCachingNullValues()
.entryTtl(timeToLive);//缓存过时时间 RedisCacheManager.RedisCacheManagerBuilder builder
= RedisCacheManager.RedisCacheManagerBuilder .fromConnectionFactory(lettuceConnectionFactory) .cacheDefaults(config) .transactionAware(); return builder.build(); } /** * RedisTemplate配置 在单独使用redisTemplate的时候 从新定义序列化方式 */ @Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { // 设置序列化 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>( Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // 配置redisTemplate RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); RedisSerializer<?> stringSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringSerializer);// key序列化 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化 redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化 redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化 redisTemplate.afterPropertiesSet(); return redisTemplate; } private RedisSerializer<String> keySerializer() { return new StringRedisSerializer(); } private RedisSerializer<Object> valueSerializer() { // 设置序列化 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>( Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); return jackson2JsonRedisSerializer; //或者使用GenericJackson2JsonRedisSerializer //return new GenericJackson2JsonRedisSerializer(); } }

在自定义序列化过程,GenericJackson2JsonRedisSerializer和Jackson2JsonRedisSerializer大部分时候表现没有区别,实际上若是对象中有LinkedHashMap时候,后者会出错,这个之前坑了我好久,自我怀疑了好久。

建议使用GenericJackson2JsonRedisSerializer来序列化。

GenericJackson2JsonRedisSerializer和Jackson2JsonRedisSerializer都有一个问题,没法反序列化接口的动态代理类,缘由应该是动态代理类没有缺省构造函数,对JPA的自定义结果集支持很差,对Page分页支持很差。

 

4、在service上使用缓存,具体Springboot的Cache注解百度上不少。

@CacheConfig(cacheNames = "user") public interface UserService { @Cacheable(key = "'userName'.concat(#userName)") User findByUserName(String userName); }

 

5、必须修改Shiro的AuthorizingRealm,这里也是最坑的地方

public class MyShiroRealm extends AuthorizingRealm { @Resource @Lazy //就是这里,必须延时加载,根本缘由是bean实例化的顺序上,shiro的bean必需要先实例化,不然@Cacheable注解无效,理论上能够用@Order控制顺序 private UserService userService; //权限信息,包括角色以及权限
 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 略 } /*主要是用来进行身份认证的,也就是说验证用户输入的帐号和密码是否正确。*/ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 略 } }

6、实体中若是有java8time,诸如LocalDateTime,redis缓存反序列化的时候会失败,必须在实体中指定json序列化和反序列化的类@JsonDeserialize和@JsonSerialize

@JsonDeserialize(using = LocalDateTimeDeserializer.class) @JsonSerialize(using = LocalDateTimeSerializer.class) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") //格式化前台页面收到的json时间格式,不指定的话会变成缺省的"yyyy-MM-dd'T'HH:mm:ss"
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime;//建立时间
    @JsonDeserialize(using = LocalDateDeserializer.class) @JsonSerialize(using = LocalDateSerializer.class) @DateTimeFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate expiredDate;//过时日期

 

暂时就是这些关键点和关键坑,记录,否则确定忘记。

相关文章
相关标签/搜索