(eblog)8、消息异步通知、细节调整
小Hub領讀:
繼續我們的eblog,今天來完成博客文章收藏,用戶中心的設置!
項目名稱:eblog
項目 Git 倉庫:https://github.com/MarkerHub/eblog(給個 star 支持哈)
項目演示地址:https://markerhub.com:8082
前幾篇項目講解文章:
1、(eblog)Github 上最值得學習的 Springboot 開源博客項目!
2、(eblog)小 Hub 手把手教你如何從 0 搭建一個開源項目架構
3、(eblog)整合Redis,以及項目優雅的異常處理與返回結果封裝
4、(eblog)用Redis的zset有序集合實現一個本周熱議功能
5、(eblog)自定義Freemaker標簽實現博客首頁數據填充
1、細節調整
這一次作業,我們來修復一下bug,還有一些細節調整,因為博客的功能其實不多,業務邏輯也不復雜,后面我們還有搜索、群聊等功能,都是大模塊。
文章收藏
文章收藏的js其實已經寫好的了,只是有些條件沒有觸發而已,是什么條件呢,我們先來找到收藏的js先:
static/res/mods/jie.js
可以看到什么觸發加載收藏的條件有兩個:
是否有id為LAY_jieAdmin的元素
layui.cache.user.uid是否為-1
LAY_jieAdmin是為了限定只有文章詳情頁才加載這個js,而其他頁面不需要;那layui.cache.user.uid是哪里設置的呢?大家還記得我們一開始給html分模塊的時候嗎,我們在layout.ftl宏中有一段js,原本uid的值就是-1,所以我們需要把登錄之后的值附上去。
templates/inc/layout.ftl
熟系freemarker語法的同學應該都懂${profile.id!'-1'}是啥意思了,!后面表示當值為空的默認值。 好,改好了之后刷新一下,你會發現有個彈窗提示"請求異常,請重試",我們暫時先不管,先把收藏功能搞定先,看看是不是收藏功能controller還沒有導致的。
從上圖可以看出,我已經把查看是否收藏功能的鏈接改了一下
/collection/find/
功能代碼其實很簡單,就從UserCollection表中查詢是否有記錄就行了,如果有表明已經收藏了,js會渲染出取消收藏的按鈕,如果沒有記錄,就會渲染收藏的按鈕。
com.example.controller.PostController
根據js,我直接返回的是data中放一個參數collection是否為true就行了。渲染效果如下:?
然后點擊按鈕,發現有兩個鏈接(我改了一下鏈接前綴):
/collection/add/
/collection/remove/
分別代表這收藏和取消收藏,所以我們分別寫這兩個controller,注意都是ajax請求來的。收藏的邏輯也比較簡單,首先判斷一下是否已經收藏過了,已經收藏就返回提示已經收藏,未收藏就添加一天記錄即可。
com.example.controller.PostController
com.example.controller.PostController
取消收藏的邏輯:刪除一條記錄即可
@ResponseBody @PostMapping("/collection/remove/") public Result collectionRemove(Long cid) {Post post = postService.getById(Long.valueOf(cid));Assert.isTrue(post != null, "該帖子已被刪除");boolean hasRemove = userCollectionService.remove(new QueryWrapper<UserCollection>().eq("post_id", cid).eq("user_id", getProfileId()));return Result.succ(hasRemove); }ok,收藏設計到的3個方法已經開發完畢,點擊文章詳情頁的收藏和取消收藏,都能正常執行代碼!無bug~
消息未讀
到了這時候,你發現,刷新頁面之后,還是有彈窗提示,這是啥問題?瀏覽器打開F12,切換到Network標簽,因為我們猜想應該是一些異步請求出了異常,所以觸發了彈窗提示。接下來我們就要找到這個請求,Network下,我們再點擊XHR,因為這表示是發起的異步請求的鏈接。從這里我們就看到了一個nums/的請求是404,具體的請求其實是:http://localhost:8080/message/nums/,
然后我們再全局搜索/message/nums找到發起這個異步請求的js地方:
所以我們確定了這個彈窗應該就是這引起的了。所以我們去寫一下這個方法。這是新消息通知,我們之前在用戶中心弄過一個我的消息,但是好像沒有狀態(已讀和未讀),所以我需要在UserMessage上添加一個status字段標識已讀和未讀。記得數據庫要添加字段。
com.example.entity.UserMessage
然后我們再查下當前用戶的狀態未0的消息數量出來,就是新消息通知的數量了。
com.example.controller.IndexController
返回值是啥我是根據js推算出來的,js需要啥結果我就返回啥結果。重新運行代碼之后,我們發現彈窗沒有了,頁面展示效果如下:?
消息通知
至此,新消息通知已經ok,接下來我們搞一個高大上一點的功能。我們刷微博簡書頭條等網站的時候,如果收到消息通知,一般來說不用我們刷新頁面,而是實時給我們展示有消息來了,會突然有個新消息通知的圖標提示我們,這是怎么做到的呢,結合我們之前學過的知識。我們可以找到幾種方案來實現這個功能:
ajax定時加載刷新
websocket雙工通訊
長鏈接
我們課程中有節課是專門講解websocket的,接下來我們就使用這個技術來實現這個功能。
同學們可以去回顧一下websocket的知識:
https://gitee.com/lv-success/git-third/tree/master/course-15-websocket/springboot-websocket
上面是一個springboot集成ws的demo,接下來我們安裝這個例子的步驟把ws集成到我們現有的項目里面。
第一步:導入jar包
pom.xml
第二步:編寫ws配置
com.example.config.WebSocketConfig
我們來解析一下這是啥意思,首先@EnableWebSocketMessageBroker,springboot的手動配置大家還記得吧?這個也是開啟ws消息代理,然后繼承WebSocketMessageBrokerConfigurer重寫registerStompEndpoints和configureMessageBroker方法,registerStompEndpoints方法是注冊端點,addEndpoint("/websocket")表示注冊一個端點叫websocket,那么前端就能通過這個鏈接連接到服務器實現雙工通訊了。.withSockJS()意思是使用SockJs協議,回顧一下:
SockJs是解決瀏覽器不支持ws的情況
Stompjs是簡化文本傳輸的格式
configureMessageBroker是配置消息代理,上面我們配置了/user,/topic都是需要消息代理的鏈接。前端/app鏈接前綴過來的消息都會進入消息代理。
有了這兩步驟后,我們就可以使用ws了,我們先來寫一下前端:
因為我們的消息通知是在頭部的用戶名稱那里,所有的頁面都有,所以我們把js寫在layout.ftl上。
$(function () {var elemUser = $('.fly-nav-user');if(layui.cache.user.uid !== -1 && elemUser[0]){var socket = new SockJS("/websocket");stompClient = Stomp.over(socket);stompClient.connect({},function (frame) {//subscribe訂閱stompClient.subscribe('/user/' + ${profile.id} + '/messCount',function (res) {showTips(res.body);})})} });前面的if判斷,我是根據收藏那里來寫的,var socket = new SockJS("/websocket");表示建立端點鏈接,這樣前端就會和后端建立ws雙工通道,stompClient = Stomp.over(socket);表示切換成stomp文本傳輸協議傳輸內容。stompClient.connect表示建立連接觸發的方法,這個方法里面有個stompClient.subscribe,差不多就表示訂閱這個消息隊列的意思,當后端往/user/{userId}/messCount里面發送消息時候,當前用戶就能接收到消息,res.body就是返回的內容,然后就是showTips方法,這個方法其實就是渲染新消息通知的樣式,我們從之前的新消息通知那里吧對應的js復制過來即可:
function showTips(count) {var msg = $('<a class="fly-nav-msg" href="javascript:;">'+ count +'</a>');var elemUser = $('.fly-nav-user');elemUser.append(msg);msg.on('click', function(){location.href = '/center/message/';});layer.tips('你有 '+ count +' 條未讀消息', msg, {tips: 3,tipsMore: true,fixed: true});msg.on('mouseenter', function(){layer.closeAll('tips');}) }ok,那前端我們已經可以連上ws實現雙工通訊,并且監聽了/user/{userId}/messCount這個隊列,所以后端往這里面發送消息前端就能收到然后實現showTips方法。 那后端什么時候該發送消息給前端呢?
有人評論了作者文章,或者回復作者的評論
系統消息等
ok,我們先來寫一個wsService,寫一個發送消息數量給前端的方法。
com.example.service.WsService
他的實現類復雜嘛?其實不復雜,我們先來看下參數,userId,就是限定要給誰發送消息,count是消息數量,這里我們考慮多種情況,但count不為空時候,我們返回count數量的,當count為空時候,我們搜索userId所有未讀的消息數量然后返回。
com.example.service.impl.WsServiceImpl
發送ws消息,用的是SimpMessagingTemplate,convertAndSendToUser方法會自動在前面添加前綴/user,然后是userId,加上后面的后綴/messCount,所以加起來的鏈接其實就是/user/{userId}/messCount,那么我們在需要發送消息的地方調用這個方法即可。 然后這里還有個內容要點,就是這里我用了一個@Async表示異步,從線程角度來說就是新起一個線程來執行這個方法,從而保證不影響調用方的事務和執行時間等。
那么我們來說下@Async的用法
異步@Async
其實這里我原本是想用隊列來實現的,也能表示異步。本著讓同學們接觸到更多知識,我們這里就用了@Aysnc注解來實現,后面我們還是會用到MQ的,同學們別急。
使用這個注解我們需要開啟異步配置。注解是@EnableAsync
com.example.config.AsyncConfig
所以使用了@EnableAsync注解之后我們就可以使用@Aysnc注解來實現異步了,asyncTaskExecutor()其實就是我用來重寫AsyncTaskExecutor用的,定義了最大線程組等信息。另外Async其實還可以配置很多信息,比如異步線程出錯時候的處理(重試等),大家課后可以多查詢一下資料,這注解我在工作中運用其實還比較多的。 好了,上面我們已經把發送ws消息的方法改成了異步方法,會起一個線程執行發送。我們現在需要調用的地方其實就是在評論那里。
com.example.controller.PostController#reply(Long, Long, String)
這樣有人評論文章或者回復評論的時候,都能實時收到消息了,我們來演示一下效果:
至此,我們實現了傳說中的實時通知功能!要膨脹了~
文章閱讀量
接下來的任務,我們是要完善一下文章閱讀量。之前訪問文章,閱讀量都沒增加,現在我們來補上 這個一個bug。怎么做呢?是每訪問一次我們就直接修改數據庫?這里我們使用緩存在解決這個問題,每次訪問,我們就直接緩存的閱讀量增一,然后在某一時刻再同步到數據庫中即可。訪問文章時候,我們把緩存中的閱讀量傳到vo中,具體咋樣的呢,我們找到之前寫的com.example.controller.PostController#view方法,然后我加了這一句代碼:
技術要把vo的viewCount值修改成緩存的數量。
com.example.service.impl.PostServiceImpl#setViewCount
從代碼中可以看到,我們先從緩存中獲取ViewCount,然后設置post.setViewCount,最后再把加一之后的值同步到redis中。 ok,這一步還是比較簡單的,接下來我們要起一個定時器,然后定時吧緩存中的閱讀量同步到數據庫中,實現數據同步。
com.example.schedules.ScheduledTasks
為何獲取所有需要同步閱讀的列表,我們用了keys命令,實際上當redis的緩存越來越大的時候,我們是不能再使用這keys命令的,因為keys命令會檢索所有的key,是個耗時的過程,而redis又是個單線程的中間件,會影響其他命令的執行。所以理論上我們需要用scan命令。考慮到這里博客只是個簡單業務,redis不會很大,所以就直接用了keys命令,后期大家可以自行優化。 然后獲取到列表后,然后就是獲取所有的實體,然后批量更新閱讀量。
?給eblog一個star,感謝支持哈
總結
以上是生活随笔為你收集整理的(eblog)8、消息异步通知、细节调整的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 所谓技术团队绩效
- 下一篇: python pop3lib连接网易企业