SpringBoot整合Redis

目录

  • 前言
  • pom引入
  • RedisCacheConfig配置
  • RedisUtil 工具类
  • application.yml配置
  • 用户详情查询测试

项目目录结构

SpringBoot整合Redis_第1张图片

前言

 

关于Redis的解释网上有很多,可以自行查阅,Redis与SpringBoot整合有两种方式,第一种是使用Jedis,它是Redis官方推荐的面向Java的操作Redis的客户端,第二种是使用RedisTemplate,它是SpringDataRedis中对JedisApi的高度封装。我此次使用的是RedisTemplate,并整理了redis工具类方便大家使用,GitHub地址文末给出,需要的话可以留言,留下QQ邮箱号,我会发给你。

POM引入



    org.springframework.boot
    spring-boot-starter-data-redis

RedisCacheConfig配置

自定义序列化器Jackson2JsonRedisSerializer是解决序列号乱码问题

package com.example.demo.config;


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @ClassName: RedisCacheConfig
 * @Description: redis 缓存配置;
 * 注意:RedisCacheConfig这里也可以不用继承:CachingConfigurerSupport,
 * 也就是直接一个普通的Class就好了 这里主要我们之后要重新实现
 * key的生成策略,只要这里修改KeyGenerator,其它位置不用修改就生效了。
 * 普通使用普通类的方式的话,那么在使用@Cacheable的时候还需要指定KeyGenerator的名称;
 * 这样编码的时候比较麻烦。
 * @author: lst
 * @date: 2019年12月25日 下午3:30:19
 */
@Configuration
@EnableCaching // 启用缓存,这个注解很重要;
public class RedisCacheConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    /**
     * 缓存配置初始化一个cacheManager
     * @param connectionFactory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory).build();
        return redisCacheManager;
    }


    /**
     * 防止redis入库序列化乱码的问题
     * @param redisConnectionFactory
     * @return RedisTemplate
     */
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 使用Jackson2JsonRedisSerialize 替换默认序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 设置value的序列化规则和 key的序列化规则
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 重写hashOperations
     * @param redisTemplate
     * @return
     */
    @Bean
    public HashOperations hashOperations(RedisTemplate redisTemplate) {
        return redisTemplate.opsForHash();
    }

    /**
     * 重写listOperations
     * @param redisTemplate
     * @return
     */
    @Bean
    public ListOperations listOperations(RedisTemplate redisTemplate) {
        return redisTemplate.opsForList();
    }

    /**
     * redisMessageListenerContainer
     * @return
     */
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
        return redisMessageListenerContainer;
    }
}

RedisUtil 工具类

package com.example.demo.utils;


import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;


/**
 * @author LST
 * @version 1.0
 * @Description: redis工具类
 * @date 2019-12-25 16:52
 */
@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private HashOperations hashOperations;

    @Autowired
    private ListOperations listOperations;

    /**
     * 默认过期时长,单位:秒/ 三十分钟
     */
    public final static long DEFAULT_EXPIRE = 180 * 10;

    /**
     * 不设置过期时长
     */
    public final static long NOT_EXPIRE = -1;

    /**
     * 普通缓存放入
     * @param key 键
     * @param value 值
     */
    public void setValue(String key, T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 普通缓存放入并设置时间
     * @param key 键
     * @param value 值
     * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
     */
    public void setValue(String key, T value, Long time) {
        setValue(key, value);
        if(time > 0){
            redisTemplate.expire(key, time, TimeUnit.SECONDS);
        }
    }

    /**
     * 普通缓存放入并设置时间和单位
     * @param key 键
     * @param value 值
     * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @param unit 缓存设置的时间单位
     */
    public void setValue(String key, T value, Long time, TimeUnit unit) {
        setValue(key, value);
        redisTemplate.expire(key, time, unit);
    }

    /**
     * 普通缓存获取
     * @param key 键
     * @return 值
     */
    public T getValue(String key) {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        return valueOperations.get(key);
    }

    /**
     * 删除缓存
     * @param key 键
     */
    public void deleteValue(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 判断key是否存在
     * @param key 键
     * @return true 存在  false 不存在
     */
    public boolean exists(String key) {
        if (getValue(key) == null) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 放入一个map对象
     * @param key 键
     * @param map 对象
     * @return true 存在  false 不存在
     */
    public boolean hmset(String key, Map map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * Map缓存获取
     * @param key 键
     * @return map
     */
    public Map hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 重复提交
     * @param key 键
     * @return
     */
    public long repeatSubmit(String key) {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        long ret = valueOperations.increment(key, 1);
        redisTemplate.expire(key, 10L, TimeUnit.SECONDS);
        return ret;
    }

    /**
     * 将list放入缓存
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 删除hash值
     *
     * @param key      key
     * @param hashKeys hashKeys
     */
    public void delHash(String key, String... hashKeys) {
        Arrays.stream(hashKeys).forEach(hashKey -> hashOperations.delete(key, hashKeys));
    }


    /**
     * 先根据key删除
     * 然后在把list放入缓存中
     *
     * @param key                key
     * @param getHashKeyFunction 获取hashKey值的方法
     * @param list               list实体类
     * @param expire 时间
     */
    public  void putHashList(String key, Function getHashKeyFunction, List list, Long expire) {
        putHashList(key, getHashKeyFunction, list);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }

    /**
     * 先根据key删除
     * 然后在把list放入缓存中
     * @param key 键
     * @param getHashKeyFunction
     * @param list
     * @param 
     */
    public  void putHashList(String key, Function getHashKeyFunction, List list) {
        deleteValue(key);
        list.stream().filter(distinctByValue(getHashKeyFunction)).forEach(model -> putHashModel(key, getHashKeyFunction, model));
    }


    /**
     * 将实体类放到Hash里面,并设置时间
     * @param key                key
     * @param getHashKeyFunction 获取hashKey值的方法
     * @param model              实体类
     * @param                 T
     */
    public  void putHashModel(String key, Function getHashKeyFunction, T model, Long expire) {
        putHashModel(key, getHashKeyFunction, model);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }

    /**
     * 将实体类放到Hash里面
     * @param key                key
     * @param getHashKeyFunction 获取hashKey值的方法
     * @param model              实体类
     * @param                 T
     */
    public  void putHashModel(String key, Function getHashKeyFunction, T model) {
        hashOperations.put(key, getHashKeyFunction.apply(model), JSONObject.toJSON(model).toString());
    }


    /**
     * 根据有效时间,key 获取List
     *
     * @param key   key
     * @param clazz clazz
     * @param    T
     * @return List
     */
    public  List getHashList(String key, Class clazz, Long expire) {
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
        return getHashList(key, clazz);
    }

    /**
     * 获取全部list
     * @param key
     * @param clazz
     * @param 
     * @return
     */
    public  List getHashList(String key, Class clazz) {
        Optional> objectList = Optional.ofNullable(hashOperations.values(key));
        return objectList.map(objects -> objects.stream()
                .map(t -> JSONObject.parseObject(JSONObject.toJSON(t).toString(), clazz))
                .collect(Collectors.toList())).orElse(null);
    }


    /**
     * 根据 key 和 hashKey 获取值
     *
     * @param key     key
     * @param hashKey hashKey
     * @param clazz   clazz
     * @param      T
     * @return T
     */
    public  T getHashObject(String key, String hashKey, Class clazz) {
        Optional object = Optional.ofNullable(hashOperations.get(key, hashKey));
        if (object.isPresent()) {
            return JSONObject.parseObject(JSONObject.toJSON(object).toString(), clazz);
        }
        return null;
    }

    /**
     * 去除重复
     * @param keyExtractor
     * @param 
     * @return
     */
    public static  Predicate distinctByValue(Function keyExtractor) {
        ConcurrentHashMap map = new ConcurrentHashMap<>();
        return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }


    /**
     * 判断key是否存在
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            return false;
        }
    }


    /**
     * 获取有效全部list
     * @param key    key
     * @param clazz  clazz
     * @param     T
     * @param expire 超时时间
     * @return return
     */
    public  List getList(String key, Class clazz, Long expire) {
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
        return getList(key, clazz);
    }

    /**
     * 获取全部list
     * @param key
     * @param clazz
     * @param 
     * @return
     */
    public  List getList(String key, Class clazz) {
        Optional> list = Optional.ofNullable(listOperations.range(key, 0, listOperations.size(key)));
        return list.map(objects -> objects.stream()
                .map(t -> JSONObject.parseObject(JSONObject.toJSON(t).toString(), clazz))
                .collect(Collectors.toList())).orElse(null);
    }

    /**
     * 先根据key删除
     * 然后在把list放入缓存中
     * @param key              键
     * @param getValueFunction 获取value值的方法
     * @param list             list
     * @param               T
     * @param expire           超时时间
     */
    public  void leftPushList(String key, List list, Function getValueFunction, Long expire) {
        leftPushList(key, list, getValueFunction);
        if (expire != NOT_EXPIRE) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }

    /**
     *实体类去重放入listOperations
     * @param key
     * @param list
     * @param getValueFunction 获取value值的方法
     * @param 
     */
    public  void leftPushList(String key, List list, Function getValueFunction) {
        deleteValue(key);
        list.stream().filter(distinctByValue(getValueFunction)).forEach(model -> leftPushModel(key, model, getValueFunction));
    }

    /**
     * 实体类放入
     * @param key 键
     * @param model
     * @param getValueFunction
     * @param 
     */
    public  void leftPushModel(String key, T model, Function getValueFunction) {
        listOperations.leftPush(key, getValueFunction.apply(model));
    }
}
 
  

application.yml配置

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: root1234
    # 使用Druid数据源
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    druid:
      filters: stat
      maxActive: 20
      initialSize: 1
      maxWait: 60000
      minIdle: 1
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: select 'x'
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true
      maxOpenPreparedStatements: 20

  data:
    redis:
      repositories:
        enabled: false
  redis:
    database: 0   # redis数据库索引(默认为0),我们使用索引为其他(0-15)的数据库,避免和其他数 据库冲突
    host: 127.0.0.1
    port: 6379
    password: 12345678

 

用户详情查询测试

UserController类
/**
     * 获取用户详情
     * @param userId 用户id
     * @return
     */
    @GetMapping(value = "/{userId}", produces = "application/json; charset=utf-8")
    @ApiOperation(value = "获取用户详情", notes = "获取用户详情", code = 200, produces = "application/json")
    public RestResponse> getUser(@PathVariable("userId") String userId) {
        return ResultGenerator.genSuccessResult(userService.getUser(userId));
    }
UserServiceImpl实现类
 /**
     * 获取用户详情
     * @param userId 用户id
     * @return
     */
    @Override
    public User getUser(String userId) {
        //先查询redis缓存
        User user = (User) redisUtil.getValue(userId);
        if(user == null){
            user = userMapper.selectOne(new QueryWrapper().lambda().eq(User::getId, userId));
            if(user == null){
                throw new SXException(ServiceExceptionEnum.DATA_NOT_REQUESTED);
            }
            //放入缓存中
            redisUtil.setValue(userId, user);
        }
        return user;
    }

每次查询会先查询redis里面有没有,没有的话,就查询数据库,然后放入redis缓存中,以后查询就直接查询redis中即可。

第一次查询:

SpringBoot整合Redis_第2张图片

第二次查询:

SpringBoot整合Redis_第3张图片

 

因为整合的其实不复杂,只要把本文章的RedisCacheConfig和RedisUtil拷贝进自己的项目可以直接使用。或者需要源码的小伙伴可直接留言。

 

 

你可能感兴趣的:(redis,springboot,redis)