回味下自己幾年前寫的 “醬香代碼”
大家好,我是鲏。
從醬香拿鐵、醬香巧克力、再到醬香大床,最近茅臺(tái)真的是一步步刷新了大家的認(rèn)知。
但我若掏出自己幾年前的 “醬香代碼”,閣下如何應(yīng)對?!
還記得我在幾年前直播帶大家開發(fā)過一個(gè)表情包網(wǎng)站,網(wǎng)站名叫 “爸爸”、域名是 father.cool:
當(dāng)時(shí)這個(gè)網(wǎng)站用戶未萬,就中道崩殂了,主要的原因是流量費(fèi)、以及圖片內(nèi)容安全問題,后面我也就不再維護(hù)了,但是把代碼完全開源給了大家。
開源地址:https://github.com/liyupi/father
最近是在整理自己的原創(chuàng)文章時(shí),又發(fā)現(xiàn)了這個(gè)項(xiàng)目,所以決定再翻出來看看代碼。
俗話說,檢驗(yàn)一個(gè)程序員進(jìn)步的最好方式,就是讓他去評(píng)價(jià)自己之前寫過的代碼。
如果想吐槽 “這爛代碼誰寫的?!” 那么恭喜你,有進(jìn)步了!????
那接下來跟著魚皮一起來看看,當(dāng)年直播的時(shí)候?qū)懙臓€代碼吧,相信很多同學(xué)也都寫過。
前端
先把前端項(xiàng)目運(yùn)行起來,給大家看看效果。
打開依賴文件,發(fā)現(xiàn)這個(gè)項(xiàng)目我竟然用的是 Vue 3!
幾年前做這個(gè)項(xiàng)目的時(shí)候,應(yīng)該是 Vue 3 剛開始流行,所以我用了 Vue 3 來嘗個(gè)鮮:
接下來試著運(yùn)行下前端項(xiàng)目。但很不幸的是,代碼保質(zhì)期有限,用 npm 運(yùn)行的時(shí)候失敗了,換了 yarn 依賴管理才成功運(yùn)行。不得不感慨(吐槽),前端依賴升級(jí)的實(shí)在是太快了!
項(xiàng)目運(yùn)行后,長下面這個(gè) ?? 樣子:
左上角的裂圖是由于當(dāng)時(shí)項(xiàng)目 Logo 用的是網(wǎng)絡(luò)圖片,而不是放在本地的,后面這張圖片失效了所以無法顯示。
像 Logo 這種重要的圖片,還是老老實(shí)實(shí)放在 public 目錄下吧。
點(diǎn)擊圖片后,可以對圖片進(jìn)行編輯,比如添加文字等,制作自己的表情包:
不運(yùn)行后端也能使用,效果還是不錯(cuò)的:
后端
重點(diǎn)看下后端的代碼。
先看 pom.xml 依賴文件,幾年前項(xiàng)目用的就已經(jīng)是 Spring Boot 2.5 了,到現(xiàn)在 Spring Boot 2 還是主流,而且會(huì)持續(xù)很長一段時(shí)間。
依賴文件中引入了 Apache 的 httpclient,用來發(fā)送 Http 請求的工具包。但是這個(gè)庫其實(shí)是有坑的,所以后面我很少用這個(gè)包了,基本上會(huì)用 Hutool 工具庫來代替。
來看看項(xiàng)目結(jié)構(gòu),大多數(shù)類名還是比較規(guī)范的,見名知意。除了那個(gè) MyConstant 常量類。。。
當(dāng)時(shí)估計(jì)是偷懶了,就隨便起了個(gè)名字。定義常量時(shí)最好還是分個(gè)類,比如把用戶相關(guān)的常量放在 UserConstant 下。
打開一個(gè) Controller,在類名上有一行長長的 @CrossOrigin 注解,用來定義允許哪些域名跨域:
其實(shí)不太推薦使用這種在每個(gè)類上打注解的方式實(shí)現(xiàn)跨域,雖然方便,但是不利于后期的修改和維護(hù),因?yàn)槊看我暮芏囝悺?/p>
大多數(shù)情況下,對于同一個(gè)后端服務(wù)提供的接口,應(yīng)用的跨域規(guī)則是一致的。
所以后面很多項(xiàng)目我都采用統(tǒng)一的配置類來實(shí)現(xiàn)全局的跨域配置了:
再看 Controller 文件內(nèi)新增表情功能的實(shí)現(xiàn)代碼,非常的簡短,非常的樸實(shí)無華。
但其實(shí)問題也很大,當(dāng)時(shí)肯定是出于直播、為了快速實(shí)現(xiàn)功能才這么寫了,上述代碼存在至少 3 個(gè)問題:
1)直接用了實(shí)體類接收請求參數(shù),可能會(huì)導(dǎo)致調(diào)用方傳了一些不允許傳遞的參數(shù),比如傳遞 reviewStatus = 1 直接讓表情過審
2)未對字段做任何的校驗(yàn),直接插入到數(shù)據(jù)庫中了
3)沒有指定上傳用戶的 id。即使有些系統(tǒng)不要求登錄,也建議傳個(gè)能夠標(biāo)識(shí)用戶(或機(jī)器)的字段,比如 IP 地址,防止有小人惡意插入大量數(shù)據(jù)
其實(shí)判斷對象是否為 null 這行代碼也是可以優(yōu)化的:
可以自己封裝一個(gè)斷言工具類來拋異常,比如下列示例代碼:
AssertUtil.assertNotNull(emoji);
再接著看 Controller,在搜索表情接口中,竟然寫了老長一段封裝 SQL 查詢對象的代碼:
其實(shí)根據(jù)對象封裝查詢對象是一個(gè)通用邏輯,可以把它單獨(dú)提取出來作為一個(gè)方法,而不是寫在接口類中。Controller 層的代碼盡量保證精簡,盡量不要寫業(yè)務(wù)邏輯。
再看文件上傳功能,到第二行就繃不住了:
上面的代碼中,我用當(dāng)前時(shí)間 + 用戶上傳的原始文件名來拼接新的文件名,當(dāng)時(shí)應(yīng)該是圖省事兒,用這種方式保證文件名不重復(fù)。
但其實(shí),這種命名規(guī)則,是非常不利于文件維護(hù)的!最好使用 業(yè)務(wù)前綴 + 用戶標(biāo)識(shí) + 日期 等維度來拼接完整的文件路徑,便于檢索和遷移文件。
再往下看,當(dāng)時(shí)自己還手寫了很多工具類,比如下載圖片:
現(xiàn)在想想,挺天真的,明明用個(gè)工具類(比如 Hutool)一行代碼就搞定了。
再往下看,在 resources 目錄中有一個(gè) banner.txt 文件,這東西很有意思,可以允許你自定義啟動(dòng)項(xiàng)目時(shí)控制臺(tái)的輸出信息。
像我當(dāng)時(shí)用了個(gè)字符畫生成網(wǎng)站,生成了 Father 單詞對應(yīng)的字符畫,這就是屬于程序員的浪漫吧~
OK,就分享到這里,大家自己寫過的每個(gè)項(xiàng)目(哪怕是玩具)代碼都一定要留好,都是屬于自己的財(cái)富。多年之后回過頭來看看,真的會(huì)有一種別樣的快樂!
???? 點(diǎn)擊下方閱讀原文,獲取魚皮往期編程干貨
往期推薦
