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

前提:

1、SpringBoot+shiro已经集成完毕,如果没有集成,先查阅之前的Springboot2.0 集成shiro权限管理

2、redis已经安装完成

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

4、json使用springboot默认的

一、依赖

        <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>

连接池:

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

必须注销:

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

二、Application.yml


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

三、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分页支持不好。

四、在service上使用缓存,具体Springboot的Cache注解百度上很多。

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

五、必须修改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 {

} }

六、实体中如果有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;//过期日期

暂时就是这些关键点和关键坑,记录,不然肯定忘记。

Springboot2.x+shiro+redis(Lettuce)整合填坑的更多相关文章

  1. springboot+shiro+redis项目整合

    介绍: Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最 ...

  2. spring boot shiro redis整合基于角色和权限的安全管理-Java编程

    一.概述 本博客主要讲解spring boot整合Apache的shiro框架,实现基于角色的安全访问控制或者基于权限的访问安全控制,其中还使用到分布式缓存redis进行用户认证信息的缓存,减少数据库 ...

  3. springboot+shiro+redis(集群redis版)整合教程

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3.springboot+shiro+redis(单机red ...

  4. springboot+shiro+redis(单机redis版)整合教程

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(集群redis版)整合教程 3.springboot+shiro+redis(单机red ...

  5. SpringBoot2.0+Shiro+JWT 整合

    SpringBoot2.0+Shiro+JWT 整合 JSON Web Token(JWT)是一个非常轻巧的规范.这个规范允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息. 我们利用一定的编 ...

  6. springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3. springboot+shiro+redis(集群re ...

  7. .Net Core Web Api实践(四)填坑连接Redis时Timeout performing EVAL

    前言:前两篇文章.net core+Redis+IIS+nginx实现Session共享中,介绍了使用Microsoft.Extensions.Caching.Redis实现Session共享的方法, ...

  8. Springboot2.x集成Redis集群模式

    Springboot2.x集成Redis集群模式 说明 Redis集群模式是Redis高可用方案的一种实现方式,通过集群模式可以实现Redis数据多处存储,以及自动的故障转移.如果想了解更多集群模式的 ...

  9. Springboot2.x集成Redis哨兵模式

    Springboot2.x集成Redis哨兵模式 说明 Redis哨兵模式是Redis高可用方案的一种实现方式,通过哨兵来自动实现故障转移,从而保证高可用. 准备条件 pom.xml中引入相关jar ...

随机推荐

  1. c/c++链表的实现

    #include<iostream> #include<string> #define SIZE 3 using std::cout; using std::endl; usi ...

  2. Java:泛型擦除

    https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

  3. 「专题训练」Air Raid(HDU-1151)

    题目 在一个城市里有\(n\)个地点和\(k\)条道路,道路是无环的(也就是说一定可以二分染色--回路长度为偶数0),现在伞兵需要去n个地点视察,只能沿着路的方向走,问最少需要多少伞兵. 分析 这是什 ...

  4. AirtestIDE实践二:Poco框架试用

    上一篇用airtest框架做了一个梦幻西游手游的DEMO,这次看看poco的强大之处.首先安装poco:pip install pocoui 其次,把SDK集成到你家游戏中,我这直接用官网提供的一个U ...

  5. 【CentOS】下安装RabbitMQ教程

    系统版本: 安装依赖: 由于RabbitMQ依赖Erlang, 所以需要先安装Erlang. Erlang的安装方式大概有两种: (1) Erlang Solution安装(推荐) wget http ...

  6. 【转】: 探索Lua5.2内部实现:虚拟机指令(1) 概述

    Lua一直把虚拟机执行代码的效率作为一个非常重要的设计目标.而采用什么样的指令系统的对于虚拟机的执行效率来说至关重要. Stack based vs Register based VM 根据指令获取操 ...

  7. 创建https证书

    第一个里程碑:创建https证书 创建文件认证目录 mkdir /application/nginx/key/ -p 在认证目录下创建认证文件 openssl req -new -x509 -node ...

  8. SGU 438 The Glorious Karlutka River =)(最大流)

    Description A group of Mtourists are walking along the Karlutka river. They want to cross the river, ...

  9. VUE中组件的使用

    关于vue组件引用 使用Nodejs的方法 被引用的组件要暴露 module.exports={}; 引用时 用 var abc= require("组件的路径") 然后 就可以用 ...

  10. Graph Theory

    Description Little Q loves playing with different kinds of graphs very much. One day he thought abou ...