redis的使用,存储验证码

421 阅读3分钟

1.存储验证码

1.为了确定哪个验证码属于哪个用户,我们先生成个随机字符串kaptchaOwner,通过cookie发送给前端。

2.然后把kaptchaOwner,拼在redis的key中,这样就可以通过cookie拼成key获取对应的value。

3.存储验证码

之前是存session的

//使用redis优化
String kaptchaOwner = CommunityUtil.generateUUID();
Cookie cookie = new Cookie("kaptchaOwner",kaptchaOwner);
cookie.setMaxAge(60);
cookie.setPath(contextPath);
response.addCookie(cookie);
//将验证码存入redis
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
redisTemplate.opsForValue().set(redisKey,text,60, TimeUnit.SECONDS);

登录验证

String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
kaptcha = (String) redisTemplate.opsForValue().get(redisKey);

2.存储登录凭证

登录时,我们把ticket生成的字符串发给浏览器之后,并且存在数据库(比session好),现在我们把数据库改成redis。登录状态通过拦截器实现。

//生成登录凭证.本来存session的,还是改数据库了
        LoginTicket loginTicket = new LoginTicket();
        loginTicket.setUserId(user.getId());
        loginTicket.setTicket(CommunityUtil.generateUUID());
        loginTicket.setStatus(0);
        loginTicket.setExpired(new Date(System.currentTimeMillis() + (long) expiredSecond * 1000));
//        loginTicketMapper.insertLoginTicket(loginTicket);

        //改成保存登录凭证到redis中
        String redisKey = RedisKeyUtil.getTicketKey(loginTicket.getTicket());
        redisTemplate.opsForValue().set(redisKey,loginTicket);

登出,把状态改成1

public void logout(String ticket){
//        loginTicketMapper.updateStatus(ticket,1);
        String redisKey = RedisKeyUtil.getTicketKey(ticket);
        LoginTicket loginTicket = (LoginTicket) redisTemplate.opsForValue().get(redisKey);
        loginTicket.setStatus(1);
        redisTemplate.opsForValue().set(redisKey,loginTicket);
    }

3.点赞set,查看默认获得的赞

该应用包括看点赞的人的信息和点赞数量。所以需要用set去重存储点赞人的userId。 当存在相同的userId表示已经点赞完成,所以变成了取消点赞。

key包括类型(人,评论,文章)和实体id,value是点赞人的id

两次更新需要用redis的事务,Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。

总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

public void like(int userId,int entityType,int entityId,int entityUserId){
//        String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType,entityId);
//        Boolean isMember = redisTemplate.opsForSet().isMember(entityLikeKey, userId);
//        if (isMember){
//            redisTemplate.opsForSet().remove(entityLikeKey,userId);
//        }else {
//            redisTemplate.opsForSet().add(entityLikeKey,userId);
//        }
        //上面的只是实现了点赞。现在我们不仅需要知道谁点赞。而且得知道xx总共获得的赞数.
        //由于涉及两个key的update所以需要事务
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType,entityId);
                //这里的id就是entityId的拥有者id,查询某个人的赞数
                String userLikeKey = RedisKeyUtil.getUserLikeKey(entityUserId);

                Boolean isMember = redisTemplate.opsForSet().isMember(entityLikeKey, userId);

                redisOperations.multi();
                if (isMember){
                    redisOperations.opsForSet().remove(entityLikeKey,userId);
                    redisOperations.opsForValue().decrement(userLikeKey);
                }else{
                    redisOperations.opsForSet().add(entityLikeKey,userId);
                    redisOperations.opsForValue().increment(userLikeKey);
                }
                return redisOperations.exec();
            }
        });
    }
/**
 * 查询某个用户获得的赞
 */
public int findUserLikeCount(int userId){
    String userLikeKey = RedisKeyUtil.getUserLikeKey(userId);
    Integer count = (Integer) redisTemplate.opsForValue().get(userLikeKey);
    return count == null ? 0 : count.intValue();
}

4.关注zSet

我们需要zset,score存的时间戳,这样按照时间顺序看关注人的列表了。

我关注一个人,分了两种 1.我成了entityId的粉丝 2.我关注的人增加1

2:key:我的Id,value entityId

1: key entityId,value 我的id

public void follow(int userId,int entityType,int entityId){
    redisTemplate.execute(new SessionCallback() {
        @Override
        public Object execute(RedisOperations redisOperations) throws DataAccessException {
            String followeeKey = RedisKeyUtil.getFolloweeKey(userId,entityType);
            String followerKey = RedisKeyUtil.getFollowerKey(entityType,entityId);

            redisOperations.multi();
            redisOperations.opsForZSet().add(followeeKey,entityId,System.currentTimeMillis());
            redisOperations.opsForZSet().add(followerKey,userId,System.currentTimeMillis());
            return redisOperations.exec();
        }
    });
}
/**
 * 取消关注
 */
public void unFollow(int userId,int entityType,int entityId){
    redisTemplate.execute(new SessionCallback() {
        @Override
        public Object execute(RedisOperations redisOperations) throws DataAccessException {
            String followeeKey = RedisKeyUtil.getFolloweeKey(userId,entityType);
            String followerKey = RedisKeyUtil.getFollowerKey(entityType,entityId);

            redisOperations.multi();
            redisOperations.opsForZSet().remove(followeeKey,entityId);
            redisOperations.opsForZSet().remove(followerKey,userId);
            return redisOperations.exec();
        }
    });
}
/**
 * 查询某用户的关注实体数量
 */
public long findFolloweeCount(int userId,int entityType){
    String followeeKey = RedisKeyUtil.getFolloweeKey(userId,entityType);
    return redisTemplate.opsForZSet().zCard(followeeKey);
}

/**
 * 查询实体的粉丝数量
 */
public long findFollowerCount(int entityType,int entityId){
    String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
    return redisTemplate.opsForZSet().zCard(followerKey);
}

/**
 * 查询当前使用是否关注当前值
 */
public boolean hasFollowed(int userId,int entityType,int entityId){
    String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
    //查实体的分数,如果有表示已关注true 未关注false
    return redisTemplate.opsForZSet().score(followeeKey, entityId) != null;
}

/**
 * 查询某用户关注的人
 */
public List<Map<String,Object>> findFollowee(int userId,int offset,int limit){
    String followeeKey = RedisKeyUtil.getFolloweeKey(userId, ENTITY_TYPE_USER);
    Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);
    if (targetIds == null){
        return null;
    }
    List<Map<String,Object>> list = new ArrayList<>();
    for (Integer targetId : targetIds) {
        Map<String,Object> map = new HashMap<>();
        //xx关注的用户user
        User user = userService.findUserById(targetId);
        map.put("user",user);
        //获取关注的时间
        Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
        map.put("followTime",new Date(score.longValue()));
        list.add(map);
    }
    return list;
}

/**
 *  查询某用户的粉丝
 */
public List<Map<String,Object>> findFollower(int userId,int offset,int limit){
    String followerKey = RedisKeyUtil.getFollowerKey(ENTITY_TYPE_USER, userId);
    //redis range方法返回的set是有序的从小到大
    Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);
    if (targetIds == null){
        return null;
    }

    List<Map<String,Object>> list = new ArrayList<>();
    for (Integer targetId : targetIds) {
        Map<String,Object> map = new HashMap<>();
        //xx关注的用户user
        User user = userService.findUserById(targetId);
        map.put("user",user);
        //获取关注的时间
        Double score = redisTemplate.opsForZSet().score(followerKey, targetId);
        map.put("followTime",new Date(score.longValue()));
        list.add(map);
    }
    return list;
}

5.统计网站访问量

HW~WG{ZVT}_06D9P2VV_E.png

HW~WG{ZVT}_06D9P2VV_E.png

/**
 * 记录ip UV
 */
public void recordUV(String ip){
    String redisKey = RedisKeyUtil.getUVKey(simpleDateFormat.format(new Date()));
    redisTemplate.opsForHyperLogLog().add(redisKey,ip);
}

/**
 * 返回指定日期范围的UV
 */
public long calculateUV(Date start,Date end){
    if (start == null || end == null){
        throw new IllegalArgumentException("参数不能为空");
    }
    //获取该日期范围的key
    List<byte[]> keyList = new ArrayList<>();
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(start);
    //当前时间不晚于end就循环
    while (!calendar.getTime().after(end)){
        String key = RedisKeyUtil.getUVKey(simpleDateFormat.format(calendar.getTime()));
        keyList.add(key.getBytes());
        calendar.add(Calendar.DATE,1);
    }

    //合并,也就是求value的并集
    String redisKey = RedisKeyUtil.getUVKey(simpleDateFormat.format(start),simpleDateFormat.format(end));
    redisTemplate.opsForHyperLogLog().union(redisKey,keyList.toArray());

    return redisTemplate.opsForHyperLogLog().size(redisKey);
}

public void recordDAU(int userId){
    String redisKey = RedisKeyUtil.getDAUKey(simpleDateFormat.format(new Date()));
    redisTemplate.opsForValue().setBit(redisKey,userId,true);
}

public long calculateDAU(Date start,Date end){
    if (start == null || end == null) {
        throw new IllegalArgumentException("参数不能为空!");
    }

    // 整理该日期范围内的key
    List<byte[]> keyList = new ArrayList<>();
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(start);
    while (!calendar.getTime().after(end)) {
        String key = RedisKeyUtil.getDAUKey(simpleDateFormat.format(calendar.getTime()));
        keyList.add(key.getBytes());
        calendar.add(Calendar.DATE, 1);
    }

    // 进行OR运算
    return (long) redisTemplate.execute(new RedisCallback() {
        @Override
        public Object doInRedis(RedisConnection connection) throws DataAccessException {
            String redisKey = RedisKeyUtil.getDAUKey(simpleDateFormat.format(start), simpleDateFormat.format(end));
            connection.bitOp(RedisStringCommands.BitOperation.OR,
                    redisKey.getBytes(), keyList.toArray(new byte[0][0]));
            return connection.bitCount(redisKey.getBytes());
        }
    });
}