從八月底到昨天属提,整整三個(gè)月,邊看視頻學(xué)技術(shù)棧邊寫(xiě)代碼美尸,每天晚上擠時(shí)間完成了這個(gè)項(xiàng)目冤议,還是想為明年實(shí)習(xí)做一個(gè)項(xiàng)目上的準(zhǔn)備。最初是想做一個(gè)深度學(xué)習(xí)方面的項(xiàng)目师坎,當(dāng)時(shí)對(duì)這方面基礎(chǔ)知識(shí)的儲(chǔ)備還不夠恕酸,如今也還在看視頻和文檔學(xué)習(xí),因此選擇了web項(xiàng)目胯陋。其實(shí)對(duì)于以后工作的方向到底是算法還是研發(fā)現(xiàn)在也說(shuō)不清楚蕊温,等明年初根據(jù)自己的學(xué)習(xí)情況再做進(jìn)一步的打算袱箱。
接下來(lái)學(xué)校的課越來(lái)越集中,各種考試也陸續(xù)而至义矛,深度學(xué)習(xí)也還在繼續(xù)學(xué)習(xí)发笔,因此留給項(xiàng)目上的準(zhǔn)備時(shí)間也捉襟見(jiàn)肘,但每天還是會(huì)堅(jiān)持寫(xiě)算法題凉翻,相信明年會(huì)越來(lái)越好了讨。
這個(gè)項(xiàng)目是以現(xiàn)在的知乎、旁朊客網(wǎng)這類(lèi)問(wèn)答平臺(tái)為原型量蕊,基于springboot的SSM框架的Java web應(yīng)用項(xiàng)目。數(shù)據(jù)庫(kù)使用了redis和mysql艇挨,同時(shí)通過(guò)一個(gè)異步消息框架來(lái)實(shí)現(xiàn)事件的異步處理残炮,并使用爬蟲(chóng)對(duì)網(wǎng)站進(jìn)行數(shù)據(jù)填充。
目錄
- 項(xiàng)目的基本框架及配置
- AOP和IOC
- MySQL+MyBatis
- 注冊(cè)與登錄的實(shí)現(xiàn)
- 發(fā)表問(wèn)題+敏感詞過(guò)濾
- 發(fā)表評(píng)論和站內(nèi)信
- Redis實(shí)現(xiàn)點(diǎn)贊和點(diǎn)踩功能
- 異步消息機(jī)制
- 關(guān)注+粉絲列表的實(shí)現(xiàn)
- Timeline與新鮮事缩滨,推拉模式下的Feed流
- 使用爬蟲(chóng)爬取數(shù)據(jù)势就,對(duì)網(wǎng)站進(jìn)行數(shù)據(jù)填充
- 功能擴(kuò)展以及深度擴(kuò)展
項(xiàng)目的基本框架及配置
創(chuàng)建git倉(cāng)庫(kù),本地配置idea并測(cè)試pull和push脉漏。
創(chuàng)建springboot工程苞冯,導(dǎo)入web,velocity和aop的包侧巨。
生成maven項(xiàng)目舅锄,pom.xml包含上述依賴(lài)。
controller中使用注解配置司忱,requestmapping皇忿,responsebody基本可以解決請(qǐng)求轉(zhuǎn)發(fā)以及響應(yīng)內(nèi)容的渲染。responsebody自動(dòng)選擇viewresolver進(jìn)行解析坦仍。
使用pathvariable和requestparam傳遞參數(shù)鳍烁,使用velocity編寫(xiě)頁(yè)面模板,注意其中的語(yǔ)法使用繁扎。常用{}幔荒。
使用http規(guī)范下的httpservletrequest和httpservletresponse來(lái)封裝請(qǐng)求和相響應(yīng),使用封裝好的session和cookie對(duì)象梳玫。
使用重定向的redirectview和統(tǒng)一異常處理器exceptionhandler爹梁。
AOP和IOC
IOC解決對(duì)象實(shí)例化以及依賴(lài)傳遞問(wèn)題,解耦提澎。
AOP解決縱向切面問(wèn)題卫键,主要實(shí)現(xiàn)日志和權(quán)限控制功能。
aspect實(shí)現(xiàn)切面虱朵,并且使用logger來(lái)記錄日志莉炉,用該切面的切面方法來(lái)監(jiān)聽(tīng)controller钓账。
MySQL+MyBatis
使用mysql創(chuàng)建數(shù)據(jù)庫(kù)和表。
加入mybatis和mysql的maven倉(cāng)庫(kù)絮宁,注意梆暮,由于現(xiàn)在版本的springboot不再支持velocity進(jìn)而導(dǎo)致我使用較早版本的springboot,所以這里提供一可以正常運(yùn)行的版本設(shè)置绍昂。
springboot使用1.4.0啦粹,mybatis-spring-boot-starter使用1.2.1,mysql-connector-java使用8.0.12窘游。
注意mybatis的注解語(yǔ)法以及xml的配置要求唠椭,xml要求放在resource中并且與dao接口在相同的包路徑下。
application.properties增加spring配置數(shù)據(jù)庫(kù)鏈接地址忍饰。
兩個(gè)小工具:
- ViewObject:方便傳遞任何數(shù)據(jù)到
- VelocityDateTool:velocity自帶工具類(lèi)
寫(xiě)好靜態(tài)文件html css和js贪嫂,并且注意配置。
- spring.velocity.suffix=.html 保證跳轉(zhuǎn)請(qǐng)求轉(zhuǎn)發(fā)到html上
- spring.velocity.toolbox-config-location=toolbox.xml
注冊(cè)與登錄的實(shí)現(xiàn)
新建數(shù)據(jù)表login_ticket用來(lái)存儲(chǔ)ticket字段艾蓝。該字段在用戶(hù)登錄成功時(shí)被生成并存入數(shù)據(jù)庫(kù)力崇,并被設(shè)置為cookie,下次用戶(hù)登錄時(shí)會(huì)帶上這個(gè)ticket赢织,ticket是隨機(jī)的UUID字符串亮靴,有過(guò)期時(shí)間以及有效狀態(tài)。
使用攔截器interceptor來(lái)攔截所有用戶(hù)請(qǐng)求于置,判斷請(qǐng)求中是否存在有效的ticket茧吊,如果有就將用戶(hù)信息寫(xiě)入Threadlocal。所有線(xiàn)程的threadlocal都被存在一個(gè)叫做hostholder的實(shí)例中八毯,根據(jù)該實(shí)例就可以在全局任意位置獲取用戶(hù)的信息搓侄。
該ticket的功能類(lèi)似session,也是通過(guò)cookie寫(xiě)回瀏覽器宪彩,瀏覽器請(qǐng)求時(shí)再通過(guò)cookie傳遞休讳,區(qū)別是該字段是存在數(shù)據(jù)庫(kù)中的讲婚,并且可以用于移動(dòng)端尿孔。
通過(guò)用戶(hù)訪(fǎng)問(wèn)權(quán)限攔截器來(lái)攔截用戶(hù)的越界訪(fǎng)問(wèn),比如用戶(hù)沒(méi)有管理員權(quán)限就不能訪(fǎng)問(wèn)管理員頁(yè)面筹麸。
配置了json工具類(lèi)以及md5工具類(lèi)活合,并且使用Java自帶的鹽生成api將用戶(hù)密碼加密為密文。保證密碼安全物赶。
數(shù)據(jù)安全性的保障手段:https使用公鑰加密私鑰解密白指,比如支付寶的密碼加密,單點(diǎn)登錄驗(yàn)證酵紫,驗(yàn)證碼機(jī)制等告嘲。
發(fā)表問(wèn)題+敏感詞過(guò)濾
發(fā)布問(wèn)題時(shí)檢查標(biāo)題和內(nèi)容错维,防止xss注入,并且過(guò)濾敏感詞橄唬。
防止xss注入直接使用HTMLutils的方法即可實(shí)現(xiàn)赋焕。
過(guò)濾敏感詞首先需要建立一個(gè)字典樹(shù),并且讀取一份保存敏感詞的文本文件仰楚,然后初始化字典樹(shù)隆判。最后將過(guò)濾器作為一個(gè)服務(wù),讓需要過(guò)濾敏感詞的服務(wù)進(jìn)行調(diào)用即可僧界。
發(fā)表評(píng)論和站內(nèi)信
首先建立表comment和message分別代表評(píng)論和站內(nèi)信侨嘀。
評(píng)論的邏輯是每一個(gè)問(wèn)題下面都有評(píng)論,顯示評(píng)論數(shù)量捂襟,具體內(nèi)容咬腕,評(píng)論人等信息。
消息的邏輯是笆豁,兩個(gè)用戶(hù)之間發(fā)送一條消息郎汪,有一個(gè)唯一的會(huì)話(huà)id,這個(gè)會(huì)話(huà)里可以有多條這兩個(gè)用戶(hù)的交互信息闯狱。通過(guò)一個(gè)用戶(hù)id獲取該用戶(hù)的會(huì)話(huà)列表煞赢,再根據(jù)會(huì)話(huà)id再獲取具體的會(huì)話(huà)內(nèi)的多條消息。
邏輯清楚之后哄孤,再加上一些附加功能照筑,比如顯示未讀消息數(shù)量,根據(jù)時(shí)間順序排列會(huì)話(huà)和消息瘦陈。
本節(jié)內(nèi)容基本就是業(yè)務(wù)邏輯的開(kāi)發(fā)凝危,沒(méi)有新增什么技術(shù)點(diǎn),主要是前后端交互的邏輯比較復(fù)雜晨逝,前端的開(kāi)發(fā)量也比較大蛾默。
Redis實(shí)現(xiàn)點(diǎn)贊和點(diǎn)踩功能
首先了解一下redis的基礎(chǔ)知識(shí),數(shù)據(jù)結(jié)構(gòu)捉貌,jedis使用等支鸡。
編寫(xiě)list,string趁窃,hashmap牧挣,set,sortset的測(cè)試用例醒陆,熟悉jedis api瀑构。
開(kāi)發(fā)點(diǎn)踩和點(diǎn)贊功能,在此之前根據(jù)業(yè)務(wù)封裝好jedis的增刪改查操作刨摩,放在util包中寺晌。
根據(jù)需求確定key字段世吨,格式是 like:實(shí)體類(lèi)型:實(shí)體id 和 dislike:實(shí)體類(lèi)型:實(shí)體id 這樣可以將喜歡一條新聞的人存在一個(gè)集合,不喜歡的存在另一個(gè)集合呻征。通過(guò)統(tǒng)計(jì)數(shù)量可以獲得點(diǎn)贊和點(diǎn)踩數(shù)另假。
一般點(diǎn)贊點(diǎn)踩操作是先修改redis的值并獲取返回值,然后再異步修改mysql數(shù)據(jù)庫(kù)的likecount數(shù)值怕犁。這樣既可以保證點(diǎn)贊操作快速完成边篮,也可保證數(shù)據(jù)一致性。
異步消息機(jī)制
在之前的功能中有一些不需要實(shí)時(shí)執(zhí)行的操作或者任務(wù)奏甫,我們可以把它們改造成異步消息來(lái)進(jìn)行發(fā)送戈轿。
具體操作就是使用redis來(lái)實(shí)現(xiàn)異步消息隊(duì)列。代碼中使用事件event來(lái)包裝一個(gè)事件阵子,事件需要記錄事件實(shí)體的各種信息:一個(gè)異步工具類(lèi)(事件生產(chǎn)者+事件消費(fèi)者+eventHandler接口)思杯,讓以后各種事件的實(shí)現(xiàn)類(lèi)來(lái)實(shí)現(xiàn)這個(gè)接口。
事件生產(chǎn)者一般作為一個(gè)服務(wù)挠进,由Controller中的業(yè)務(wù)邏輯調(diào)用并產(chǎn)生一個(gè)事件色乾,將事件序列化存入redis隊(duì)列中,事件消費(fèi)者則通過(guò)一個(gè)線(xiàn)程循環(huán)獲取隊(duì)列里的事件领突,并且尋找對(duì)應(yīng)的handler進(jìn)行處理暖璧。
整個(gè)異步事件的框架開(kāi)發(fā)完成,后面新加入的登錄君旦,點(diǎn)贊等事件都可以這么實(shí)現(xiàn)澎办。
關(guān)注+粉絲列表的實(shí)現(xiàn)
新增關(guān)注功能,使用redis實(shí)現(xiàn)每一個(gè)關(guān)注對(duì)象的粉絲列表以及每一個(gè)用戶(hù)的關(guān)注對(duì)象列表金砍。通過(guò)該列表的crud操作可以對(duì)應(yīng)獲取粉絲列表和關(guān)注列表局蚀,并且實(shí)現(xiàn)關(guān)注和取關(guān)功能。
由于關(guān)注成功和添加粉絲成功時(shí)同一個(gè)事務(wù)里的兩個(gè)操作恕稠,可以使用redis的事務(wù)multi來(lái)包裝事務(wù)并進(jìn)行提交琅绅。
除此之外,關(guān)注成功或者被關(guān)注還可以通過(guò)事件機(jī)制來(lái)生成發(fā)送郵件的事件鹅巍,由異步的隊(duì)列處理器來(lái)完成事件響應(yīng)千扶,同樣是根據(jù)redis來(lái)實(shí)現(xiàn)。
對(duì)于粉絲列表昆著,除了顯示粉絲的基本信息之外县貌,還要顯示當(dāng)前用戶(hù)是否關(guān)注了這個(gè)粉絲术陶,以便前端顯示凑懂。
對(duì)于關(guān)注列表來(lái)說(shuō),如果被關(guān)注對(duì)象是用戶(hù)的話(huà)梧宫,除了顯示用戶(hù)的基本信息之外接谨,還要顯示當(dāng)前用戶(hù)是被這個(gè)用戶(hù)關(guān)注摆碉,以便前端顯示。
Timeline與新鮮事脓豪,推拉模式下的Feed流
微博的新鮮事功能介紹:關(guān)注好友的動(dòng)態(tài)(好友的點(diǎn)贊和發(fā)表的問(wèn)題等)巷帝,關(guān)注了某個(gè)問(wèn)題,這些都是feed流的一部分扫夜。
在知乎中的feed流主要體現(xiàn)于:關(guān)注用戶(hù)的評(píng)論行為楞泼,關(guān)注用戶(hù)的關(guān)注問(wèn)題行為。
feed流主要分為兩種笤闯,推模式和拉模式堕阔。推模式主要是把新鮮事推送給關(guān)注該用戶(hù)的粉絲,本例使用redis來(lái)存儲(chǔ)某個(gè)用戶(hù)接受的新鮮事id列表颗味,這個(gè)信息流又稱(chēng)為timeline超陆,根據(jù)用戶(hù)的唯一key來(lái)存儲(chǔ);拉模式主要是用戶(hù)直接找尋自己所有關(guān)注的人浦马,并且到數(shù)據(jù)庫(kù)去查找這些關(guān)注對(duì)象的新鮮事时呀,直接返回。
推模式主要適合粉絲較少的小用戶(hù)晶默,因?yàn)樗麄兊姆劢z量少谨娜,使用推模式產(chǎn)生的冗余副本也比較少,并且可以減少用戶(hù)訪(fǎng)問(wèn)的壓力磺陡。
拉模式主要適合大v瞧预,因?yàn)楹芏嘟┦酆头腔钴S用戶(hù)根本不需要推送信息,用推模式發(fā)給這些僵尸粉或者非活躍用戶(hù)就是浪費(fèi)資源仅政。所以讓用戶(hù)通過(guò)拉模式請(qǐng)求垢油,只需要一個(gè)數(shù)據(jù)副本即可。同時(shí)如果是熱點(diǎn)信息圆丹,這些信息也可以放在緩存滩愁,讓用戶(hù)首先拉取這些信息,提高查詢(xún)效率辫封。
使用feedhandler異步處理上述的兩個(gè)事件硝枉,當(dāng)事件發(fā)生時(shí),根據(jù)事件實(shí)體進(jìn)行重新包裝倦微,構(gòu)造一個(gè)新鮮事妻味,因?yàn)樗行迈r事的格式是一樣的。需要包括:日期欣福,新鮮事類(lèi)型责球,發(fā)起者,新鮮事內(nèi)容,然后把該數(shù)據(jù)存入數(shù)據(jù)庫(kù)雏逾,以便用戶(hù)使用pull模式拉出嘉裤。
為了適配推送模式,此時(shí)也要把新鮮事放到該用戶(hù)所有粉絲的timeline里栖博,這樣的話(huà)就同時(shí)實(shí)現(xiàn)了推和拉的操作了屑宠。
使用爬蟲(chóng)爬取數(shù)據(jù),對(duì)網(wǎng)站進(jìn)行數(shù)據(jù)填充
安裝python3.x并且配置環(huán)境變量仇让。同時(shí)安裝pycharm,安裝pip典奉。
安裝好以后,先熟悉python的語(yǔ)法丧叽,寫(xiě)一些例子秋柄,比如數(shù)據(jù)類(lèi)型,操作符蠢正,方法調(diào)用骇笔,以及面向?qū)ο蟮募夹g(shù)。
因?yàn)閿?shù)據(jù)是要導(dǎo)入數(shù)據(jù)庫(kù)的嚣崭,所以這里安裝MySQLdb的一個(gè)庫(kù)笨触,并且寫(xiě)一下連接數(shù)據(jù)庫(kù)的代碼,寫(xiě)一下簡(jiǎn)單的crud進(jìn)行測(cè)試雹舀。
使用requests庫(kù)作為解析http請(qǐng)求的工具芦劣,使用beautifulsoup作為解析html代碼的工具,請(qǐng)求之后直接使用css選擇器匹配说榆。即可獲得內(nèi)容虚吟。
當(dāng)然現(xiàn)在我們有更方便的工具pyspider,可以方便解析請(qǐng)求并且可以設(shè)置代理签财,偽裝身份等串慰,直接傳入url并且寫(xiě)好多級(jí)的解析函數(shù),程序便會(huì)迭代執(zhí)行唱蒸,直到把所有頁(yè)面的內(nèi)容解析出來(lái)邦鲫。這里我們直接啟動(dòng)pyspider的web應(yīng)用并且寫(xiě)好python代碼,就可以執(zhí)行爬蟲(chóng)了神汹。
知乎:先找到問(wèn)題庆捺,再把問(wèn)題下所有的回答進(jìn)行爬取,最后把問(wèn)題和評(píng)論一起處理屁魏。
功能擴(kuò)展以及深度擴(kuò)展
功能擴(kuò)展
- 用戶(hù)注冊(cè)滔以,郵箱激活流程
- 管理員后臺(tái)管理
- timeline推拉結(jié)合
- 個(gè)性化首頁(yè),timeline更多事件
深度擴(kuò)展
- 搜索結(jié)果排序打分
- 爬蟲(chóng)覆蓋用戶(hù)氓拼,評(píng)論你画,內(nèi)容去html標(biāo)簽
- 個(gè)性化推薦