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.统计网站访问量
/**
* 记录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());
}
});
}