场景
个人搭建的一个美食教程网站,每个美食教程的详细页面有一个点赞按钮,每个用户可以通过点击按钮来点赞与取消点赞,并可以看见当前菜品有多少个赞。
实现思路
因为点赞与取消点赞是一个在页面上用户操作比较频繁的功能,而点赞数这个字段是存储在美食教程表里的,用户每点击一次按钮就要修改这个字段会产生很大的数据库开销,所以不考虑直接操作MySQL数据库,转而采用Redis进行存储。后面可采用Quartz框架进行定时的数据同步操作。
采用Redis存储就面临着该选择那一种数据结构来存储每一个教程的点赞数据。根据上面提到的场景可以做出分析:
一个教程可以有多个用户点赞;
一个用户只能给每一个教程点一次赞,再次点击就是取消点赞;
而Redis的集合刚好可以满足我们这一需求。因为集合成员是唯一的,集合中不能出现重复数据。
时序图
核心代码
前端点赞按钮:
<div id="like" class="boxx-one" th:attr="dishId=${item.info.dishId}">
<button th:if="${session.loginUser!=null}"></button>
</div>
<script type="text/javascript">
var elementById1 = document.getElementById("like");
elementById1.onclick = function () {
var path = $("#like").attr("dishId")
var p = document.getElementById("count")
//发送ajax请求
axios({
//请求类型
method: 'POST',
//url
url: 'http://item.meiwei.com/like',
//设置请求体
data: {
dishId: path
}
}).then(function (res) {
p.innerHTML = "已有" + res.data + "名用户点赞";
})
}
</script>
页面传给后端的Vo数据:
public class RequestVo {
private String dishId;
private String members;
}
后端核心代码:
@ResponseBody
@PostMapping("/like")
public void like(@RequestBody RequestVo requestBody, HttpServletResponse response, HttpSession session) {
String dishId = requestBody.getDishId();
//获取用户信息
MemberRespVo user = (MemberRespVo) session.getAttribute(AuthServerConstant.LOGIN_USER);
String username = user.getUsername();
String key = "like:" + dishId;
//判断redis中是否存在,即判断是否已点赞
Boolean ifAbsent = redisTemplate.opsForSet().isMember(key, username);
if (!ifAbsent) {
//如果不存在,则存入redis
likeService.add(key, username);
} else {
//如果存在,则从redis删除
likeService.delete(key, username);
}
//将点赞数回显
Long size = likeService.getCount(key);
try {
response.getWriter().write(size.toString());
} catch (IOException e) {
e.printStackTrace();
}
}