使用redis实现了点赞、关注相关的功能,优化了登录模块。
Redis是一个开源的key-value存储系统,支持多种数据类型,包括string(字符串),list(链表),set(集合),zset(有序集合)和hash(哈希)。Redis操作都是原子性的(有一个失败则都失败)。Redis支持各种方式的排序。Redis数据可以缓存在内存中,也可以周期性的写入到磁盘中(即持久化操作),在此基础上实现了主从(master-slave)同步。
Redis将所有的数据都存放在内存中,所以读写速度很快。同时,Redis将内存中的数据以快照或日志的形式保存到硬盘上,以保证数据的安全性。
第一步:引入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
第二步:对redis进行配置
# RedisProperties
spring.redis.database=11
spring.redis.host=localhost
spring.redis.port=6379
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String,Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 设置key的序列化方式
template.setKeySerializer(RedisSerializer.string());
// 设置value的序列化方式
template.setValueSerializer(RedisSerializer.json());
// 设置hash的key的序列化方式
template.setHashKeySerializer(RedisSerializer.string());
// 设置hash的value的序列化方式
template.setHashValueSerializer(RedisSerializer.json());
template.afterPropertiesSet();
return template;
}
}
第三步:访问redis的的不同数据类型
redisTemplate.opForValue()
redisTemplate.opForHash()
redisTemplate.opForList()
redisTemplate.opForSet()
redisTemplate.opForZset()
redis也是一个数据库,它也是支持事务的,redis事务管理的机制:当启用事务以后,再执行redis命令的时候,并不会立马执行命令,而是将命令放到一个队列里先存着,直到提交事务的时候才会将队列中的命令一次性发送给redis服务器一起执行。所以,redis使用事务的时候,不要在事务过程中做查询操作,因为查询不会立马显示结果,查询操作应当放在事务前或者事务后。
因为声明式事务只可以精确到方法,所以一般使用编程式事务,编程式事务示例如下:
// 编程式事务
@Test
public void testTransactional(){
Object obj = redisTemplate.execute(new SessionCallback() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
String redisKey = "test:tx";
operations.multi(); // 启用事务
operations.opsForSet().add(redisKey,"zhangsan");
operations.opsForSet().add(redisKey,"lisi");
operations.opsForSet().add(redisKey,"wangwu");
// 查询时是没有结果的。所以redis在管理事务的时候中间不要做查询,无效
System.out.println(operations.opsForSet().members(redisKey));
return operations.exec(); // 提交事务
}
});
System.out.println(obj);
}
点赞部分主要有两大块功能,第一块就是点赞,第二块就是收到的赞
主要显示页面:首页的帖子列表部分显示帖子的赞的数量;帖子详情上需要显示赞的数量以及点赞状态;个人主页上需要显示收到的赞的数量。
点赞
:支持对帖子、评论点赞,第1次点赞,第2次取消点赞;需要显示点赞数量:对于首页点赞数量:统计帖子的点赞数量;对于详情页点赞数量:统计点赞数量,显示点赞状态。
详细步骤:点赞,首先调用点赞业务,查询点赞数量,当前点赞状态,~~根据点赞状态确定是否出发点赞事件(后面系统通知部分的功能),重新计算帖子分数(后面热帖的功能),~~最后返回响应。
注意⚠️:点赞部分的存储使用redis的set来实现,将点赞者的用户ID存到set中。
收到的赞
:需要重构点赞功能,以用户为key,记录点赞数量,增加点赞数量使用increment(key),减少点赞数量使用decrement(key);开发个人主页,以用户为key,显示用户收到的点赞的数量。
详细步骤:业务层重构点赞方法,另外需要添加一个查询某个用户获得的赞的数量的业务层方法。开发个人主页时,需要显示的内容主要有:用户信息,获得点赞数量,关注数量,粉丝数量,是否已关注,下一部分实现关注相关功能。
注意⚠️:使用了redis事务管理,把点赞与记录点赞数量两个redis命令放在一个事务。
收获的赞的数量使用redis的String来存储,存储的值为整数类型。
关注、取消关注
⚠️注意:
关注列表、粉丝列表
⚠️注意:业务层查询的信息用map来存,因为列表中不只需要有用户的信息,还需要有关注的时间。主要步骤是:先通过Redis查出来userid集合,然后遍历该集合,从根据userid从user数据库中查用户信息;关注时间是通过Redis来查询的,score就是关注时间。
主要使用Redis优化3个方面:存储验证码,存储用户登录凭证,缓存用户信息
为什么要使用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 kaptcha = (String) session.getAttribute("kaptcha");
String kaptcha = null;
if(StringUtils.isNoneBlank(kaptchaOwner)){
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
kaptcha = (String) redisTemplate.opsForValue().get(redisKey);
}
if(StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)){
model.addAttribute("codeMsg","验证码不正确!");
return "/site/login";
}
// 1.优先从缓存中取值
private User getCache(int userId){
String redisKey = RedisKeyUtil.getUserKey(userId);
return (User) redisTemplate.opsForValue().get(redisKey);
}
// 2.取不到时初始化缓存数据
private User initCache(int userId){
User user = userMapper.selectById(userId);
String redisKey = RedisKeyUtil.getUserKey(userId);
redisTemplate.opsForValue().set(redisKey,user,3600, TimeUnit.SECONDS);
return user;
}
// 3.数据变更时清除缓存数据
private void clearCache(int userId){
String redisKey = RedisKeyUtil.getUserKey(userId);
redisTemplate.delete(redisKey);
}
小结:点赞部分用了Set数据结构,点赞数量用的String数据结构。关注用的Zset数据结构。验证码的存取用的String数据结构。登录凭证的存取用的String数据结构。缓存用户信息用的String数据结构。