大众点评项目 基于Redis的点赞功能实现
- 需求:基于Redis实现点赞功能实现
- 业务实战
- 总体代码展示
- 总结
SpringCloud章节复习已经过去,新的章节Redis开始了,这个章节中将会回顾Redis实战项目 大众点评
主要依照以下几个原则
- 基础+实战的Demo和Coding上传到我的代码仓库
- 在原有基础上加入一些设计模式,stream+lamdba等新的糖
- 通过DeBug调试,进入组件源码去分析底层运行的规则和设计模式
代码会同步在我的gitee中去,觉得不错的同学记得一键三连求关注,感谢:
Redis优化-链接: RedisFunctionLikeProject
需求:基于Redis实现点赞功能实现
** 点赞功能的基本实现, 点赞用户排序, 相关用户信息显示**
业务实战
- 在原有Blog类的基础上添加相关字段
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("tb_blog")
public class Blog implements Serializable {
/**
* 用户图标
*/
@TableField(exist = false)
private String icon;
/**
* 用户姓名
*/
@TableField(exist = false)
private String name;
/**
* 是否点赞过了
*/
@TableField(exist = false)
private Boolean isLike;
}
**@TableField(exist = false)**表示不存在,我们通过在业务层手动注入这些信息
- 通过相应的url进行基本操作,业务放到Service层去做
原有业务
@PutMapping("/like/{id}")
public Result likeBlog(@PathVariable("id") Long id) {
// 修改点赞数量
return blogService.likeBlog(id);
blogService.update()
.setSql("liked = liked + 1").eq("id", id).update();
return Result.ok();
}
这里对点赞次数没有限制,是不行的,我们希望对点赞功能只能一次;
@PutMapping("/like/{id}")
public Result likeBlog(@PathVariable("id") Long id) {
// 修改点赞数量
return blogService.likeBlog(id);
}
- 将点赞信息存放到Redis中,存放类型是zset类型,通过这种类型,可以保证
- 数据唯一性
- 指定SCORE属性进行排序,我们选用时间戳System.currentTimeMillis()
/**
* @Function:点赞功能实现
* @param id
* @return
*/
@Override
public Result likeBlog(Long id) {
Long userId = UserHolder.getUser().getId();
//判断当前用户是否点赞
String key = RedisConstants.BLOG_LIKED_KEY + id;
Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
// if (!member) { 包装类可能为null
// if (BooleanUtil.isFalse(member)) {
if (score == null) {
//如果set中不存在,说明没有
// blog.setIsLike(false);
boolean flag = update().setSql("liked = liked + 1").eq("id", id).update();
if (flag) {
stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis());
}
}else{
//如果没有点赞
// blog.setIsLike(true);
boolean flag = update().setSql("liked = liked - 1").eq("id", id).update();
if (flag) {
stringRedisTemplate.opsForZSet().remove(key, userId.toString());
}
}
return Result.ok();
}
- 点赞排序,显示用户信息
@GetMapping("/likes/{id}")
public Result likesBlog(@PathVariable("id") Long id) {
// 修改点赞数量
return blogService.queryBlogLikes(id);
}
@Override
public Result queryBlogLikes(Long id) {
String key = RedisConstants.BLOG_LIKED_KEY + id;
Set<String> topFive = stringRedisTemplate.opsForZSet().range(key, 0, 4);
if (topFive == null || topFive.isEmpty()) {
return Result.ok(Collections.emptyList());
}
List<Long> userIdOrder = topFive.stream().map(Long::valueOf).collect(Collectors.toList());
String idStr = StrUtil.join(",", userIdOrder);
List<UserDTO> userDTOS = userService.query()
.in("id", userIdOrder)
.last("ORDER BY FIELD(id, "+ idStr + ")").list()
.stream()
.map(user -> {
return BeanUtil.copyProperties(user, UserDTO.class);
}).collect(Collectors.toList());
return Result.ok(userDTOS);
}
这里需要注意下 userService.query() .in("id", userIdOrder) .last("ORDER BY FIELD(id, "+ idStr + ")").list()
这个是为了按时间顺序展示来进行的,ORDER BY FIELD
就是值其排序方式按我们的要求来进行,这里通过MP的last方法进行了拼装
总体代码展示
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
@Resource
private IBlogService blogService;
@Resource
private IUserService userService;
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* @Function:点赞功能实现
* @param id
* @return
*/
@Override
public Result likeBlog(Long id) {
Long userId = UserHolder.getUser().getId();
//判断当前用户是否点赞
String key = RedisConstants.BLOG_LIKED_KEY + id;
Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
// if (!member) { 包装类可能为null
// if (BooleanUtil.isFalse(member)) {
if (score == null) {
//如果set中不存在,说明没有
// blog.setIsLike(false);
boolean flag = update().setSql("liked = liked + 1").eq("id", id).update();
if (flag) {
stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis());
}
}else{
//如果没有点赞
// blog.setIsLike(true);
boolean flag = update().setSql("liked = liked - 1").eq("id", id).update();
if (flag) {
stringRedisTemplate.opsForZSet().remove(key, userId.toString());
}
}
return Result.ok();
}
@Override
public Result queryBlogLikes(Long id) {
String key = RedisConstants.BLOG_LIKED_KEY + id;
Set<String> topFive = stringRedisTemplate.opsForZSet().range(key, 0, 4);
if (topFive == null || topFive.isEmpty()) {
return Result.ok(Collections.emptyList());
}
List<Long> userIdOrder = topFive.stream().map(Long::valueOf).collect(Collectors.toList());
String idStr = StrUtil.join(",", userIdOrder);
List<UserDTO> userDTOS = userService.query()
.in("id", userIdOrder)
.last("ORDER BY FIELD(id, "+ idStr + ")").list()
.stream()
.map(user -> {
return BeanUtil.copyProperties(user, UserDTO.class);
}).collect(Collectors.toList());
return Result.ok(userDTOS);
}
总结