點(diǎn)贊功能在社交類型、社區(qū)類型的項(xiàng)目上必不可少,正好項(xiàng)目中用到了這塊,本以為挺簡單的就只是些++、--操作,沒想到實(shí)戰(zhàn)邏輯理起來是相當(dāng)?shù)睦@。那廢話不多說直接開始吧
還原項(xiàng)目場景

前端UI
如圖,我們需要在一篇文章的左邊放置這樣一個(gè)工具條,點(diǎn)贊是其中一個(gè)功能。
表與邏輯
一張記錄文章是否被點(diǎn)贊過的狀態(tài)表 blog_statue
一張用戶表 user
一張博客表 blog

狀態(tài)表
collect表示boolean類型的是否收藏。同理thumbs表示是否點(diǎn)贊過,bid是blog_id,uid是user_id

邏輯關(guān)系
coding

前端按鈕
thumbsClick: function () {
const url = "foreCheckLogin";
const bid = getUrlParms("bid");
axios.get(url).then(function (response) { //這里是檢測當(dāng)前用戶是否登錄
if(response.data.code === 0) { //返回0 表示登錄
const url = "blogs/" + bid +"/statue";
axios.put(url).then(function (response) { //后臺(tái)處理點(diǎn)贊邏輯
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("您還未登錄");
}
});
},
點(diǎn)贊邏輯處理
@PutMapping("blogs/{bid}/statue")
public int postThumbs(@PathVariable("bid") int bid, HttpSession session) {
//先查詢statue,Statue是狀態(tài)表的實(shí)體類
User user = (User) session.getAttribute("user");
Statue statue = statueService.findOne(bid,user.getId());
//可能這個(gè)用戶只點(diǎn)擊了收藏,沒有點(diǎn)贊,只是收藏也會(huì)產(chǎn)生一條記錄,所以此處要做判斷是否進(jìn)行了點(diǎn)贊
if(statue != null) {
//如果為true,也就是進(jìn)行了點(diǎn)贊,那么這次點(diǎn)擊就是取消點(diǎn)贊,進(jìn)行--操作
if(statue.isThumbs()) { // isThumbs 對(duì)應(yīng)狀態(tài)表中是否點(diǎn)贊的字段
int thumbs = blogService.findOne(bid).getThumbNums(); //獲取博客表的總贊數(shù)
int newthumbs = --thumbs;
blogService.autoSetThumbs(newthumbs, bid); //將改變后的贊數(shù)更新到博客表
statueService.updateThumbs(false, bid, user.getId()); //更新是否點(diǎn)贊的狀態(tài)
return newthumbs; //返回操作后的總贊數(shù)
}
else { //這里就是存在這樣一條記錄,但是用戶從來沒有進(jìn)行點(diǎn)贊操作,或者曾經(jīng)取消過行為,這個(gè)thumbs為false、null
//這次事件就是 點(diǎn)贊事件 ++
int thumbs = blogService.findOne(bid).getThumbNums();
int newthumbs = ++thumbs;
blogService.autoSetThumbs(newthumbs,bid);
statueService.updateThumbs(true, bid, user.getId());
return newthumbs; //這段就同上了
}
}
else { // 到這里是用戶還沒有為該文章點(diǎn)贊或者收藏
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;
}
}
//這段代碼是登錄成功后執(zhí)行的前端代碼
const url = "blogs/" + bid +"/statue";
axios.put(url).then(function (response) {
const newthumbs = response.data;
const url = "statues/" + bid;
//從數(shù)據(jù)庫中獲取狀態(tài)表的點(diǎn)贊狀態(tài)
axios.get(url).then(function (response) {
const isThumbs = response.data;
if(isThumbs) { //如果點(diǎn)贊狀態(tài)是true 就設(shè)置按鈕顏色為橘黃
vue.blog.thumbNums = newthumbs;
$(".thumbs_icon").css("color", "orange");
}
else { //否則白色
vue.blog.thumbNums = newthumbs;
$(".thumbs_icon").css("color", "white");
}
});
});
當(dāng)然,頁面加載的時(shí)候,必須檢查狀態(tài)表中該用戶有沒有給這篇博客點(diǎn)贊,使用的是vue,mounted鉤子函數(shù),邏輯就是先檢查是否登錄,然后查詢狀態(tài)表,根據(jù)返回狀態(tài)判斷是什么顏色
//檢查當(dāng)前用戶是否點(diǎn)贊過
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();
}
}
綜上,代碼看上去還有很大優(yōu)化的空間,點(diǎn)贊功能的后臺(tái)邏輯比較繞,因?yàn)樯婕暗淖侄味?,同理收藏功能也可以這么處理。另外關(guān)于++i 與 --i 都不具備原子性,所以它不是線程安全的,由于 i 這個(gè)值是全局變量,并發(fā)環(huán)境會(huì)產(chǎn)生臟讀。這類操作可以考慮synchronized來保證唯一訪問。