Redis拾遗(七)——基于springboot操作set等数据类型

前言

在总结Redis拾遗(六) 的时候我们从头到尾搭建了一个项目,大量篇幅耗费在了搭建基础代码层面,对基础的数据类型操作并没有总结完成,本篇博客继续梳理

Set类型

关于set类型的操作,先给出基本的操作,之后列出一个简单的业务场景,在上一篇博客的基本项目中完成这些操作

基本的API操作

/**
 * autor:liman
 * createtime:2020/7/27
 * comment:
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringBootRedisApplication.class)
@Slf4j
public class SetRedisTest {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testSetRedis(){
        log.info("======开始测试set集合======");
        final String keyOne = "SpringBootRedis:Set:10010";
        final String keyTwo = "SpringBootRedis:Set:10011";

        redisTemplate.delete(keyOne);
        redisTemplate.delete(keyTwo);

        SetOperations<String,String> setOperations = redisTemplate.opsForSet();
        setOperations.add(keyOne,new String[]{"a","b","c"});
        setOperations.add(keyTwo,new String[]{"b","e","f"});

        log.info("---集合keyOne的元素:{}", setOperations.members(keyOne));
        log.info("---集合keyTwo的元素:{}", setOperations.members(keyTwo));

        log.info("---集合keyOne随机取1个元素:{}", setOperations.randomMember(keyOne));
        log.info("---集合keyOne随机取n个元素:{}", setOperations.randomMembers(keyOne, 2L));

        log.info("---集合keyOne元素个数:{}", setOperations.size(keyOne));
        log.info("---集合keyTwo元素个数:{}", setOperations.size(keyTwo));

        log.info("---元素a是否为集合keyOne的元素:{}", setOperations.isMember(keyOne, "a"));
        log.info("---元素f是否为集合keyOne的元素:{}", setOperations.isMember(keyOne, "f"));

        log.info("---集合keyOne和集合keyTwo的差集元素:{}", setOperations.difference(keyOne, keyTwo));
        log.info("---集合keyOne和集合keyTwo的交集元素:{}", setOperations.intersect(keyOne, keyTwo));
        log.info("---集合keyOne和集合keyTwo的并集元素:{}", setOperations.union(keyOne, keyTwo));

        log.info("---从集合keyOne中弹出一个随机的元素:{}", setOperations.pop(keyOne));
        log.info("---集合keyOne的元素:{}", setOperations.members(keyOne));
        log.info("---将c从集合keyOne的元素列表中移除:{}", setOperations.remove(keyOne, "c"));
    }
}

两个简单的业务场景

防止用户重复注册

在正常的系统中,为了防止用户重复注册,我们通常会遇到一个邮箱是否已经注册的需求,这里就来模拟一下这个业务场景。

1、针对Redis的操作

/**
 * autor:liman
 * createtime:2020/7/29
 * comment:redis操作set的service
 * 需要说明的是,在获取operation类型的时候,可以通过泛型指定具体的操作类型,如下所示:
 * SetOperations setOperations = redisTemplate.opsForSet();
 */
@Slf4j
@Service
public class SetRedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 缓存中设置user的email
     * @param user
     */
    public void setUserEmail(User user){
        SetOperations<String,String> setOperations = redisTemplate.opsForSet();
        setOperations.add(RedisKeyConstants.RedisSetKey+"_"+user.getId(),user.getEmail());
    }

    /**
     * 判断对应的用户邮箱是否存在
     * 通过isMemeber判断
     * @param user
     * @return
     */
    public boolean isUserExistEmail(User user){
        SetOperations<String,String> setOperations = redisTemplate.opsForSet();
        Boolean isExist = setOperations.isMember(RedisKeyConstants.RedisSetKey+"_"+user.getId(), user.getEmail());
        return isExist;
    }

    /**
     * 取出缓存中用户的邮箱
     * @param userId
     * @return
     * @throws Exception
     */
    public Set<String> getEmails(int userId) throws Exception{
        return redisTemplate.opsForSet().members(RedisKeyConstants.RedisSetKey+"_"+userId);
    }

}

2、与业务相关的处理类

/**
 * autor:liman
 * createtime:2020/7/29
 * comment:以用户注册为实例场景,操作set集合的业务类
 */
@Slf4j
@Service
public class SetService {

    @Autowired
    private SetRedisService setRedisService;

    @Autowired
    private UserMapper userMapper;

    /**
     * 注册用户
     * @param user
     * @return
     * 加入事务控制,如果Redis缓存中判断用户存在则直接抛出异常,如果不存在,则可以新增用户,如果用户新增成功,则将邮箱信息存入缓存。
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer registerUser(User user){
        if(this.exist(user)){
            throw new RuntimeException(StatusCode.UserEmailHasExist.getMsg());
        }
        int res = userMapper.insertSelective(user);
        if(res>0){
            setRedisService.setUserEmail(user);
        }
        return user.getId();
    }

    /**
     * 判断user的email是否存在
     * 如果通过缓存判断存在则直接返回true
     * 如果缓存判断不存在,则从数据库中获取用户邮箱信息,然后存入缓存。
     * @param user
     * @return
     */
    private Boolean exist(final User  user){
        boolean isExist = setRedisService.isUserExistEmail(user);
        if(isExist){
            return true;
        }else{
            User newUser = userMapper.selectByEmail(user.getEmail());
            if(null!=newUser){
                setRedisService.setUserEmail(newUser);
                return true;
            }else{
                return false;
            }
        }
    }
    
    /**
     * 获取缓存中用户的邮箱信息
     * @param userId
     * @return
     */
    public Set<String> getEmails(int userId){
        Set<String> emails = new HashSet<>();
        try {
            emails = setRedisService.getEmails(userId);
        } catch (Exception e) {
            log.error("获取用户注册邮箱异常,异常信息为:{}",e);
        }
        return emails;
    }
}

3、Controller类

/**
 * autor:liman
 * createtime:2020/7/29
 * comment:
 */
@RestController
@Slf4j
@RequestMapping("set")
public class SetController {

    @Autowired
    private SetService setService;

    @Autowired
    private ProblemService problemService;

    //对标用户注册的请求,新增用户
    @RequestMapping(value="put",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
    public BaseResponse put(@RequestBody @Validated User user, BindingResult bindResult){
        String checkRes=ValidatorUtil.checkResult(bindResult);
        if (StrUtil.isNotBlank(checkRes)){
            return new BaseResponse(StatusCode.Fail.getCode(),checkRes);
        }
        BaseResponse response = new BaseResponse(StatusCode.Success);
        try{
            log.info("-----用户注册信息:{}-----",user);
            response.setData(setService.registerUser(user));
        }catch (Exception e){
            log.error("用户注册出现异常,异常信息为:{}",e);
            response = new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }

    //对标获取用户信息
    @RequestMapping(value="get",method=RequestMethod.GET)
    public BaseResponse get(@RequestParam("userId") int userId){
        BaseResponse response = new BaseResponse(StatusCode.Success);
        try{
            response.setData(setService.getEmails(userId));
        }catch (Exception e){
            response = new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }
}

随机的问卷问题

在某些场景,会给客户随机发放几个简单的问卷问题,而且不同用户在同一时间收到的问题不同,同一用户在不同时间收到的问题也不同。下面会根据RedisTemplate来实现该场景

1、问卷业务处理类

/**
 * autor:liman
 * createtime:2020/7/30
 * comment:验证的问题业务逻辑类
 */
@Service
@Slf4j
public class ProblemService {

    @Autowired
    private ProblemMapper problemMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
    启动的时候,spring加载该类的时候,完成问题的加载,存入缓存
    */
    @PostConstruct
    public void init(){
        initDBToRedisCache();
    }

    /**
    从数据库中读取问卷问题,并将问题存入缓存
    */
    private void initDBToRedisCache(){
        try{
            SetOperations<String,Problem> setOperations = redisTemplate.opsForSet();
            Set<Problem> problemSet = problemMapper.getAll();
            if(problemSet!=null && !problemSet.isEmpty()){
                problemSet.forEach(problem -> setOperations.add(RedisKeyConstants.RedisSetProblemsKey,problem));
            }
        }catch (Exception e){
            log.error("项目启动拉取出数据库中的问题库,并塞入缓存Set集合中-发生异常:",e.fillInStackTrace());
        }
    }

    /**
     * 随机获取一个问题
     * @return
     */
    public Problem getRandomProblemEntity(){
        Problem problem = null;
        try{
            SetOperations<String,Problem> setOperations = redisTemplate.opsForSet();
            Long size = setOperations.size(RedisKeyConstants.RedisSetProblemsKey);
            if(size>0){
                problem = setOperations.pop(RedisKeyConstants.RedisSetProblemsKey);
            }else{
                this.initDBToRedisCache();
                problem = setOperations.pop(RedisKeyConstants.RedisSetProblemsKey);
            }
        }catch (Exception e){
            log.error("从缓存中获取随机的问题-发生异常:",e.fillInStackTrace());
        }
        return problem;
    }
    
	/**
     * 从缓存中获取随机的乱序试题
     * 所有的均会被返回,只是顺序会自动随机
     * @param total
     * @return
     */
    public Set<Problem> getRandomEntitys(Integer total){
        Set<Problem> problems=Sets.newHashSet();
        try {
            SetOperations<String,Problem> setOperations=redisTemplate.opsForSet();
            problems=setOperations.distinctRandomMembers(RedisKeyConstants.RedisSetProblemsKey,total);

        }catch (Exception e){
            log.error("从缓存中获取随机的、乱序的试题列表-发生异常:",e.fillInStackTrace());
        }
        return problems;
    }
}

2、问题业务的controller

/**
 * autor:liman
 * createtime:2020/8/2
 * comment:
 */
@Slf4j
@RestController
@RequestMapping("problem")
public class ProblemController {

    @Autowired
    private ProblemService problemService;

    @RequestMapping(value="get",method=RequestMethod.GET)
    public BaseResponse get(){
        BaseResponse response = new BaseResponse(StatusCode.Success);
        try{
            response.setData(problemService.getRandomProblemEntity());
        }catch (Exception e){
            response = new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }
}

ZSet类型

基本API操作

这个比较简单直接上代码吧

/**
 * autor:liman
 * createtime:2020/7/31
 * comment:ZSet的测试类
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringBootRedisApplication.class)
@Slf4j
public class ZSetRedisTest {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testZSetRedis(){
        log.info("------开始有序集合SortedSet的测试-----");
        final String key = "SpringBootRedis:SortedSet:10010";
        redisTemplate.delete(key);//清空
        ZSetOperations<String,String> zSetOperations = redisTemplate.opsForZSet();
        zSetOperations.add(key,"a",8.0);
        zSetOperations.add(key,"b",2.0);
        zSetOperations.add(key,"c",4.0);
        zSetOperations.add(key,"d",6.0);
        log.info("---有序集合SortedSet-成员数:{}",zSetOperations.size(key));
        log.info("---有序集合SortedSet-按照分数正序:{}",zSetOperations.range(key,0L,zSetOperations.size(key)));
        log.info("---有序集合SortedSet-按照分数倒序:{}",zSetOperations.reverseRange(key,0L,zSetOperations.size(key)));
        log.info("---有序集合SortedSet-获取成员a的得分:{}",zSetOperations.score(key,"a"));
        log.info("---有序集合SortedSet-获取成员c的得分:{}",zSetOperations.score(key,"c"));

        log.info("---有序集合SortedSet-正序中c的排名:{} 名",zSetOperations.rank(key,"c")+1);
        log.info("---有序集合SortedSet-倒序中c的排名:{} 名",zSetOperations.reverseRank(key,"c"));

        zSetOperations.incrementScore(key,"b",10.0);
        log.info("---有序集合SortedSet-按照分数倒序:{}",zSetOperations.reverseRange(key,0L,zSetOperations.size(key)));

        zSetOperations.remove(key,"b");
        log.info("---有序集合SortedSet-按照分数倒序:{}",zSetOperations.reverseRange(key,0L,zSetOperations.size(key)));

        log.info("---有序集合SortedSet-取出分数区间的成员:{}",zSetOperations.rangeByScore(key,0,7));

        log.info("---有序集合SortedSet-取出带分数的排好序的成员:");
        Set<ZSetOperations.TypedTuple<String>> set=zSetOperations.rangeWithScores(key,0L,zSetOperations.size(key));
        set.forEach(tuple -> log.info("--当前成员:{} 对应的分数:{}",tuple.getValue(),tuple.getScore()));
    }

}

一个简单的业务场景

这里以充话费排行榜来进行实例演练,并要求完成根据所充话费多少可以进行排序

1、ZSet操作的通用service

/**
 * autor:liman
 * createtime:2020/8/2
 * comment:针对zset的操作
 */
@Service
@Slf4j
public class ZSetRedisService<T> {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 通用的,往zset中就增加元素
     * @param key
     * @param obj
     * @param score
     */
    public void addElement(String key,Object obj,Double score){
        ZSetOperations<String,Object> zSetOperations = redisTemplate.opsForZSet();
        zSetOperations.add(key,obj,score);
    }

    /**
     * 将所有的列表排序,升序或者倒序
     * @param key
     * @param isAsc
     * @return
     */
    public Set<T> getSortedList(final String key,final boolean isAsc){
        ZSetOperations<String,T> zSetOperations = redisTemplate.opsForZSet();
        Long allSize = zSetOperations.size(key);
        return isAsc ? zSetOperations.range(key,0L,allSize) : zSetOperations.reverseRange(key,0L,allSize);
    }
    
	/**
     * 获取对应对象的分数
     * @param key
     * @param obj
     * @return
     */
    public double getScore(final String key,T obj){
        try{
            ZSetOperations<String,T> zSetOperations = redisTemplate.opsForZSet();
            return Optional.ofNullable(zSetOperations.score(key,obj)).orElse(0.0D);
        }catch (Exception e){
            log.error("异常:{}",e);
            return 0.0D;
        }

    }

    /**
     * 获取更新后的排行榜
     * @param key
     * @param isAsc
     * @return
     */
    public Set<ZSetOperations.TypedTuple<T>> getUpdateSortedList(final String key,final boolean isAsc){
        ZSetOperations<String,T> zSetOperations=redisTemplate.opsForZSet();
        final Long size=zSetOperations.size(key);
        return zSetOperations.reverseRangeWithScores(key,0L,size);
    }
}

2、操作Redis的业务类,完成手机话费的充值

/**
 * autor:liman
 * createtime:2020/8/2
 * comment:手机话费的充值的业务类
 */
@Slf4j
@Service
public class ZSetService {

    @Autowired
    private ZSetRedisService<PhoneFare> zSetRedisService;
    
    @Autowired
    private ZSetRedisService<String> zSetUpdateRedisService;

    @Autowired
    private PhoneFareMapper fareMapper;


    /**
     * 新增手机话费充值记录
     * @param fare
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer addRecord(PhoneFare fare) throws Exception{
        log.info("-----sorted set话费充值记录新增:{}----- ",fare);

        int res=fareMapper.insertSelective(fare);
        if (res>0){
            zSetRedisService.addElement(RedisKeyConstants.RedisSortedSetKeyOne,fare,fare.getFare().doubleValue());
        }
        return fare.getId();
    }

    /**
     * 获取充值排行榜
     * @param isAsc
     * @return
     */
    public Set<PhoneFare> getSortFares(final Boolean isAsc){
        return zSetRedisService.getSortedList(RedisKeyConstants.RedisSortedSetKeyOne, Optional.ofNullable(isAsc).orElse(true));
    }
    
    /**
     * 新增排序记录
     * @param fare
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer addRecordUpdate(PhoneFare fare) throws Exception{
        log.info("-----sorted set 话费充值新增记录[更新]:{}-----",fare);
        int res = fareMapper.insertSelective(fare);
        if(res>0){
            //这里为了累加排序,这里引入一个新的zSetUpdateRedisService
            double score = zSetUpdateRedisService.getScore(RedisKeyConstants.RedisSortedSetKey2, fare.getPhone());
            log.info("===score:{}===",score);
            if(score>0){//如果手机号已经充值过了,则直接加金额即可
                zSetUpdateRedisService.incrementScore(RedisKeyConstants.RedisSortedSetKey2,fare.getPhone(),fare.getFare().doubleValue());
            }else{
                zSetUpdateRedisService.addElement(RedisKeyConstants.RedisSortedSetKey2,fare.getPhone(),fare.getFare().doubleValue());
            }
        }
        return fare.getId();
    }

    /**
     * 升级版的获取用户充值排序记录
     * @return
     */
    public List<PhoneFare> getSortFaresUpdate(){
        List<PhoneFare> result = Lists.newLinkedList();

        Set<ZSetOperations.TypedTuple<String>> scoreSet
                = zSetUpdateRedisService.getUpdateSortedList(RedisKeyConstants.RedisSortedSetKey2, true);

        if(null!=scoreSet && !scoreSet.isEmpty()){
            scoreSet.forEach(
                    t->{
                        PhoneFare fare = new PhoneFare();
                        fare.setFare(BigDecimal.valueOf(t.getScore()));
                        fare.setPhone(t.getValue());
                        result.add(fare);
                    }
            );
        }
        return result;
    }
}

3、controller入口类

/**
 * autor:liman
 * createtime:2020/8/2
 * comment:
 */
@RestController
@Slf4j
@RequestMapping("/zset")
public class ZSetController {

    @Autowired
    private ZSetService zSetService;
	
    //新增充话费的记录
    @RequestMapping(value = "put",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
    public BaseResponse put(@RequestBody @Validated PhoneFare fare, BindingResult result){
        String checkRes= ValidatorUtil.checkResult(result);
        if (StrUtil.isNotBlank(checkRes)){
            return new BaseResponse(StatusCode.Fail.getCode(),checkRes);
        }
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            response.setData(zSetService.addRecord(fare));

        }catch (Exception e){
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }

    @RequestMapping(value = "get",method = RequestMethod.GET)
    public BaseResponse get(){
        BaseResponse response=new BaseResponse(StatusCode.Success);
        Map<String,Object> resMap=Maps.newHashMap();
        try {
            //这里为了测试,将正序倒序都输出
            resMap.put("SortFaresASC",zSetService.getSortFares(true));
            resMap.put("SortFaresDESC",zSetService.getSortFares(false));

        }catch (Exception e) {
            response = new BaseResponse(StatusCode.Fail.getCode(), e.getMessage());
        }
        response.setData(resMap);
        return response;
    }
    
        @RequestMapping(value = "putUpdate",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
    public BaseResponse putUpdate(@RequestBody @Validated PhoneFare fare, BindingResult result){
        String checkRes= ValidatorUtil.checkResult(result);
        if (StrUtil.isNotBlank(checkRes)){
            return new BaseResponse(StatusCode.Fail.getCode(),checkRes);
        }
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
           response.setData(zSetService.addRecordUpdate(fare));

        }catch (Exception e){
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }

    @RequestMapping(value = "getUpdate",method = RequestMethod.GET)
    public BaseResponse getUpdate(){
        BaseResponse response=new BaseResponse(StatusCode.Success);
        Map<String,Object> resMap=Maps.newHashMap();
        try {
            resMap.put("sortList",zSetService.getSortFaresUpdate());

        }catch (Exception e) {
            response = new BaseResponse(StatusCode.Fail.getCode(), e.getMessage());
        }
        response.setData(resMap);
        return response;
    }
}

Hash类型

简单API操作

直接上代码吧

/**
 * autor:liman
 * createtime:2020/8/2
 * comment:hash数据类型的基本操作
 */
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringBootRedisApplication.class)
public class HashRedisTest {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void method5() {
        log.info("----开始哈希Hash测试");

        final String key = "SpringBootRedis:Hash:Key:v1";
        redisTemplate.delete(key);

        HashOperations<String,String,String> hashOperations=redisTemplate.opsForHash();
        hashOperations.put(key,"10010","zhangsan");
        hashOperations.put(key,"10011","lisi");

        Map<String,String> dataMap= Maps.newHashMap();
        dataMap.put("10012","wangwu");
        dataMap.put("10013","zhaoliu");
        hashOperations.putAll(key,dataMap);

        log.info("---哈希hash-获取列表元素: {} ",hashOperations.entries(key));
        log.info("---哈希hash-获取10012的元素: {} ",hashOperations.get(key,"10012"));
        log.info("---哈希hash-获取所有元素的field列表: {} ",hashOperations.keys(key));

        log.info("---哈希hash-10013成员是否存在: {} ",hashOperations.hasKey(key,"10013"));
        log.info("---哈希hash-10014成员是否存在: {} ",hashOperations.hasKey(key,"10014"));

        hashOperations.putIfAbsent(key,"10020","sunwukong");
        log.info("---哈希hash-获取列表元素: {} ",hashOperations.entries(key));

        log.info("---哈希hash-删除元素10010 10011: {} ",hashOperations.delete(key,"10010","10011"));
        log.info("---哈希hash-获取列表元素: {} ",hashOperations.entries(key));

        log.info("---哈希hash-获取列表元素个数: {} ",hashOperations.size(key));
    }
}

一个简单的业务场景

在有些系统中,会有预加载的配置信息,这些配置信息就可以通过hash的数据类型来操作

1、针对Redis的操作

/**
 * autor:liman
 * createtime:2020/8/2
 * comment:Hash针对Redis的操作
 */
@Slf4j
@Service
public class HashRedisService<T> {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 实时获取所有有效的数据字典列表-转化为map-存入hash缓存中
     *
     * @param key
     * @param dataMap
     */
    @Async
    public void cacheConfigMap(final String key, Map<String, List<T>> dataMap) {
        try {
            HashOperations<String, String, List<T>> hashOperations = redisTemplate.opsForHash();
            hashOperations.putAll(RedisKeyConstants.RedisHashKeyConfig, dataMap);
        } catch (Exception e) {
            log.error("实时获取所有有效的数据字典列表-转化为map-存入hash缓存中-发生异常:", e.fillInStackTrace());
        }
    }

    /**
     * 从缓存hash中获取所有的数据字典配置map
     *
     * @return
     */
    public Map<String, List<T>> getAllCacheConfigInfo(final String hashKey) {
        Map<String, List<T>> result = Maps.newHashMap();
        try {
            HashOperations<String, String, List<T>> hashOperations = redisTemplate.opsForHash();
            result = hashOperations.entries(hashKey);
        } catch (Exception e) {
            log.error("从缓存hash中获取所有的数据字典配置map-发生异常:", e.fillInStackTrace());
        }
        return result;
    }

    /**
     * 从缓存hash中获取特定的数据字典列表
     *
     * @param hashEntityKey
     * @return
     */
    public List<T> getAllConfigInfoByType(final String hashKey,final String hashEntityKey) {
        List<T> result = Lists.newLinkedList();
        try {
            HashOperations<String, String, List<T>> hashOperations = redisTemplate.opsForHash();
            result = hashOperations.get(hashKey, hashEntityKey);
        } catch (Exception e) {
            log.error("从缓存hash中获取特定的数据字典列表-发生异常:", e.fillInStackTrace());
        }
        return result;
    }
}

2、hash配信息的业务类

/**
 * autor:liman
 * createtime:2020/8/2
 * comment:
 */
@Service
@Slf4j
public class HashService {

    @Autowired
    private HashRedisService<SysConfig> hashRedisService;

    @Autowired
    private SysConfigMapper sysConfigMapper;

    /**
     * 添加数据字典及其对应的选项(code-value)
     * @param config
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer addSysConfigInfo(SysConfig config){
        try{
            int res = sysConfigMapper.insertSelective(config);
            if(res>0){
                List<SysConfig> configList = sysConfigMapper.selectActiveConfigs();
                if (configList!=null && !configList.isEmpty()) {
                    Map<String, List<SysConfig>> dataMap = Maps.newHashMap();

                    //TODO:所有的数据字典列表遍历 -> 转化为 hash存储的map
                    configList.forEach(t -> {
                        List<SysConfig> list = dataMap.get(t.getType());
                        if (list == null || list.isEmpty()) {
                            list = Lists.newLinkedList();
                        }
                        list.add(t);

                        dataMap.put(t.getType(), list);
                    });

                    hashRedisService.cacheConfigMap(RedisKeyConstants.RedisHashKeyConfig,dataMap);
                }
            }
        }catch (Exception e){
            log.error("实时获取所有有效的数据字典列表-转化为map-存入hash缓存中-发生异常:",e.fillInStackTrace());
        }
        return config.getId();
    }

    /**
     * 取出缓存中所有的数据字典列表
     * @return
     */
    public Map<String,List<SysConfig>> getAll(){
        return hashRedisService.getAllCacheConfigInfo(RedisKeyConstants.RedisHashKeyConfig);
    }

    /**
     * 取出缓存中特定的数据字典列表
     * @param type
     * @return
     */
    public List<SysConfig> getByType(final String type){
        return hashRedisService.getAllConfigInfoByType(RedisKeyConstants.RedisHashKeyConfig,type);
    }
}

3、hashController的入口类

/**
 * autor:liman
 * createtime:2020/8/2
 * comment:hash的controller
 */
@RestController
@Slf4j
@RequestMapping("hash")
public class HashController {

    @Autowired
    private HashService hashService;

    /**
     * 增加配置
     * @param config
     * @param result
     * @return
     */
    @RequestMapping(value = "put",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
    public BaseResponse put(@RequestBody @Validated SysConfig config, BindingResult result){
        String checkRes= ValidatorUtil.checkResult(result);
        if (StrUtil.isNotBlank(checkRes)){
            return new BaseResponse(StatusCode.Fail.getCode(),checkRes);
        }
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            hashService.addSysConfigInfo(config);

        }catch (Exception e){
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }

    /**
     * 获取配置
     * @return
     */
    @RequestMapping(value = "get",method = RequestMethod.GET)
    public BaseResponse get(){
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            response.setData(hashService.getAll());

        }catch (Exception e){
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }

    /**
     * 按照类型获取配置信息
     * @param type
     * @return
     */
    @RequestMapping(value = "get/type",method = RequestMethod.GET)
    public BaseResponse getType(@RequestParam String type){
        BaseResponse response=new BaseResponse(StatusCode.Success);
        try {
            response.setData(hashService.getByType(type));

        }catch (Exception e){
            response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }
}

总结

本篇博客是在上篇博客的基础上,基于springboot的环境下操作Redis的相关类型,操作的一些数据表可以在上一篇博客中找到答案。

你可能感兴趣的:(分布式,redis)