Spring Boot 整合 Redis 實現點贊功能:從基礎到實踐

在當今互聯網應用開發中,點贊功能幾乎成為了各類內容平臺的標配。它不僅能增加用戶與內容之間的互動,還能直觀地反映內容的受歡迎程度。本文將詳細介紹如何使用 Spring Boot 整合 Redis 來實現一個簡單的文章點贊功能,讓你輕松掌握這一實用技術。

一、Redis 簡介

Redis 是一個開源的、基于內存的數據結構存儲系統,它可以用作數據庫、緩存和消息中間件。Redis 支持多種數據結構,如字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)等,這使得它在處理各種場景時都能表現出色。其高性能、低延遲的特性,使其成為處理點贊、緩存等高頻讀寫場景的首選技術。

二、實驗目的與任務

本次實驗的核心目的是學習如何在 Spring Boot 項目中整合 Redis,實現一個簡單而實用的文章點贊功能。具體任務為:當用戶對一篇文章進行點贊操作時,點贊數在 Redis 緩存中實時加 1;當用戶取消點贊時,點贊數減 1。所有數據都存儲在 Redis 緩存中,以確保高效的讀寫操作。

三、實驗內容與要求

(一)環境準備

  1. Redis 安裝
    • 可以選擇 Windows 版或 Linux 版的 Redis 進行安裝。對于有虛擬機或云服務器的同學,建議嘗試 Linux 版安裝,以更好地模擬生產環境。

Windows 版安裝步驟

D:
cd Redis
cd Redis-x64-3.2.100\
redis-server --service-install redis.windows.conf

?

  • 從下載地址下載 Redis-x64-3.2.100.msi 安裝包。
  • 將安裝包解壓到 D 盤的 Redis 文件夾中。
  • 打開 cmd 指令窗口,依次輸入以下命令啟動 Redis 服務:
  • 若要部署 Redis 在 Windows 下的服務,可輸入:
D:
cd Redis
cd Redis-x64-3.2.100\
redis-server --service-install redis.windows.conf

?

  1. RedisDesktopManager 安裝
    • RedisDesktopManager 是一個可視化操作 Redis 數據的工具,方便我們管理和查看 Redis 中的數據。
    • 訪問相關鏈接下載并完成安裝,安裝完成后即可使用它連接到 Redis 服務。

(二)Spring Boot 項目配置

  1. 引入依賴:在項目的 pom.xml 文件中引入 Spring Boot 整合 Redis 的相關依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

同時,為了構建完整的 Web 應用,還需引入 Spring Boot Web 和 Thymeleaf 等依賴:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

配置 Redis 屬性:在 src/main/resources/application.properties 文件中配置 Redis 相關屬性:

spring.redis.host=localhost
spring.redis.port=6379

這里假設 Redis 服務運行在本地,端口為默認的 6379。

(三)實現點贊功能

  1. 選擇 Redis 數據類型
    • 對于文章點贊信息,我們選用 Set 數據結構。Set 具有唯一性,非常適合存儲點贊用戶的標識,能確保每個用戶對同一篇文章只能點贊一次。鍵名格式為:article:{articleId}:likes。
    • 為了統計點贊數量,我們使用 String 數據結構,鍵名格式為:article:like_count:{id}。
  2. 后端代碼實現Redis 配置類:在 src/main/java/org/example/demo/config/RedisConfig.java 中配置 Redis 連接工廠和 RedisTemplate:
package org.example.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private int port;@Beanpublic RedisConnectionFactory redisConnectionFactory() {return new LettuceConnectionFactory(host, port);}@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new GenericJackson2JsonRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());return template;}
}
  • 文章服務類:在 src/main/java/org/example/demo/service/ArticleService.java 中實現點贊和獲取點贊數的業務邏輯:
package org.example.demo.service;import org.example.demo.model.Article;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class ArticleService {private static final Logger logger = LoggerFactory.getLogger(ArticleService.class);@Autowiredprivate RedisTemplate<String, Object> redisTemplate;// 點贊/取消點贊public int likeArticle(int id) {try {String key = "article:likes:" + id;if (redisTemplate.opsForSet().isMember(key, "liked")) {// 已點贊,取消點贊redisTemplate.opsForSet().remove(key, "liked");String countKey = "article:like_count:" + id;// 處理點贊數遞減可能出現的空指針問題if (redisTemplate.hasKey(countKey)) {redisTemplate.opsForValue().decrement(countKey);}return 0;} else {// 未點贊,進行點贊redisTemplate.opsForSet().add(key, "liked");redisTemplate.opsForValue().increment("article:like_count:" + id);return 1;}} catch (Exception e) {logger.error("Error occurred while liking or unliking article with id: {}", id, e);return -1; // 返回 -1 表示操作異常}}public long getArticleLikeCount(int id) {try {String key = "article:like_count:" + id;Object value = redisTemplate.opsForValue().get(key);if (value == null) {return 0;}if (value instanceof Long) {return (Long) value;} else if (value instanceof Integer) {return ((Integer) value).longValue();} else {logger.error("Unexpected data type for like count of article with id: {}. Value: {}", id, value);return 0;}} catch (Exception e) {logger.error("Error occurred while getting like count for article with id: {}", id, e);return 0;}}
}
  • 控制器類:在 src/main/java/org/example/demo/controller/MyController.java 中定義處理點贊請求的接口:
package org.example.demo.controller;import org.example.demo.model.Article;
import org.example.demo.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
public class MyController {@Autowiredprivate ArticleService articleService;@GetMapping("/article/{id}")public String getArticleById(@PathVariable int id, Model model) {// 根據文章ID查詢文章內容Article article = articleService.getArticleById(id);// 將文章內容傳遞給前端頁面model.addAttribute("article", article);return "article";}@GetMapping("/article/{id}/like")@ResponseBodypublic int judgment(@PathVariable int id) {return articleService.likeArticle(id);}@GetMapping("/article/{id}/likeCount")@ResponseBodypublic long getArticleLikeCount(@PathVariable int id) {return articleService.getArticleLikeCount(id);}
}
  1. 前端代碼實現:在 src/main/resources/templates/article.html 中實現點贊按鈕的交互邏輯:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>文章詳情</title><!-- 引入Bootstrap CSS --><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"><!-- 引入Font Awesome圖標庫 --><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"><style>.like-btn {margin-top: 10px;}/* 定義選中文章的樣式 */.active-article {color: #0dcaf0; /* 這里可以根據喜好設置顏色,比如淺藍色 */}</style>
</head><body>
<div class="container-fluid"><nav class="navbar navbar-expand-lg navbar-dark bg-dark"><div class="container-fluid"><a class="navbar-brand" href="#">文章列表</a><button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav"><li class="nav-item"><a class="nav-link" href="/article/1" onclick="highlightArticle(this)">文章一</a></li><li class="nav-item"><a class="nav-link" href="/article/2" onclick="highlightArticle(this)">文章二</a></li><li class="nav-item"><a class="nav-link" href="/article/3" onclick="highlightArticle(this)">文章三</a></li></ul></div></div></nav><div class="row"><div class="col-md-8 offset-md-2"><div class="card mt-4"><div class="card-body"><h1 class="card-title" th:text="${article.title}">Article Title</h1><p class="card-text text-muted">作者:<span th:text="${article.author}">Author</span>,出生時間:<span th:text="${article.date}">Date</span></p><p class="card-text" th:text="${article.content}">Article Content</p><button class="btn btn-primary like-btn" onclick="toggleLike()"><i class="fa-solid fa-thumbs-up"></i><span id="likeStatus0">點贊</span><span id="likeStatus1" style="display: none;">已點贊</span></button><span id="likeCount" class="ml-2"></span></div></div></div></div>
</div>
<!-- 引入Bootstrap JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>// 頁面加載時獲取點贊數量window.onload = function () {var articleId = window.location.pathname.split('/')[2];var xhr = new XMLHttpRequest();xhr.open('GET', '/article/' + articleId + '/likeCount', true);xhr.onreadystatechange = function () {if (xhr.readyState === XMLHttpRequest.DONE) {if (xhr.status === 200) {document.getElementById('likeCount').innerText = '點贊數:' + xhr.responseText;}}};xhr.send();}// 點贊按鈕點擊事件function toggleLike() {var articleId = window.location.pathname.split('/')[2];// 發送GET請求到后端var xhr = new XMLHttpRequest();xhr.open('GET', '/article/' + articleId + '/like', true);xhr.onreadystatechange = function () {if (xhr.readyState === XMLHttpRequest.DONE) {if (xhr.status === 200) {// 獲取后端返回的點贊狀態var likeStatus = parseInt(xhr.responseText);var likeStatus0 = document.getElementById('likeStatus0');var likeStatus1 = document.getElementById('likeStatus1');var likeBtn = document.querySelector('.like-btn');if (likeStatus === 1) {// 點贊成功console.log('點贊成功1');likeBtn.classList.remove('btn-primary');likeBtn.classList.add('btn-success');likeStatus0.style.display = 'none';likeStatus1.style.display = 'inline';} else {// 取消點贊console.log('取消點贊0');likeBtn.classList.remove('btn-success');likeBtn.classList.add('btn-primary');likeStatus0.style.display = 'inline';likeStatus1.style.display = 'none';}// 更新點贊數量var xhrCount = new XMLHttpRequest();xhrCount.open('GET', '/article/' + articleId + '/likeCount', true);xhrCount.onreadystatechange = function () {if (xhrCount.readyState === XMLHttpRequest.DONE) {if (xhrCount.status === 200) {document.getElementById('likeCount').innerText = '點贊數:' + xhrCount.responseText;}}};xhrCount.send();} else {console.error('請求失敗:' + xhr.status);}}};xhr.send();}// 點擊文章鏈接時高亮顯示當前文章function highlightArticle(link) {var navLinks = document.querySelectorAll('.navbar-nav a');navLinks.forEach(function (a) {a.classList.remove('active-article');});link.classList.add('active-article');}
</script>
</body></html>

四、步驟總結

  1. 完成 Redis 和 RedisDesktopManager 的安裝,并確保 Redis 服務正常運行。
  2. 在 Spring Boot 項目中引入相關依賴,配置 Redis 屬性。
  3. 編寫后端代碼,包括 Redis 配置類、文章服務類和控制器類,實現點贊和獲取點贊數的業務邏輯。
  4. 編寫前端代碼,實現點贊按鈕的交互邏輯,包括點贊狀態切換和點贊數更新。
  5. 使用 Maven 命令 mvn clean install 下載項目所需的依賴項,并編譯項目代碼,然后通過 mvn spring-boot:run 啟動項目。
  6. 使用 Postman 或瀏覽器訪問相關 URL,驗證項目功能是否正常。訪問http://localhost:8080/article/{articleId}/like進行文章點贊操作等。

五、運行截圖展示

運行 redis 截圖:展示 Redis 服務啟動后的界面,確保 Redis 正常運行。

運行文章界面:展示文章詳情頁面,包括文章標題、作者、內容等信息。

點贊文章界面:當用戶點擊點贊按鈕后,展示點贊成功后的界面,點贊按鈕樣式改變,點贊數實時更新。

取消文章點贊界面:當用戶再次點擊已點贊的按鈕取消點贊時,展示取消點贊后的界面,按鈕樣式恢復,點贊數相應減少。

通過以上步驟,我們成功實現了 Spring Boot 整合 Redis 的點贊功能。這一技術組合在實際項目中具有廣泛的應用場景,希望本文能幫助你快速掌握并應用到實際開發中。如果在實踐過程中有任何問題,歡迎在評論區留言交流。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/76009.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/76009.shtml
英文地址,請注明出處:http://en.pswp.cn/web/76009.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

openGauss DataVec + Dify,快速搭建你的智能助手平臺

在當今數字化和智能化的時代&#xff0c;大語言模型&#xff08;LLM&#xff09;的應用正以前所未有的速度改變著各個領域的工作方式和用戶體驗。Dify 作為一個開源的大語言模型應用開發平臺&#xff0c;為開發者們提供了便捷且強大的工具&#xff0c;助力構建從基礎智能體到復…

OpenLayers:extent與view extent 介紹

一、范圍的概念 1.什么是范圍&#xff1f; 在Openlayers中范圍&#xff08;Extent&#xff09;是用于表示地理空間區域的一種概念。它通常由一個數字數組構成&#xff0c;數組中的內容為&#xff1a;[最小x坐標&#xff0c;最小y坐標&#xff0c;最大x坐標&#xff0c;最大y坐…

can‘t set boot order in virtualbox

Boot order setting is ignored if UEFI is enabled https://forums.virtualbox.org/viewtopic.php?t99121 如果勾選EFI boot order就是灰色的 傳統BIOS就是可選的 然后選中任意介質&#xff0c;通過右邊的上下箭頭調節順序&#xff0c;最上面的應該是優先級最高的 然后就…

如何在 Kali 上解決使用 evil-winrm 時 Ruby Reline 的 quoting_detection_proc 警告

在使用 Kali Linux 運行 Ruby 工具&#xff08;例如 evil-winrm&#xff09;時&#xff0c;你可能會遇到以下警告&#xff1a; Warning: Remote path completions is disabled due to ruby limitation: undefined method quoting_detection_proc for module Reline這個警告會導…

工資管理系統的主要功能有哪些

工資管理系統通過自動化薪資計算、稅務處理、員工數據管理、報表生成等功能&#xff0c;極大地提升了薪資發放的效率和準確性。在傳統的人工薪資管理中&#xff0c;HR人員需要手動計算每位員工的薪資&#xff0c;并確保符合稅務要求&#xff0c;極易出錯且耗時。而現代工資管理…

C++語言程序設計——02 變量與數據類型

目錄 一、變量與數據類型&#xff08;一&#xff09;變量的數據類型&#xff08;二&#xff09;變量命名規則&#xff08;三&#xff09;定義變量&#xff08;四&#xff09;變量賦值&#xff08;五&#xff09;查看數據類型&#xff08;六&#xff09;數據類型的字節長度&…

咋用fliki的AI生成各類視頻?AI生成視頻教程

最近想制作視頻&#xff0c;多方考查了決定用fliki&#xff0c;于是訂閱了一年試試&#xff0c;這個AI生成的視頻效果來看真是不錯&#xff0c;感興趣的自己官網注冊個賬號體驗一下就知道了。 fliki官網 Fliki生成視頻教程 創建賬戶并登錄 首先&#xff0c;訪問fliki官網并注…

文章記單詞 | 第32篇(六級)

一&#xff0c;單詞釋義 inferior [?n?f??ri?(r)] adj. 較差的&#xff1b;次的&#xff1b;下級的&#xff1b;n. 下屬&#xff1b;次品joy [d???] n. 歡樂&#xff1b;喜悅&#xff1b;樂趣&#xff1b;樂事&#xff1b;v. 因… 而高興resemble [r??zembl] vt. 類…

windows上安裝Jenkins

1. 下載windows版 jenkins安裝包 2. 配置本地安全策略 在 Windows 11/10 上打開本地安全策略。 Secpol.msc 或本地安全策略編輯器是一個 Windows 管理工具&#xff0c;允許您在本地計算機上配置和管理與安全相關的策略。 安全設置-》本地策略-》用戶權限分配-》作為服務登錄…

dfs二叉樹中的深搜(回溯、剪枝)--力扣129、814、230、257

目錄 1.1題目鏈接&#xff1a;129.求根節點到葉結點數字之和 1.2題目描述&#xff1a;給你一個二叉樹的根節點 root &#xff0c;樹中每個節點都存放有一個 0 到 9 之間的數字。 1.3解法(dfs-前序遍歷)&#xff1a; 2.1題目鏈接&#xff1a;814.二叉樹剪枝 2.2題目描述&…

【樹形dp題解】dfs的巧妙應用

【樹形dp題解】dfs的巧妙應用 [P2986 USACO10MAR] Great Cow Gathering G - 洛谷 題目大意&#xff1a; Bessie 正在計劃一年一度的奶牛大集會&#xff0c;來自全國各地的奶牛將來參加這一次集會。當然&#xff0c;她會選擇最方便的地點來舉辦這次集會。 每個奶牛居住在 N N …

【c++深入系列】:new和delete運算符詳解

&#x1f525; 本文專欄&#xff1a;c &#x1f338;作者主頁&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客勵志語錄&#xff1a; “生活不會向你許諾什么&#xff0c;尤其不會向你許諾成功。它只會給你掙扎、痛苦和煎熬的過程。但只要你堅持下去&#xff0c;終有一天&…

Spring Boot 實現防盜鏈

在 Spring Boot 項目中實現防盜鏈可以通過多種方式&#xff0c;下面為你介紹兩種常見的實現方法&#xff0c;分別是基于請求頭 Referer 和基于令牌&#xff08;Token&#xff09;的防盜鏈。 基于請求頭 Referer 的防盜鏈 這種方法通過檢查請求頭中的 Referer 字段&#xff0c…

悄悄話識別、 打電話識別、攀高識別三種識別算法

在攝像頭正對場景下,悄悄話識別(唇語識別)、打電話識別和攀高識別是三種典型的行為檢測技術。以下從技術原理、算法模型、應用場景及挑戰等方面進行詳細分析: 一、悄悄話識別(唇語識別) 技術原理 唇語識別通過分析嘴唇的幾何特征(形狀、開合程度、運動軌跡)和動態變化…

centos部署的openstack發布windows虛擬機

?CentOS上部署的OpenStack可以發布Windows虛擬機?。在CentOS上部署OpenStack后&#xff0c;可以通過OpenStack平臺創建和管理Windows虛擬機。以下是具體的步驟和注意事項&#xff1a; ?安裝和配置OpenStack?&#xff1a; 首先&#xff0c;確保系統滿足OpenStack的最低硬件…

【電子通識】案例:電纜的安裝方式也會影響設備的可靠性?

背景 在日常生活中&#xff0c;我們常常會忽略一些看似微不足道的細節&#xff0c;但這些細節有時卻能決定設備的壽命和安全性。比如&#xff0c;你知道嗎&#xff1f;一根電纜的布置方式&#xff0c;可能會決定你的設備是否會因為冷凝水而損壞。 今天&#xff0c;我們就來聊聊…

【Web APIs】JavaScript 操作多個元素 ④ ( 表格全選復選框案例 )

文章目錄 一、核心要點解析 - 表格全選復選框案例1、案例需求2、復選框設置3、獲取 全選復選框 和 普通復選框4、設置 全選復選框 邏輯5、設置 普通復選框 邏輯 二、完整代碼示例1、代碼示例2、執行結果 一、核心要點解析 - 表格全選復選框案例 1、案例需求 在表格中 , 設置 多…

OpenAI發布GPT-4.1系列模型——開發者可免費使用

OpenAI剛剛推出GPT-4.1模型家族&#xff0c;包含GPT-4.1、GPT-4.1 Mini和GPT-4.1 Nano三款模型。重點是——現在全部免費開放&#xff01; 雖然技術升級值得關注&#xff0c;但真正具有變革意義的是開發者能通過Cursor、Windsurf和GitHub Copilot等平臺立即免費調用這些模型。…

《重構全球貿易體系用戶指南》解讀

文章目錄 背景核心矛盾與理論框架美元的“特里芬難題”核心矛盾目標理論框架 政策工具箱的協同運作機制關稅體系的精準打擊匯率政策的混合干預安全工具的復合運用 實施路徑與全球秩序重構階段性目標 風險傳導與反制效應內部失衡加劇外部反制升級系統性風險 范式突破與理論再思考…

磁盤清理-C盤

0.采用的工具——WizTree&#xff08;一定要以管理員身份運行&#xff09; 沒有以管理員身份運行時&#xff1a; 以管理員身份運行&#xff1a;&#xff08;查出很多之前沒有查出的文件&#xff09; 1.該死的優酷&#xff01;緩存占我11個G的內存 2.C 盤 Dell 文件夾下的 SARe…