一、項目概述
微頭條是一個基于現代技術棧構建的新聞發布和瀏覽平臺,旨在為用戶提供便捷的新聞閱讀體驗和高效的新聞管理功能。該項目通過前后端分離的架構設計,實現了用戶注冊、登錄、新聞瀏覽、搜索、發布、修改和刪除等功能,同時通過JWT技術保證了用戶認證的安全性和高效性。
二、業務功能
? 用戶功能
? 注冊功能:用戶可以通過填寫相關信息完成注冊,成為平臺的合法用戶。
? 登錄功能:用戶使用注冊的賬號和密碼登錄平臺,登錄成功后通過JWT生成并存儲token,用于后續的用戶身份驗證。
? JWT實現:利用JWT技術生成和校驗token,確保用戶在每次請求時都能被正確識別和授權。
? 頭條新聞功能
? 分頁瀏覽:新聞以分頁的形式展示,用戶可以通過翻頁查看更多的新聞內容,提高了瀏覽效率。
? 搜索功能:用戶可以通過輸入新聞標題的關鍵字進行搜索,快速找到感興趣的新聞。
? 新聞詳情:用戶點擊新聞標題可以查看新聞的詳細內容,包括新聞正文、發布時間等。
? 修改和刪除:用戶可以對自己發布的新聞進行修改和刪除操作,但無法修改或刪除其他用戶發布的新聞,體現了權限控制機制。
三、技術棧
? 前端技術棧
? ES6:作為基礎的JavaScript語法,提供更簡潔、高效的代碼編寫方式。
? Node.js:作為運行環境,支持前端項目的開發和運行。
? npm:作為項目依賴管理工具,方便管理和安裝項目所需的依賴包。
? Vite:作為項目構建工具,提供快速的開發體驗和高效的構建性能。
? Vue3:作為項目數據的渲染框架,實現數據的動態綁定和頁面的響應式更新。
? Axios:用于前后端數據的交互,通過發送HTTP請求獲取或提交數據。
? Vue Router:用于頁面的跳轉,實現單頁面應用的路由管理。
? Pinia:用于存儲用戶的數據,提供全局狀態管理。
? LocalStorage:作為用戶校驗token的存儲手段,確保用戶在瀏覽器端的安全性和持久性。
? Element-Plus:提供豐富的UI組件,提升頁面的美觀度和用戶體驗。
? 后端技術棧
? Java:作為開發語言,版本為JDK17,提供強大的編程能力和豐富的庫支持。
? Tomcat:作為服務容器,版本為10.1.7,用于部署和運行Java Web應用。
? MySQL 8:作為項目存儲數據的數據庫,提供高效的數據存儲和查詢功能。
? SpringMVC:用于控制層實現前后端數據交互,處理用戶的HTTP請求并返回響應。
? MyBatis-Plus:用于實現數據的CRUD操作,簡化數據庫訪問代碼。
? Druid:作為數據源的連接池,提供高效的數據庫連接管理和性能優化。
? Spring Boot:作為項目基礎架構,簡化Spring應用的初始搭建和開發過程。
? MD5:用于用戶密碼的加密,確保用戶密碼的安全性。
? JWT:用于token的生成和校驗,實現無狀態的用戶認證機制。
? Jackson:用于JSON數據的轉換,方便前后端數據的交互和處理。
四、項目優勢
? 用戶體驗:通過分頁瀏覽和關鍵字搜索功能,用戶可以快速找到感興趣的新聞,提升了瀏覽效率。
? 安全性:采用JWT技術進行用戶認證,結合MD5加密用戶密碼,確保了用戶數據的安全性。
? 開發效率:使用Vue3和Spring Boot等現代技術棧,提高了開發效率,降低了開發成本。
? 可擴展性:基于前后端分離的架構設計,便于后續功能的擴展和維護。
五、功能展示
? 頭條首頁信息搜索:用戶可以在首頁通過關鍵字搜索新聞,快速定位到感興趣的新聞內容。
? 登錄功能:用戶通過輸入賬號和密碼進行登錄,登錄成功后獲取token并存儲在LocalStorage中。
? 注冊功能:新用戶可以填寫相關信息完成注冊,注冊成功后即可登錄使用平臺。
? 新聞發布功能:用戶可以發布新的新聞,輸入標題和內容后提交至后端服務器。
? 新聞修改功能:用戶可以對自己發布的新聞進行修改,包括標題和內容的更新。
? 新聞刪除功能:用戶可以刪除自己發布的新聞,但無法刪除其他用戶發布的新聞,體現了權限控制機制。
微頭條項目通過合理的技術選型和功能設計,為用戶提供了一個安全、高效、易用的新聞發布和瀏覽平臺。
項目準備工作
前端項目創建:
通過網盤分享的文件:qianduan.zip
鏈接: https://pan.baidu.com/s/1synlG5QjepKxT_D-GioeEw?pwd=u4jn 提取碼: u4jn
1.將項目導入到vscode
2.運行代碼 下載所需要的依賴 下載完之后會出現這個文件夾
npm install
3.運行項目
npm run dev
創建數據庫
CREATE DATABASE sm_db;USE sm_db;SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for news_headline
-- ----------------------------
DROP TABLE IF EXISTS `news_headline`;
CREATE TABLE `news_headline` (`hid` INT NOT NULL AUTO_INCREMENT COMMENT '頭條id',`title` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '頭條標題',`article` VARCHAR(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '頭條新聞內容',`type` INT NOT NULL COMMENT '頭條類型id',`publisher` INT NOT NULL COMMENT '頭條發布用戶id',`page_views` INT NOT NULL COMMENT '頭條瀏覽量',`create_time` DATETIME(0) NULL DEFAULT NULL COMMENT '頭條發布時間',`update_time` DATETIME(0) NULL DEFAULT NULL COMMENT '頭條最后的修改時間',`version` INT DEFAULT 1 COMMENT '樂觀鎖',`is_deleted` INT DEFAULT 0 COMMENT '頭條是否被刪除 1 刪除 0 未刪除',PRIMARY KEY (`hid`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;-- ----------------------------
-- Records of news_headline
-- ----------------------------INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (5, '江南水鄉 龍舟競渡', '江南水鄉 龍舟競渡---6月18日,浙江省湖州市“我們的節日·端午”暨第七屆江南·民當端午民俗文化旅游節在南潯區和孚鎮民當村開幕,來自南潯區各個鄉鎮的農民選手在河道中賽龍舟、劃菱桶,體驗傳統端午民俗。', 1, 1, 0, '2023-06-25 09:32:13', '2023-06-25 09:32:13', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (6, '螃蟹粽、印花蛋、艾草涼粉……你知道端午有哪些創意美食嗎?', '端午有旅行路上的見聞,有詩畫里的藝術,也少不了舌尖上的風韻。聽風入夏粽香佐茶,您還知道端午有哪些創意美食嗎?端午至味,總少不了粽子這一味。甜的、咸的,肉餡的、蛋黃的、紅棗的、豆沙的……一起來尋味端午!\n\n 古人其實早就喜歡把各種果干放進粽子里,美食家蘇軾還發明了楊梅粽。《玉臺新詠》中說,“酒中喜桃子,粽里覓楊梅。”后來蘇軾曾借用過這個典故,在元祐三年所寫的端午帖子中說,“不獨盤中見盧橘,時于粽里得楊梅”。', 1, 1, 0, '2023-06-25 09:32:40', '2023-06-25 09:32:40', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (7, '尼克斯拒絕執行羅斯球隊選項 羅斯成自由球員', '北京時間6月25日,據多方消息源報道,尼克斯拒絕執行德里克-羅斯下賽季的球隊選項,羅斯成為完全自由球員。\n\n 34歲的羅斯在剛剛結束的賽季隊內角色嚴重下滑,他僅出戰27場比賽,場均登場12.5分鐘,得到5.6分1.5籃板1.7助攻。\n\n 2021年,羅斯與尼克斯簽下3年4300萬美元的續約合同,其中最后一年為1560萬美元球隊選項。', 2, 2, 0, '2023-06-25 09:34:26', '2023-06-25 09:34:26', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (8, '班凱羅承諾代表美國男籃打世界杯 名單僅差1人', '北京時間6月25日,據著名NBA記者沙姆斯-查拉尼亞報道,魔術前鋒保羅-班凱羅承諾將代表美國男籃參加2023年男籃世界杯。\n\n 班凱羅在剛剛結束的賽季場均能夠砍下20.0分6.9籃板3.7助攻,獲得了NBA2022-23賽季年度最佳新秀。', 2, 2, 0, '2023-06-25 09:34:59', '2023-06-25 09:34:59', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (9, 'F1加拿大大獎賽正賽:維斯塔潘冠軍 阿隆索亞軍', '2023年F1加拿大大獎賽正式比賽結束。紅牛車隊維斯塔潘桿位發車一路輕松領跑,再次完成了Pole-to-Win!這是紅牛車隊歷史上的第100座分站冠軍!同時也是維斯塔潘F1生涯的第41座分站冠軍,追平了“車神”埃爾頓·塞納的冠軍數!阿斯頓馬丁車隊阿隆索亞軍,梅賽德斯車隊漢密爾頓季軍。', 2, 2, 0, '2023-06-25 09:35:43', '2023-06-25 09:35:43', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (10, 'CTCC紹興柯橋站圓滿落幕 張志強曹宏煒各取一冠', '6月24日,2023賽季CTCC中國汽車場地職業聯賽紹興柯橋站在雨中的浙江國際賽車場上演了兩回合決賽的巔峰角逐。在線上線下觀眾的共同見證下,超級杯-TCR中國系列賽、運動杯-長三角賽車節聯袂獻上高水平對決,以精彩的比賽獻禮這個端午節假期!TCR 中國系列賽第三回合于今天上午率先開戰。來自殼牌捷凱領克車隊的張志強穿云破霧奪得冠軍;奪得該回合亞軍的是駕駛新賽車出戰的東風本田車手高度,季軍則由Z.SPEED N車隊的張臻東斬獲。這也是超級杯四冠王本賽季首次登臺。', 2, 2, 0, '2023-06-25 09:36:18', '2023-06-25 09:36:18', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (11, '國象聯賽常規賽收兵:杭州銀行第一 山東成功上岸', '6月17日,“武陵山大裂谷杯”中國國際象棋甲級聯賽常規賽在武陵云海國際酒店進行了最后一輪的爭奪,杭州銀行弈和山東隊,搶到常規賽的冠軍;山東隊也是憑借這場平局,成功脫離保級區。本輪最大的懸念是第八名的爭奪——在年底進行的甲級聯賽總決賽中,前八名為上半區爭冠組,保級無憂;而第九至十二名為保級區,不僅奪冠無望,還要為保級而苦戰。', 2, 2, 0, '2023-06-25 09:36:51', '2023-06-25 09:36:51', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (12, '圍棋名宿解讀高考作文:人生如棋 要先學會下“本手”', '今年高考開考了,在語文考試后,體育借勢沖上了社交媒體的熱搜榜。奧運相關話題進入高考,是意料之中。不過當記者看到關于圍棋術語“本手、妙手和俗手”的作文命題時,著實覺得有些難。在被迅速刷屏的朋友圈里,記者感受到了很多從業者的激動、興奮乃至油然而生的自豪感。但也有人則為那些沒學過棋的孩子感到擔心,這么難的題目,究竟該如何解題?\n\n “圍棋正在深入人心。題目有些難,‘俗手’如何定義?但確實應該先下好‘本手’。”翻到中國圍棋協會副主席、國家圍棋隊領隊華學明的這條朋友圈動態時,記者瞬間覺得這道公認的難題有了解題的思路。正如高考作文材料中所說,本手是基礎。只有持之以恒地打好基礎,補強短板,守住不發生系統性風險的底線,才有可能在本手的基礎上,下出妙手,避免俗手。而如果脫離了基礎,所謂的妙手很可能就是花拳繡腿,經不起推敲,更經不起對手的沖擊。世界冠軍柯潔表示:“很多人在對局中經常會拘泥于局部,下出假妙手。想下出真正的妙手,必須在平日里有一定的經驗積累和訓練,才可能完成真正卓越的妙手。”人生如棋,棋如人生。“其實人生中大部分時間都是在下本手”,圍棋名宿曹大元九段說。', 2, 2, 0, '2023-06-25 09:37:43', '2023-06-25 09:37:43', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (13, '不甘人后:被生成式AI彌漫的亞馬遜', '今年早些時候,隨著ChatGPT席卷全球,亞馬遜的經理們要求員工開動腦筋,想想如何使用人工智能(AI)聊天機器人技術來改進自家產品和工作流程。\n\n 其中一些想法被分享在一份名為《生成式AI——ChatGPT的影響和機會分析》的內部文件中。這份文件共列了ChatGPT和類似應用程序在亞馬遜多個團隊中的67個潛在應用案例。\n\n 早在20世紀90年代,亞馬遜就靠在網上賣書創造了互聯網界首個真正的商業奇跡。\n\n 隨后,Kindle閱讀器帶來革命性體驗,Alexa和Echo智能音箱又帶來了語音計算,而AWS則創造了云計算行業,ChatGPT就運行在這個行業之上。\n\n 但這次熱潮中拿到先發優勢的是同為科技大廠的微軟。微軟現在是OpenAI背后的金主,且還在忙著把ChatGPT的底層技術融進微軟產品和服務中。', 4, 5, 0, '2023-06-25 09:40:20', '2023-06-25 09:40:20', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (14, '微創新超實用:米家旅行箱居然想到了這一點', '旅行說走就走,除非老板沒安排。名義上是旅游,實則執行任務,對內講“為公司負重前行”,對外稱“帶薪游山玩水”,一介打工人,兩副撲克臉,個中苦樂誰人知!\n\n“差旅人”精明如我,隨身攜帶更偏向實用。\n\n必備日用之外,能路上買的盡量不帶,華而不實的東西,往包里多塞一個都算我輸。行李箱尺寸自然也要濃縮到小巧但夠裝的20英寸,拉著輕松又順手,常用小物件轉移到背包,“輕裝上戰場”。', 4, 5, 0, '2023-06-25 09:41:04', '2023-06-25 09:41:04', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (15, '小鵬G6動態試駕:輔助駕駛很驚喜', '這次我們開著小鵬G6上了賽道,又體驗了最新版本的高速NGP和城市NGP,小鵬,還順便測了下充電速度,那么小鵬G6駕駛感受如何?輔助駕駛表現怎么樣?', 4, 5, 0, '2023-06-25 09:42:07', '2023-06-25 09:42:07', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (16, '養車市場陷入低價內卷,“虎貓狗”還沒等到春天', '今年“618”期間,汽車后市場的玩家們都打出了“低價牌”。比如途虎養車宣布推出“6.18全民養車季”活動,在此期間北京車主可享受“輪胎買一送一”以及多品牌輪胎降價促銷的活動。\n\n 與此同時,京東養車和天貓養車兩大大廠玩家,在本次618期間也喊出了各自的營銷口號。\n\n 前者不僅喊出了“養車愛車立省不止30%”的口號,還推出了輪胎、保養買貴賠兩倍、“輪胎免費裝、三年無憂質保”、5公里無服務門店賠雙倍安裝費等舉措;天貓養車的618活動,則覆蓋了更大的零部件范圍,比如推出了空調清洗、機油和輪胎更換等低價服務。\n\n 這樣看,在本次618期間,途虎養車、京東養車和天貓養車均貫徹著“以價換量”的戰略,以至于讓行業價格戰一觸即發。這些玩家會這樣做,主要是為了與傳統4S店、以及與彼此競爭,以便保證自身獲得更多的市場份額。', 4, 5, 0, '2023-06-25 09:42:51', '2023-06-25 09:42:51', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (17, '微軟股價歷史新高 聊天機器人技術潛力顯現', '周四,微軟股價創下歷史新高,成為今年繼英偉達和蘋果之后,又一家市值達到新高點的大型科技公司。這家軟件巨頭正致力于在其產品和服務中添加生成式人工智能功能,旨在全面改造其Office產品陣容,其中包括Excel、PowerPoint、Outlook和Word等。股價上漲3.2%,收于每股348.1美元,為2021年11月19日以來的最高收盤價。自今年初起,微軟股價累計上漲了45%,市值增加約8006億美元。微軟持有OpenAI的大部分股份,這家初創公司憑借聊天機器人ChatGPT引發生成式人工智能的熱潮。近幾個月來,該工具廣受歡迎,展示了聊天機器人技術所具有的巨大潛力。微軟于今年1月宣布將再向OpenAI投資100億美元。然而有報道稱,微軟與OpenAI之間既有合作,亦存競爭,這種特殊的雙重關系導致了雙方關系的緊張和潛在沖突。科技股如英偉達等同樣受益于生成式人工智能技術的應用,各公司將此技術融入各自產品,進而推動相關芯片需求。英偉達股價今年已飆升192%,被視為最大贏家。', 4, 5, 0, '2023-06-25 09:43:48', '2023-06-25 09:43:48', 0);
INSERT INTO `news_headline` (hid,title,article,TYPE,publisher,page_views,create_time,update_time,is_deleted) VALUES (18, '再獲11億美元投資:蔚來“長期主義”的底氣', '如果說全系降價3萬是李斌的“陽謀”,那么蔚來ET5T的發布,則是李斌的又一次誠意之作。\n\n ET5T是蔚來首款售價下探到30萬元以下的新車,作為ET5的姐妹車型,ET5T和ET5的雙車合璧,得以在30萬以下快速開疆辟土。\n\n 這樣的做法有跡可循:特斯拉曾經在Model Y上實踐過,并大獲成功。\n\n Model Y和Model 3共用平臺,零部件復用率高達75%,研發成本驟降。盡管Model Y最初被用戶吐槽是Model 3的放大版,但不置可否的是Model Y確實解決了用戶對Model 3空間不足的槽點。\n\n 不過,最為關鍵的還是Model Y的價格足夠低,直接降低了特斯拉的購買門檻,給那些對價格敏感,本猶豫要不要多花四五萬的消費者一個充足的理由。\n\n 蔚來ET5T正在用一種經受了市場驗證過的方式,直面與特斯拉的競爭。但同時,蔚來ET5T在智能化、空間表現、設計以及產品力上,都正在接近、超越特斯拉Model Y。\n\n 蔚來ET5T,平替特斯拉Model Y?\n\n 小家庭,預算30萬左右,消費者到底會選哪款純電動車?\n\n 全球市場的反饋是,特斯拉Model Y ——一款緊湊型SUV。2022年,Model Y的全球銷量為74.7萬輛,其在中國的銷量為31.5萬臺,約占其全球份額的42.2%。\n\n 按照車型大小,SUV可以分為大型、中型、小型、緊湊型四大類。按照價位,SUV又可以分為實用型、經濟型、中高檔型、豪華型、超豪華型等。\n\n Model Y 在中高端SUV的細分市場中一騎絕塵,可以說是沒有對手。因為無論是奔馳EQC、寶馬iX3,還是國產的比亞迪唐EV等,和Model Y相比,都不能對其構成威脅。奔馳EQC、寶馬iX3這兩款車型都是“油改電”,算不上真正的電動車。而比亞迪的智能化能力,遠及不特斯拉,座艙、智駕上的核心模塊還來自于供應商方案,并非自研。\n\n 雷峰網認為,此前,國內的自主品牌中只有蔚來的ES6能和Model Y一較高下。不過ES6的均價比Model Y高出一大截,二者入門版之間的價差大約在10萬左右。但在蔚來推出ET5T后,局勢必然會發生逆轉。', 4, 5, 0, '2023-06-25 09:44:20', '2023-06-25 09:44:20', 0);-- ----------------------------
-- Table structure for news_type
-- ----------------------------
DROP TABLE IF EXISTS `news_type`;
CREATE TABLE `news_type` (`tid` INT NOT NULL AUTO_INCREMENT COMMENT '新聞類型id',`tname` VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '新聞類型描述',`version` INT DEFAULT 1 COMMENT '樂觀鎖',`is_deleted` INT DEFAULT 0 COMMENT '頭條是否被刪除 1 刪除 0 未刪除',PRIMARY KEY (`tid`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;-- ----------------------------
-- Records of news_type
-- ----------------------------
INSERT INTO `news_type` (tid,tname) VALUES (1, '新聞');
INSERT INTO `news_type` (tid,tname) VALUES (2, '體育');
INSERT INTO `news_type` (tid,tname) VALUES (3, '娛樂');
INSERT INTO `news_type` (tid,tname) VALUES (4, '科技');
INSERT INTO `news_type` (tid,tname) VALUES (5, '其他');-- ----------------------------
-- Table structure for news_user
-- ----------------------------
DROP TABLE IF EXISTS `news_user`;
CREATE TABLE `news_user` (`uid` INT NOT NULL AUTO_INCREMENT COMMENT '用戶id',`username` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用戶登錄名',`user_pwd` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用戶登錄密碼密文',`nick_name` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用戶昵稱',`version` INT DEFAULT 1 COMMENT '樂觀鎖',`is_deleted` INT DEFAULT 0 COMMENT '頭條是否被刪除 1 刪除 0 未刪除',PRIMARY KEY (`uid`) USING BTREE,UNIQUE INDEX `username_unique`(`username`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;-- ----------------------------
-- Records of news_user
-- ----------------------------
INSERT INTO `news_user` (uid,username,user_pwd,nick_name) VALUES (1, 'zhangsan', 'e10adc3949ba59abbe56e057f20f883e', '張三');
INSERT INTO `news_user` (uid,username,user_pwd,nick_name) VALUES (2, 'lisi', 'e10adc3949ba59abbe56e057f20f883e', '李四');
INSERT INTO `news_user` (uid,username,user_pwd,nick_name) VALUES (5, 'zhangxiaoming', 'e10adc3949ba59abbe56e057f20f883e', '張小明');
INSERT INTO `news_user` (uid,username,user_pwd,nick_name)VALUES (6, 'xiaohei', 'e10adc3949ba59abbe56e057f20f883e', '李小黑');SET FOREIGN_KEY_CHECKS = 1;
搭建SpringBoot項目
1.創建Springboot工程
2.導入pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.nie</groupId><artifactId>spring-weitoutiao</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.0.5</version></parent><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency><!-- 數據庫相關配置啟動器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- druid啟動器的依賴 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.18</version></dependency><!-- 驅動類--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.0</version></dependency></dependencies><!-- SpringBoot應用打包插件--><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
3.寫入配置 application.yml
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedruid:url: jdbc:mysql:///sm_dbusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverserver:port: 8080servlet:context-path: /mybatis-plus:type-aliases-package: com.nie.pojoglobal-config:db-config:logic-delete-field: isDeletedid-type: autotable-prefix: news_#jwt配置
jwt:token:tokenExpiration: 120 #有效時間,單位分鐘tokenSignKey: headline123456 #當前程序簽名秘鑰 自定義
4.druid兼容springboot3文件
文件名:org.springframework.boot.autoconfigure.AutoConfiguration.imports
內容:com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure
5.啟動類和mybatiesPlus配置
package com.nie;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;@SpringBootApplication
@MapperScan("com.nie.pojo")
public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}@Beanpublic MybatisPlusInterceptor getMybatisConfiguration() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();//配置分頁插件mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//配置樂觀鎖mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());//配置防止權標刪除mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());return mybatisPlusInterceptor;}}
6.工具類準備
6.1 封裝結果類
package com.nie.utils;/*** 全局統一返回結果類*/
public class Result<T> {// 返回碼private Integer code;// 返回消息private String message;// 返回數據private T data;public Result(){}// 返回數據protected static <T> Result<T> build(T data) {Result<T> result = new Result<T>();if (data != null)result.setData(data);return result;}public static <T> Result<T> build(T body, Integer code, String message) {Result<T> result = build(body);result.setCode(code);result.setMessage(message);return result;}public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {Result<T> result = build(body);result.setCode(resultCodeEnum.getCode());result.setMessage(resultCodeEnum.getMessage());return result;}/*** 操作成功* @param data baseCategory1List* @param <T>* @return*/public static<T> Result<T> ok(T data){Result<T> result = build(data);return build(data, ResultCodeEnum.SUCCESS);}public Result<T> message(String msg){this.setMessage(msg);return this;}public Result<T> code(Integer code){this.setCode(code);return this;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getData() {return data;}public void setData(T data) {this.data = data;}
}
6.2 枚舉類
package com.nie.utils;/*** 統一返回結果狀態信息類**/
public enum ResultCodeEnum {SUCCESS(200,"success"),USERNAME_ERROR(501,"usernameError"),PASSWORD_ERROR(503,"passwordError"),NOTLOGIN(504,"notLogin"),USERNAME_USED(505,"userNameUsed");private Integer code;private String message;private ResultCodeEnum(Integer code, String message) {this.code = code;this.message = message;}public Integer getCode() {return code;}public String getMessage() {return message;}
}
6.3 MD5加密工具類
package com.nie.utils;import org.springframework.stereotype.Component;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;@Component
public final class MD5Util {public static String encrypt(String strSrc) {try {char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'a', 'b', 'c', 'd', 'e', 'f' };byte[] bytes = strSrc.getBytes();MessageDigest md = MessageDigest.getInstance("MD5");md.update(bytes);bytes = md.digest();int j = bytes.length;char[] chars = new char[j * 2];int k = 0;for (int i = 0; i < bytes.length; i++) {byte b = bytes[i];chars[k++] = hexChars[b >>> 4 & 0xf];chars[k++] = hexChars[b & 0xf];}return new String(chars);} catch (NoSuchAlgorithmException e) {e.printStackTrace();throw new RuntimeException("MD5加密出錯!!+" + e);}}
}
MybatiesX插件生成service接口 service實現類 mapper.xml mapper接口
選中三個數據庫表 點擊第一個
配置路徑
選擇配置 點擊finish
添加主鍵,樂觀鎖,邏輯刪除注解!!!
用戶表:
package com.nie.pojo;import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;import java.io.Serializable;/*** @TableName news_user*/
@Data
public class User implements Serializable {@TableIdprivate Integer uid;private String username;private String userPwd;private String nickName;@Versionprivate Integer version;private Integer isDeleted;
}
類型表:
package com.nie.pojo;import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;import java.io.Serializable;/*** @TableName news_type*/@Data
public class Type implements Serializable {@TableIdprivate Integer tid;private String tname;@Versionprivate Integer version;private Integer isDeleted;
}
新聞表:
package com.nie.pojo;import com.baomidou.mybatisplus.annotation.*;import java.io.Serializable;
import java.util.Date;
import lombok.Data;/*** @TableName news_headline*/
@Data
public class Headline implements Serializable {@TableIdprivate Integer hid;private String title;private String article;private Integer type;private Integer publisher;private Integer pageViews;private Date createTime;private Date updateTime;@Versionprivate Integer version;private Integer isDeleted;
}
后臺功能開發
封裝JWT工具類
package com.nie.utils;import com.alibaba.druid.util.StringUtils;
import io.jsonwebtoken.*;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;import java.util.Date;@Data
@Component
@ConfigurationProperties(prefix = "jwt.token")
public class JwtHelper {// JWT 令牌的有效時間,單位為毫秒(1000毫秒 = 1秒)private long tokenExpiration;// JWT 簽名密鑰,用于生成和驗證 JWT 令牌private String tokenSignKey;/*** 生成 JWT 令牌字符串。* <p>* 這個方法根據用戶 ID 創建一個 JWT 令牌,并設置其有效時間和簽名。** @param userId 用戶的唯一標識* @return 生成的 JWT 令牌字符串*/public String createToken(Long userId) {System.out.println("tokenExpiration = " + tokenExpiration);System.out.println("tokenSignKey = " + tokenSignKey);String token = Jwts.builder().setSubject("YYGH-USER") // 設置主題(可以是任意字符串,用于標識令牌的用途).setExpiration(new Date(System.currentTimeMillis() + tokenExpiration * 1000 * 60)) // 設置令牌的有效時間(單位為分鐘).claim("userId", userId) // 添加用戶 ID 到 JWT 的自定義聲明中.signWith(SignatureAlgorithm.HS512, tokenSignKey) // 使用 HS512 算法和簽名密鑰對令牌進行簽名.compressWith(CompressionCodecs.GZIP) // 對 JWT 令牌進行壓縮.compact(); // 將 JWT 令牌轉換為緊湊的字符串形式return token;}/*** 從 JWT 令牌字符串中獲取用戶 ID。* <p>* 這個方法解析 JWT 令牌,并從其自定義聲明中提取用戶 ID。** @param token JWT 令牌字符串* @return 用戶 ID,如果令牌無效或為空,則返回 null*/public Long getUserId(String token) {if (StringUtils.isEmpty(token)) return null; // 如果令牌為空,直接返回 nullJws<Claims> claimsJws = Jwts.parser() // 解析 JWT 令牌.setSigningKey(tokenSignKey) // 設置簽名密鑰.parseClaimsJws(token); // 解析并驗證 JWT 令牌Claims claims = claimsJws.getBody(); // 獲取 JWT 的聲明部分Integer userId = (Integer) claims.get("userId"); // 從聲明中提取用戶 IDreturn userId.longValue(); // 返回用戶 ID 的長整型值}/*** 判斷 JWT 令牌是否過期。* <p>* 這個方法解析 JWT 令牌,并檢查其有效時間是否已經過期。** @param token JWT 令牌字符串* @return 如果令牌過期或無效,返回 true;否則返回 false*/public boolean isExpiration(String token) {try {boolean isExpire = Jwts.parser() // 解析 JWT 令牌.setSigningKey(tokenSignKey) // 設置簽名密鑰.parseClaimsJws(token) // 解析并驗證 JWT 令牌.getBody() // 獲取 JWT 的聲明部分.getExpiration() // 獲取令牌的有效時間.before(new Date()); // 檢查有效時間是否在當前時間之前// 如果沒有過期,返回 falsereturn isExpire;} catch (Exception e) {// 如果解析失敗或令牌過期,返回 truereturn true;}}
}
用戶模塊
controller
層
package com.nie.controller;import com.nie.pojo.User;
import com.nie.service.UserService;
import com.nie.utils.JwtHelper;
import com.nie.utils.Result;
import com.nie.utils.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("user")
@CrossOrigin
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate JwtHelper jwtHelper;@PostMapping("login")public Result login(@RequestBody User user) {Result result=userService.login(user);return result;}@GetMapping("getUserInfo")public Result getUserInfo(@RequestHeader String token){Result result=userService.getUserInfo(token);return result;}@PostMapping("checkUserName")public Result checkUserName(String username){Result result=userService.checkUserName(username);return result;}//注冊@PostMapping("regist")public Result regist(@RequestBody User user){Result result=userService.regist(user);return result;}//登陸檢查@GetMapping("checkLogin")public Result checkLogin(@RequestHeader String token){boolean expiration = jwtHelper.isExpiration(token);if (expiration) {return Result.build(null, ResultCodeEnum.NOTLOGIN);}return Result.ok(null);}
}
service
接口
package com.nie.service;import com.nie.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;
import com.nie.utils.Result;/**
* @author Administrator
* @description 針對表【news_user】的數據庫操作Service
* @createDate 2025-04-15 12:01:47
*/
public interface UserService extends IService<User> {Result login(User user);Result getUserInfo(String token);Result checkUserName(String username);Result regist(User user);
}
service
實現類
package com.nie.service.impl;import com.alibaba.druid.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nie.pojo.User;
import com.nie.service.UserService;
import com.nie.mapper.UserMapper;
import com.nie.utils.JwtHelper;
import com.nie.utils.MD5Util;
import com.nie.utils.Result;
import com.nie.utils.ResultCodeEnum;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;/**
* @author Administrator
* @description 針對表【news_user】的數據庫操作Service實現
* @createDate 2025-04-15 12:01:47
*/
@Service
@MapperScan("com.nie.mapper")
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{@Autowiredprivate UserMapper userMapper;@Autowiredprivate JwtHelper jwtHelper;@Overridepublic Result login(User user) {LambdaQueryWrapper<User> lambdaQueryWrappen=new LambdaQueryWrapper<>();lambdaQueryWrappen.eq(User::getUsername,user.getUsername());User loginUser = userMapper.selectOne(lambdaQueryWrappen);if (loginUser == null) {return Result.build(null, ResultCodeEnum.USERNAME_ERROR);}if (!StringUtils.isEmpty(user.getUserPwd()) && MD5Util.encrypt(user.getUserPwd()).equals(loginUser.getUserPwd())){String token = jwtHelper.createToken(Long.valueOf(loginUser.getUid()));Map data=new HashMap();data.put("token",token);return Result.ok(data);}return Result.build(null,ResultCodeEnum.PASSWORD_ERROR);}@Overridepublic Result getUserInfo(String token) {//判斷傳過來的token是否過期 true就是過期了boolean expiration = jwtHelper.isExpiration(token);if (expiration) {return Result.build(null,ResultCodeEnum.NOTLOGIN);}int userid = jwtHelper.getUserId(token).intValue();User user = userMapper.selectById(userid);user.setUserPwd("");Map data=new HashMap();data.put("loginUser",user);return Result.ok(data);}//是否可以注冊@Overridepublic Result checkUserName(String username) {LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(User::getUsername,username);Long count = userMapper.selectCount(lambdaQueryWrapper);if (count==0) {return Result.ok(null);}else{return Result.build(null,ResultCodeEnum.USERNAME_USED);}}//注冊業務@Overridepublic Result regist(User user) {LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(User::getUsername, user.getUsername());Long count = userMapper.selectCount(lambdaQueryWrapper);if (count > 0) {return Result.build(null, ResultCodeEnum.USERNAME_USED);}//密碼加密user.setUserPwd(MD5Util.encrypt(user.getUserPwd()));userMapper.insert(user);return Result.ok(null);}
}
mapper
接口
package com.nie.mapper;import com.nie.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;/**
* @author Administrator
* @description 針對表【news_user】的數據庫操作Mapper
* @createDate 2025-04-15 12:01:47
* @Entity com.nie.pojo.User
*/
public interface UserMapper extends BaseMapper<User> {}
mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nie.mapper.UserMapper"><resultMap id="BaseResultMap" type="com.nie.pojo.User"><id property="uid" column="uid" /><result property="username" column="username" /><result property="userPwd" column="user_pwd" /><result property="nickName" column="nick_name" /><result property="version" column="version" /><result property="isDeleted" column="is_deleted" /></resultMap><sql id="Base_Column_List">uid,username,user_pwd,nick_name,version,is_deleted</sql>
</mapper>
首頁模塊
配置分頁查詢實體類
package com.nie.pojo.vo;import lombok.Data;@Data
public class PortalVo {private String keyWords;private int type=0;private int pageNum=1;private int pageSize=10;}
controller
層
package com.nie.controller;import com.nie.pojo.vo.PortalVo;
import com.nie.service.HeadlineService;
import com.nie.service.TypeService;
import com.nie.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("portal")
@CrossOrigin
public class PortalController {@Autowiredprivate TypeService typeService;@Autowiredprivate HeadlineService headlineService;@GetMapping("findAllTypes")public Result findAllTypes(){Result result=typeService.findAllTypes();return result;}@PostMapping("findNewsPage")public Result findNewsPage(@RequestBody PortalVo portalVo){Result result=headlineService.findNewsPage(portalVo);return result;}@PostMapping("showHeadlineDetail")public Result showHeadlineDetail(Integer hid){Result result=headlineService.showHeadlineDetail(hid);return result;}
}
service
接口
package com.nie.service;import com.nie.pojo.Type;
import com.baomidou.mybatisplus.extension.service.IService;
import com.nie.utils.Result;/**
* @author Administrator
* @description 針對表【news_type】的數據庫操作Service
* @createDate 2025-04-15 12:01:47
*/
public interface TypeService extends IService<Type> {Result findAllTypes();
}
service
實現類
package com.nie.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nie.pojo.Type;
import com.nie.service.TypeService;
import com.nie.mapper.TypeMapper;
import com.nie.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/**
* @author Administrator
* @description 針對表【news_type】的數據庫操作Service實現
* @createDate 2025-04-15 12:01:47
*/
@Service
public class TypeServiceImpl extends ServiceImpl<TypeMapper, Type>implements TypeService{@Autowiredprivate TypeMapper typeMapper;@Overridepublic Result findAllTypes() {List<Type> types=typeMapper.selectList(null);return Result.ok(types);}
}
mapper
接口
package com.nie.mapper;import com.nie.pojo.Type;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;/**
* @author Administrator
* @description 針對表【news_type】的數據庫操作Mapper
* @createDate 2025-04-15 12:01:47
* @Entity com.nie.pojo.Type
*/
public interface TypeMapper extends BaseMapper<Type> {}
mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nie.mapper.TypeMapper"><resultMap id="BaseResultMap" type="com.nie.pojo.Type"><id property="tid" column="tid" /><result property="tname" column="tname" /><result property="version" column="version" /><result property="isDeleted" column="is_deleted" /></resultMap><sql id="Base_Column_List">tid,tname,version,is_deleted</sql>
</mapper>
頭條模塊
登陸驗證和保護
- 客戶端在進入發布頁前、發布新聞前、進入修改頁前、修改前、刪除新聞前先向服務端發送請求攜帶token請求頭
- 后端接收token請求頭后,校驗用戶登錄是否過期并做響應
- 前端根據響應信息提示用戶進入登錄頁還是進入正常業務頁面
controller
層
@GetMapping("checkLogin")
public Result checkLogin(@RequestHeader String token){if (StringUtils.isEmpty(token) || jwtHelper.isExpiration(token)){//沒有傳或者過期 未登錄return Result.build(null, ResultCodeEnum.NOTLOGIN);}return Result.ok(null);
}
攔截器
package com.nie.interceptors;import com.fasterxml.jackson.databind.ObjectMapper;
import com.nie.utils.JwtHelper;
import com.nie.utils.Result;
import com.nie.utils.ResultCodeEnum;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;@Component
public class LoginProtectedInterceptor implements HandlerInterceptor {// 自動注入 JwtHelper 工具類,用于處理 JWT 相關的邏輯@Autowiredprivate JwtHelper jwtHelper;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 從請求頭中獲取名為 "token" 的值String token = request.getHeader("token");// 調用 JwtHelper 的 isExpiration 方法,檢查 token 是否過期boolean expiration = jwtHelper.isExpiration(token);// 如果 token 未過期,允許請求繼續執行if (!expiration) {return true;}// 如果 token 過期或無效,創建一個未登錄的提示結果Result result = Result.build(null, ResultCodeEnum.NOTLOGIN);// 創建 ObjectMapper 對象,用于將 Result 對象轉換為 JSON 格式的字符串ObjectMapper objectMapper = new ObjectMapper();// 將 Result 對象轉換為 JSON 格式的字符串String json = objectMapper.writeValueAsString(result);// 將 JSON 字符串寫入響應體,返回給客戶端response.getWriter().print(json);// 返回 false,表示攔截請求,阻止請求繼續執行return false;}
}
配置攔截器 所有以headline開頭的路徑
package com.nie.config;import com.nie.interceptors.LoginProtectedInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate LoginProtectedInterceptor loginProtectedInterceptor;@Override/****添加攔截器*/public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginProtectedInterceptor).addPathPatterns("/headline/**");}
}
controller
層
package com.nie.controller;import com.nie.pojo.Headline;
import com.nie.service.HeadlineService;
import com.nie.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("headline")
@CrossOrigin
public class HeadlineController {@Autowiredprivate HeadlineService headlineService;@PostMapping("publish")public Result publish(@RequestBody Headline headline,@RequestHeader String token){Result result=headlineService.publish(headline,token);return result;}@PostMapping("findHeadlineByHid")public Result findHeadlineByHid(Integer hid){Headline headline = headlineService.getById(hid);Map map=new HashMap();map.put("headline",headline);return Result.ok(map);}@PostMapping("updata")public Result updata(@RequestBody Headline headline){Result result=headlineService.updateData(headline);return result;}@PostMapping("removeByHid")public Result removeByHid(Integer hid){Result result=headlineService.removeByHid(hid);return result;}
}
service
接口
package com.nie.service;import com.nie.pojo.Headline;
import com.baomidou.mybatisplus.extension.service.IService;
import com.nie.pojo.vo.PortalVo;
import com.nie.utils.Result;/**
* @author Administrator
* @description 針對表【news_headline】的數據庫操作Service
* @createDate 2025-04-15 12:01:47
*/
public interface HeadlineService extends IService<Headline> {Result findNewsPage(PortalVo portalVo);Result showHeadlineDetail(Integer hid);Result publish(Headline headline,String token);Result updateData(Headline headline);Result removeByHid(Integer hid);
}
service
實現類
package com.nie.service.impl;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nie.pojo.Headline;
import com.nie.pojo.vo.PortalVo;
import com.nie.service.HeadlineService;
import com.nie.mapper.HeadlineMapper;
import com.nie.utils.JwtHelper;
import com.nie.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/**
* @author Administrator
* @description 針對表【news_headline】的數據庫操作Service實現
* @createDate 2025-04-15 12:01:47
*/
@Service
public class HeadlineServiceImpl extends ServiceImpl<HeadlineMapper, Headline>implements HeadlineService{@Autowiredprivate HeadlineMapper headlineMapper;@Autowiredprivate JwtHelper jwtHelper;@Overridepublic Result findNewsPage(PortalVo portalVo) {IPage<Map> Page=new Page<>(portalVo.getPageNum(),portalVo.getPageSize());headlineMapper.selectMyPage(Page,portalVo);//獲取他里面的集合數據List<Map> records = Page.getRecords();Map data=new HashMap();data.put("pageData",records);data.put("pageNum",Page.getCurrent());data.put("pageSize",Page.getSize());data.put("totalPage",Page.getPages());data.put("totalSize",Page.getTotal());Map pageInfo=new HashMap();pageInfo.put("pageInfo",data);return Result.ok(pageInfo);}//根據ID查詢頭條詳情@Overridepublic Result showHeadlineDetail(Integer hid) {Map data=headlineMapper.queryDetailMap(hid);Map headline=new HashMap();headline.put("headline",data);//修改閱讀量加1Headline headline1=new Headline();headline1.setHid((Integer) data.get("hid"));headline1.setVersion((Integer) data.get("version"));//閱讀量+1headline1.setPageViews((Integer) data.get("pageViews")+1);headlineMapper.updateById(headline1);return Result.ok(headline);}@Overridepublic Result publish(Headline headline,String token) {//token查詢用戶idint userId = jwtHelper.getUserId(token).intValue();headline.setPublisher(userId);headline.setPageViews(0);headline.setCreateTime(new Date());headline.setUpdateTime(new Date());headlineMapper.insert(headline);return Result.ok(null);}@Overridepublic Result updateData(Headline headline) {Integer version = headlineMapper.selectById(headline.getHid()).getVersion();headline.setVersion(version);headline.setUpdateTime(new Date());headlineMapper.updateById(headline);return Result.ok(null);}@Overridepublic Result removeByHid(Integer hid) {headlineMapper.deleteById(hid);return Result.ok(null);}
}
mapper
接口
package com.nie.mapper;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nie.pojo.Headline;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.nie.pojo.vo.PortalVo;
import org.apache.ibatis.annotations.Param;import java.util.Map;/**
* @author Administrator
* @description 針對表【news_headline】的數據庫操作Mapper
* @createDate 2025-04-15 12:01:47
* @Entity com.nie.pojo.Headline
*/
public interface HeadlineMapper extends BaseMapper<Headline> {IPage<Map> selectMyPage(IPage page,@Param("portalVo") PortalVo portalVo);Map queryDetailMap(Integer hid);
}
mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nie.mapper.HeadlineMapper"><resultMap id="BaseResultMap" type="com.nie.pojo.Headline"><id property="hid" column="hid" /><result property="title" column="title" /><result property="article" column="article" /><result property="type" column="type" /><result property="publisher" column="publisher" /><result property="pageViews" column="page_views" /><result property="createTime" column="create_time" /><result property="updateTime" column="update_time" /><result property="version" column="version" /><result property="isDeleted" column="is_deleted" /></resultMap><sql id="Base_Column_List">hid,title,article,type,publisher,page_views,create_time,update_time,version,is_deleted</sql><select id="selectMyPage" resultType="map">select hid,title,type,page_views pageViews,TIMESTAMPDIFF(HOUR,create_time,NOW()) pastHours,publisher from news_headline where is_deleted=0<if test="portalVo.keyWords !=null and portalVo.keyWords.length()>0 ">and title like concat('%',#{portalVo.keyWords},'%')</if><if test="portalVo.type != null and portalVo.type != 0">and type = #{portalVo.type}</if></select><select id="queryDetailMap" resultType="java.util.Map">select hid,title,article,type, h.version ,tname typeName ,page_views pageViews,TIMESTAMPDIFF(HOUR,create_time,NOW()) pastHours,publisher,nick_name author from news_headline hleft join news_type t on h.type = t.tidleft join news_user u on h.publisher = u.uidwhere hid = #{hid}</select></mapper>