Spring-Boot整合Redis

微信搜一搜:科技猫,获取第一时间更新

本文源码地址:github.com/jonssonyan/…

事先需要自己部署一个Redis,用于之后测试连接,本文操作Redis使用Spring Data Redis框架

引入依赖

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

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<!-- spring-boot redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.58</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>
复制代码

Spring Boot配置文件 application.properties

# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis数据库索引(默认为0)
#spring.redis.database=
# Redis服务器连接用户名(默认为空)
#spring.redis.username=
# Redis服务器连接密码(默认为空)
#spring.redis.password=
# 连接超时时间(毫秒)
spring.redis.timeout=0
复制代码

Redis配置文件 RedisConfig

@Configuration
@ConditionalOnClass(RedisService.class)
public class RedisConfig {
    private RedisTemplate<String, Object> redisTemplate;

    @Bean
    @ConditionalOnMissingBean
    public RedisService redisService() {
        return new RedisService(redisTemplate);
    }

    @Autowired
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // redis configuration
    // -----------------------------------------------------------------------------------------------------------------

    /**
     * key 的序列化器
     */
    private final StringRedisSerializer keyRedisSerializer = new StringRedisSerializer();

    /**
     * value 的序列化器
     */
    private final RedisFastJsonSerializer<Object> valueRedisSerializer = new RedisFastJsonSerializer<>(Object.class);

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // RedisCacheWriter
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        // RedisCacheConfiguration - 值的序列化方式
        RedisSerializationContext.SerializationPair<Object> serializationPair = RedisSerializationContext.SerializationPair.fromSerializer(valueRedisSerializer);
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(serializationPair);

        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        // 配置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 值序列化-RedisFastJsonSerializer
        redisTemplate.setValueSerializer(valueRedisSerializer);
        redisTemplate.setHashValueSerializer(valueRedisSerializer);
        // 键序列化-StringRedisSerializer
        redisTemplate.setKeySerializer(keyRedisSerializer);
        redisTemplate.setHashKeySerializer(keyRedisSerializer);

        return redisTemplate;
    }
}
复制代码

RedisFastJsonSerializer

RedisFastJsonSerializer 是自定义的序列化和反序列化工具,为了往 Redis 中设值的时候, 自动将对象序列化, 取值的时候自动反序列化

public class RedisFastJsonSerializer<T> implements RedisSerializer<T> {
    // 新建的GenericFastJson2JsonRedisSerializer里面添加白名,防止fastjson 反序列化报错
    static {
        ParserConfig.getGlobalInstance().addAccept("com.springboot");
    }

    private final Class<T> clazz;

    public RedisFastJsonSerializer(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (Objects.isNull(t)) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (Objects.isNull(bytes) || ArrayUtils.isEmpty(bytes)) {
            return null;
        }
        return JSON.parseObject(new String(bytes, StandardCharsets.UTF_8), clazz);
    }
}
复制代码

RedisService

封装一些Redis的常用方法

@Service
public class RedisService {

    private final RedisTemplate<String, Object> redisTemplate;

    public RedisService(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * Description: 设值
     *
     * @param key     缓存 {@link RedisKey}
     * @param value   值
     * @param seconds 有效时长 (秒)
     * @return T 放入缓存中的值
     */
    public <T> T setValue(RedisKey key, T value, long seconds) {
        redisTemplate.opsForValue().set(key.of(), value, seconds, TimeUnit.SECONDS);
        return value;
    }

    private Object getValue(String key) {
        if (!Optional.ofNullable(redisTemplate.hasKey(key)).orElse(Boolean.FALSE)) {
            return null;
        }
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * Description: 取值
     *
     * @param key   缓存 {@link RedisKey}
     * @param clazz 缓存对应的对象的 class 对象
     * @return T or null
     * @see RedisService#getValue(String)
     */
    public <T> T getValue(RedisKey key, Class<T> clazz) {
        return clazz.cast(getValue(key.of()));
    }

    /**
     * Description: 删除
     *
     * @param key 缓存 {@link RedisKey}
     * @return boolean
     */
    public boolean delete(RedisKey key) {
        return Optional.ofNullable(redisTemplate.delete(key.of())).orElse(false);
    }

    /**
     * Description: 延长指定 key 的过期时间
     *
     * @param key     {@link RedisKey}
     * @param seconds 有效时长 (秒)
     * @return boolean
     */
    public boolean expire(RedisKey key, long seconds) {
        return Optional.ofNullable(redisTemplate.expire(key.of(), seconds, TimeUnit.SECONDS)).orElse(false);
    }

    public class Files {

        private static final String CACHE_KEY_PREFIX = "file:";

        private static final String FIELD_FILE_NAME = "fileName";

        private static final String FIELD_FILE_CONTENT = "fileContent";

        /**
         * Description: 缓存文件<br>
         * Details: 将文件对象读入内存, 获取字节数组, 最后 {@code Base64} 编码. 以 缓存前缀 + 文件名 作为缓存 key
         *
         * @param file (Required) 文件对象
         */
        @SneakyThrows
        public void setFile(File file) {
            final HashOperations<String, Object, Object> ops = redisTemplate.opsForHash();

            final String fileName = Objects.requireNonNull(file, "文件不能为空").getName();
            final String fileContent = new String(
                    Base64.getEncoder().encode(IOUtils.toByteArray(FileUtils.openInputStream(Objects.requireNonNull(file, "文件对象不能为空")))),
                    StandardCharsets.UTF_8
            );

            final HashMap<String, String> map = new HashMap<>(2);
            map.put(FIELD_FILE_NAME, fileName);
            map.put(FIELD_FILE_CONTENT, fileContent);
            ops.putAll(CACHE_KEY_PREFIX + fileName, map);
        }

        /**
         * Description: 获取文件
         *
         * @param fileName (Required) 文件名
         * @return java.io.File 文件对象
         */
        @SneakyThrows
        public File getFile(String fileName) {
            final HashOperations<String, Object, Object> ops = redisTemplate.opsForHash();

            // 缓存 Key
            final Map<Object, Object> entries = ops.entries(CACHE_KEY_PREFIX + Objects.requireNonNull(fileName, "文件名不能为空"));
            if (MapUtils.isEmpty(entries)) {
                return null;
            }

            final String cachedFileName = MapUtils.getString(entries, FIELD_FILE_NAME);
            final String cachedFileContent = MapUtils.getString(entries, FIELD_FILE_CONTENT);

            final File file = new File(FileUtils.getTempDirectoryPath() + cachedFileName);
            try (
                    final FileOutputStream out = new FileOutputStream(file);
                    final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out)
            ) {
                bufferedOutputStream.write(Base64.getDecoder().decode(cachedFileContent));
            }
            return file;
        }

        /**
         * Description: 获取文件的字节数组
         *
         * @param fileName (Required) 文件名
         * @return byte[] 文件的字节数组
         */
        public byte[] getBytes(String fileName) {
            final HashOperations<String, Object, Object> ops = redisTemplate.opsForHash();

            final Map<Object, Object> entries = ops.entries(CACHE_KEY_PREFIX + Objects.requireNonNull(fileName, "文件名不能为空"));
            return Base64.getDecoder().decode(MapUtils.getString(entries, FIELD_FILE_CONTENT));
        }
    }
}
复制代码

实体类

User

@Data
public class User implements Serializable {
    private static final long serialVersionUID = -2961686750510451767L;
    private Long id;
    private String name;
    private Integer age;
}
复制代码

RedisKey

@Data
@Builder
public class RedisKey {

    public static final String SEPARATOR = ".";

    /**
     * Redis key 的前缀
     */
    private String prefix;

    /**
     * Redis key 的内容
     */
    private String suffix;

    public String of() {
        return String.format("%s.%s", prefix, suffix);
    }
}
复制代码

ResultVO

视图类,返回json对象

@Data
public class ResultVO<T> {
    private Integer code;
    private String msg;
    private T data;

    public static ResultVO<Object> success(Object object) {
        ResultVO<Object> resultVO = new ResultVO<>();
        resultVO.setCode(1);
        resultVO.setMsg("成功");
        resultVO.setData(object);

        return resultVO;
    }

    public static ResultVO<Object> success() {
        return success(null);
    }

    public static ResultVO<Object> fail(Object object) {
        ResultVO<Object> resultVO = new ResultVO<>();
        resultVO.setCode(0);
        resultVO.setMsg("失败");
        resultVO.setData(object);
        return resultVO;
    }

    public static ResultVO<Object> fail() {
        return fail(null);
    }
}
复制代码

Controller

@RestController
public class Controller {
    @Autowired
    private RedisService redisService;

    @PostMapping("/redis/set")
    public ResultVO<Object> set() {
        User user = new User();
        user.setId(1L);
        user.setName("wang");
        user.setAge(22);
        redisService.setValue(RedisKey.builder().prefix("user").suffix("wang").build(), user, 10000L);
        return ResultVO.success(redisService.getValue(RedisKey.builder().prefix("user").suffix("wang").build(), user.getClass()));
    }
}
复制代码

References

[1] Redis: redis.io/

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享