点赞功能在社交类型、社区类型的项目上必不可少,正好项目中用到了这块,本以为挺简单的就只是些++、--操作,没想到实战逻辑理起来是相当的绕。那废话不多说直接开始吧
还原项目场景
前端UI如图,我们需要在一篇文章的左边放置这样一个工具条,点赞是其中一个功能。
表与逻辑
一张记录文章是否被点赞过的状态表 blog_statue
一张用户表 user
一张博客表 blog
collect表示boolean类型的是否收藏。同理thumbs表示是否点赞过,bid是blog_id,uid是user_id 逻辑关系
coding
前端按钮 thumbsClick: function () {
const url = "foreCheckLogin";
const bid = getUrlParms("bid");
axios.get(url).then(function (response) { //这里是检测当前用户是否登录
if(response.data.code === 0) { //返回0 表示登录
const url = "blogs/" + bid +"/statue";
axios.put(url).then(function (response) { //后台处理点赞逻辑
const newthumbs = response.data;
const url = "statues/" + bid;
axios.get(url).then(function (response) {
const isThumbs = response.data;
if(isThumbs) {
vue.blog.thumbNums = newthumbs;
$(".thumbs_icon").css("color", "orange");
}
else {
vue.blog.thumbNums = newthumbs;
$(".thumbs_icon").css("color", "white");
}
});
});
}
else {
alert("您还未登录");
}
});
},
点赞逻辑处理
@PutMapping("blogs/{bid}/statue")
public int postThumbs(@PathVariable("bid") int bid, HttpSession session) {
//先查询statue,Statue是状态表的实体类
User user = (User) session.getAttribute("user");
Statue statue = statueService.findOne(bid,user.getId());
//可能这个用户只点击了收藏,没有点赞,只是收藏也会产生一条记录,所以此处要做判断是否进行了点赞
if(statue != null) {
//如果为true,也就是进行了点赞,那么这次点击就是取消点赞,进行--操作
if(statue.isThumbs()) { // isThumbs 对应状态表中是否点赞的字段
int thumbs = blogService.findOne(bid).getThumbNums(); //获取博客表的总赞数
int newthumbs = --thumbs;
blogService.autoSetThumbs(newthumbs, bid); //将改变后的赞数更新到博客表
statueService.updateThumbs(false, bid, user.getId()); //更新是否点赞的状态
return newthumbs; //返回操作后的总赞数
}
else { //这里就是存在这样一条记录,但是用户从来没有进行点赞操作,或者曾经取消过行为,这个thumbs为false、null
//这次事件就是 点赞事件 ++
int thumbs = blogService.findOne(bid).getThumbNums();
int newthumbs = ++thumbs;
blogService.autoSetThumbs(newthumbs,bid);
statueService.updateThumbs(true, bid, user.getId());
return newthumbs; //这段就同上了
}
}
else { // 到这里是用户还没有为该文章点赞或者收藏
Statue statue1 = new Statue();
statue1.setUser(user);
statue1.setThumbs(true);
statue1.setCollect(false);
statue1.setBlog(blogService.findOne(bid));
int thumbs = blogService.findOne(bid).getThumbNums();
int newthumbs = ++thumbs;
blogService.autoSetThumbs(newthumbs,bid);
statueService.save(statue1);
return newthumbs;
}
}
//这段代码是登录成功后执行的前端代码
const url = "blogs/" + bid +"/statue";
axios.put(url).then(function (response) {
const newthumbs = response.data;
const url = "statues/" + bid;
//从数据库中获取状态表的点赞状态
axios.get(url).then(function (response) {
const isThumbs = response.data;
if(isThumbs) { //如果点赞状态是true 就设置按钮颜色为橘黄
vue.blog.thumbNums = newthumbs;
$(".thumbs_icon").css("color", "orange");
}
else { //否则白色
vue.blog.thumbNums = newthumbs;
$(".thumbs_icon").css("color", "white");
}
});
});
当然,页面加载的时候,必须检查状态表中该用户有没有给这篇博客点赞,使用的是vue,mounted钩子函数,逻辑就是先检查是否登录,然后查询状态表,根据返回状态判断是什么颜色
//检查当前用户是否点赞过
checkUserThumbs: function() {
const url = "foreCheckLogin";
const bid = getUrlParms("bid");
axios.get(url).then(function (response) { //登录检查
if(response.data.code === 0) {
const url = "statues/" + bid;
axios.get(url).then(function (response) {
vue.isThumbs = response.data;
if(vue.isThumbs)
$(".thumbs_icon").css("color","orange");
else
$(".thumbs_icon").css("color","white");
});
}
else
console.log("未登录");
})
},
@GetMapping("statues/{bid}")
public boolean checkIsThumbs(HttpSession session, @PathVariable("bid") int bid) {
User user = (User) session.getAttribute("user");
Statue statue = statueService.findOne(bid, user.getId());
if(statue == null) {
return false;
} else {
return statue.isThumbs();
}
}
综上,代码看上去还有很大优化的空间,点赞功能的后台逻辑比较绕,因为涉及的字段多,同理收藏功能也可以这么处理。另外关于++i 与 --i 都不具备原子性,所以它不是线程安全的,由于 i 这个值是全局变量,并发环境会产生脏读。这类操作可以考虑synchronized来保证唯一访问。
网友评论