通过封装规范redis的使用

2024-01-20 15:32 孙水迪 589

1.问题引入

在java里使用redis非常简单,只需要引入依赖后生成一个RedisTemplate对象即可,然后就可以在其他类里调用对应的put,get,delete方法对redis进行操作

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
@Configuration
public class RedisConfig {
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory();
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory());
        return template;
    }
}
@Autowired
private RedisTemplate<String, Object> redisTemplate;

public void saveData(String key, Object value) {
    redisTemplate.opsForValue().set(key, value);
}

public Object getData(String key) {
    redisTemplate.opsForValue().get(key);
}

public void deleteData(String key) {
    redisTemplate.delete(key);
}

但是这样子也出现了一个问题,没法规范redis的使用

redis存储了键值对,key一般是string类型的,但是会有多个参数进行格式化;value的类型更是多种多样的

如果没有统一的配置,key的格式化错误会导致无法get到put的值;而如果在put的时候上传了A类型,在get的时候转换为B类型,则会出现报错的情况

即使没有出现报错,也不利于后续维护

2.解决方法

对redis的操作进行二次封装是一个不错的解决方法

首先创建一个类定义redis的键值对,里面定义了key的格式化模板,redis的过期时间,备注,使用泛型则支持在实例化时对value的class进行指定

@Data
public class RedisKeyDefine<T> {

    /**
     * Key 模板
     */
    private final String keyTemplate;
    /**
     * 过期时间
     */
    private final Duration timeout;
    /**
     * 备注
     */
    private final String memo;


    RedisKeyDefine(String memo, String keyTemplate, Duration timeout) {
        this.memo = memo;
        this.keyTemplate = keyTemplate;
        this.timeout = timeout;
    }

    /**
     * 格式化 Key
     * <p>
     * 注意,内部采用 {@link String#format(String, Object...)} 实现
     *
     * @param args 格式化的参数
     * @return Key
     */
    public String formatKey(Object... args) {
        return String.format(keyTemplate, args);
    }

}

然后在常量类里定义各种不同的redis键值对,在该类里,redis的键值对信息一目了然

public class RedisKeyConstants {
    public static final RedisKeyDefine<AccessTokenInfoDO> OAUTH2_ACCESS_TOKEN =
            new RedisKeyDefine<>("访问令牌的缓存",
                    "oauth2_access_token:%s",
                    Duration.ofHours(8));
    public static final RedisKeyDefine<ThirdUserDetail> THIRD_USER_DETAIL =
            new RedisKeyDefine<>("三方用户信息",
                    "third_user_detail:%s",
                    Duration.ofHours(1));
}
然后封装一个redistemplate进行get,put,delete操作

然后封装一个redistemplate进行get,put,delete操作

@Component
@Log4j2
public class ObjectRedisTemplate {
    private final RedisTemplate<String, Object> redisTemplate;

    @Autowired
    public ObjectRedisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        template.setValueSerializer(RedisSerializer.json());
        template.setHashValueSerializer(RedisSerializer.json());
        template.afterPropertiesSet();
        this.redisTemplate = template;
    }

    public <T> T get(RedisKeyDefine<T> define, String key) {
        ValueOperations<String, T> redis = (ValueOperations<String, T>) redisTemplate.opsForValue();
        return redis.get(define.formatKey(key));
    }

    public <T> void put(RedisKeyDefine<T> define, String key, T value) {
        ValueOperations<String, T> redis = (ValueOperations<String, T>) redisTemplate.opsForValue();
        redis.set(define.formatKey(key), value, define.getTimeout());
    }

    public <T> void delete(RedisKeyDefine<T> define, String key) {
        redisTemplate.delete(define.formatKey(key));
    }


}

3.使用示例

使用方法也很简单,注入ObjectRedisTemplate后,执行put,get,delete方法即可,额外增加的RedisKeyConstants使得在操作时无需花费精力去关注redis里存储的格式,减少了出错可能

@Autowired
private ObjectRedisTemplate redisTemplate;
//上传
AccessTokenInfoDO accessTokenDO = getAccessTokenInfo(tokenDO);
redisTemplate.put(RedisKeyConstants.OAUTH2_ACCESS_TOKEN, accessToken, accessTokenDO);
//下载
AccessTokenInfoDO accessTokenDO = redisTemplate.get(RedisKeyConstants.OAUTH2_ACCESS_TOKEN, accessToken);
//删除
redisTemplate.delete(RedisKeyConstants.OAUTH2_ACCESS_TOKEN, accessToken);