Spring Boot 整合 Redis 实现点赞功能:从基础到实践
在当今互联网应用开发中,点赞功能几乎成为了各类内容平台的标配。它不仅能增加用户与内容之间的互动,还能直观地反映内容的受欢迎程度。本文将详细介绍如何使用 Spring Boot 整合 Redis 来实现一个简单的文章点赞功能,让你轻松掌握这一实用技术。
一、Redis 简介
Redis 是一个开源的、基于内存的数据结构存储系统,它可以用作数据库、缓存和消息中间件。Redis 支持多种数据结构,如字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)等,这使得它在处理各种场景时都能表现出色。其高性能、低延迟的特性,使其成为处理点赞、缓存等高频读写场景的首选技术。
二、实验目的与任务
本次实验的核心目的是学习如何在 Spring Boot 项目中整合 Redis,实现一个简单而实用的文章点赞功能。具体任务为:当用户对一篇文章进行点赞操作时,点赞数在 Redis 缓存中实时加 1;当用户取消点赞时,点赞数减 1。所有数据都存储在 Redis 缓存中,以确保高效的读写操作。
三、实验内容与要求
(一)环境准备
- 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
- RedisDesktopManager 安装:
- RedisDesktopManager 是一个可视化操作 Redis 数据的工具,方便我们管理和查看 Redis 中的数据。
- 访问相关链接下载并完成安装,安装完成后即可使用它连接到 Redis 服务。
(二)Spring Boot 项目配置
- 引入依赖:在项目的 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。
(三)实现点赞功能
- 选择 Redis 数据类型:
- 对于文章点赞信息,我们选用 Set 数据结构。Set 具有唯一性,非常适合存储点赞用户的标识,能确保每个用户对同一篇文章只能点赞一次。键名格式为:article:{articleId}:likes。
- 为了统计点赞数量,我们使用 String 数据结构,键名格式为:article:like_count:{id}。
- 后端代码实现: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);}
}
- 前端代码实现:在 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>
四、步骤总结
- 完成 Redis 和 RedisDesktopManager 的安装,并确保 Redis 服务正常运行。
- 在 Spring Boot 项目中引入相关依赖,配置 Redis 属性。
- 编写后端代码,包括 Redis 配置类、文章服务类和控制器类,实现点赞和获取点赞数的业务逻辑。
- 编写前端代码,实现点赞按钮的交互逻辑,包括点赞状态切换和点赞数更新。
- 使用 Maven 命令 mvn clean install 下载项目所需的依赖项,并编译项目代码,然后通过 mvn spring-boot:run 启动项目。
- 使用 Postman 或浏览器访问相关 URL,验证项目功能是否正常。访问http://localhost:8080/article/{articleId}/like进行文章点赞操作等。
五、运行截图展示
运行 redis 截图:展示 Redis 服务启动后的界面,确保 Redis 正常运行。
运行文章界面:展示文章详情页面,包括文章标题、作者、内容等信息。
点赞文章界面:当用户点击点赞按钮后,展示点赞成功后的界面,点赞按钮样式改变,点赞数实时更新。
取消文章点赞界面:当用户再次点击已点赞的按钮取消点赞时,展示取消点赞后的界面,按钮样式恢复,点赞数相应减少。
通过以上步骤,我们成功实现了 Spring Boot 整合 Redis 的点赞功能。这一技术组合在实际项目中具有广泛的应用场景,希望本文能帮助你快速掌握并应用到实际开发中。如果在实践过程中有任何问题,欢迎在评论区留言交流。
相关文章:
Spring Boot 整合 Redis 实现点赞功能:从基础到实践
在当今互联网应用开发中,点赞功能几乎成为了各类内容平台的标配。它不仅能增加用户与内容之间的互动,还能直观地反映内容的受欢迎程度。本文将详细介绍如何使用 Spring Boot 整合 Redis 来实现一个简单的文章点赞功能,让你轻松掌握这一实用技…...
深入解析布尔注入:原理、实战与防御
目录 一、布尔注入的原理与核心逻辑 二、布尔注入的实战步骤 三、关键函数与绕过技巧 四、实战案例:获取数据库名称 五、防御策略与最佳实践 六、总结 一、布尔注入的原理与核心逻辑 布尔注入(Boolean-Based Blind SQL Injection)是一种…...
1.2 使用RawInputSharp来取得键盘硬件信息以及虚拟码
RawInputSharp 是一个 C# 库,用于处理 Windows 的原始输入(Raw Input) API,它允许开发者直接访问键盘、鼠标等输入设备的底层数据。 本例介绍如何读取键盘的虚拟码以及键盘硬件信息。效果如下图: 示例中:开始是1键的按下与抬起&am…...
C++23 中的可选扩展浮点类型:std::float{16|32|64|128}_t 和 std::bfloat16_t
文章目录 1. 扩展浮点类型概述2. 如何使用这些类型3. 编译器支持4. 特性测试宏5. 类型转换和重载决议6. 标准库支持7. 应用场景8. 总结 C23 引入了可选的扩展浮点类型,包括 std::float16_t、 std::float32_t、 std::float64_t、 std::float128_t 和 std::bfloa…...
JVM 内存调优
内存调优 内存泄漏(Memory Leak)和内存溢出(Memory Overflow)是两种常见的内存管理问题,它们都可能导致程序执行不正常或系统性能下降,但它们的原因和表现有所不同。 内存泄漏 内存泄漏(Memo…...
数据结构(java)栈与队列
栈:(先进后出) 入栈: 1.普通栈一定要放、最小栈放的原则是: *如果最小栈是空的,那么放 *如果最小栈的栈顶元素没有当前的元素小,则放 2.如果要放的的元素小于等于最小栈栈顶元素可以放吗?放 出栈: 需要…...
医疗大模型落地方案:技术选型、部署策略与调优
医疗大模型的落地应用已成为推动医疗行业数字化转型的重要引擎。本文将从技术选型、部署策略和调优方案三大维度,系统性地解析医疗大模型落地的关键要素,为医疗机构提供可操作的落地指南。随着人工智能技术的快速发展,医疗大模型已在影像诊断…...
JVM:类加载子系统
一、类加载子系统概述 类加载子系统由多个类加载器组成,它们负责从文件系统或者网络中读取二进制形式的字节码(.class)文件,并将其加载进 JVM。字节码文件中关于类的定义、类中属性的定义、类中方法的定义以及类中方法的字节码等…...
独家!美团2025校招大数据题库
推荐阅读文章列表 2025最新大数据开发面试笔记V6.0——试读 我的大数据学习之路 面试聊数仓第一季 题库目录 Java 1.写一个多线程代码 2.写一个单例代码 3.LinkedBlockingQueue原理 4.模板设计模式 5.如何设计一个 生产者-消费者队列 6.堆内存和栈内存 7.ThreadLo…...
Angular 框架详解:从入门到进阶
Hi,我是布兰妮甜 !在当今快速发展的 Web 开发领域,Angular 作为 Google 主导的企业级前端框架,以其完整的解决方案、强大的类型系统和丰富的生态系统,成为构建大型复杂应用的首选。不同于其他渐进式框架,An…...
使用Vue 3与.NET 8.0通过SignalR实现实时通信,并结合JWT身份验证
实时通信是一个非常重要的功能。SignalR是一个强大的库,能够帮助我们轻松实现客户端和服务器之间的实时数据传输。本文将结合你的代码示例,向你展示如何使用Vue 3作为前端框架,ASP.NET Core作为后端框架,通过SignalR实现实时消息通…...
Harmonyos-Navigation路由跳转
Harmonyos-Navigation路由跳转 概述Navigation路由跳转模块内页面路由系统路由表测试页代码创建并配置路由表文件配置创建好的路由表文件跳转页面 自定义路由表 跨模块路由封装库模块路由跳转工具类 概述 Navigation是路由容器组件,一般作为首页的根容器࿰…...
《人工智能应用创新》5天出审稿意见!
期刊简介 《人工智能应用创新(Innovative Applications of AI)》 (ISSN:3078-2147)是由香港修墨信息工程研究院举办,经国际同行评审后收录的学术期刊。本刊共分三个栏目:综述分析、应用示范、前…...
Excel数据自动填充到Word自定义表格
上一份工作在一家国企做软件测试,需求变来变去(3天一小改,5天换版面),xmind要先整理一遍测试用例(版本迭代,该废的废,该加的加),完了细节在禅道里补充&#x…...
Spring Boot一次接口请求涉及的完整执行链路
Spring Boot一次接口请求涉及的完整执行链路 🔁 Spring 项目请求执行链路(简化视图) 客户端请求(浏览器、Postman)↓ Tomcat(Servlet 容器)↓ 【Listener 监听器】↓ 【Filter 过滤器】&#x…...
mapbox基础,加载视频到地图
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️raster 栅格图层 api二、🍀加载视频到…...
Android动态化技术优化
Android动态化技术优化 一、WebView优化基础 1.1 WebView性能瓶颈 初始化耗时内存占用高页面加载慢白屏问题 1.2 WebView基本配置 class OptimizedWebView : WebView {init {// 开启硬件加速setLayerType(LAYER_TYPE_HARDWARE, null)// 配置WebSettingssettings.apply {//…...
Spring Boot 自定义定时任务组件深度解析:Quartz 集成与设计模式实战
一、组件设计目标 解决痛点: 简化 Quartz 原生 API 的复杂性统一任务调度管理(增删改查、日志、重试)与 Spring Boot 生态无缝整合 二、实现步骤详解 1. 组件初始化配置 1.1 初始化 Quartz 表结构 下载 SQL 脚本 🔗 官方表…...
Java Bean演进历程:从POJO到Spring Boot配置绑定
一、早期阶段:手动编写Java Bean 基本结构 私有属性:所有字段均为private,保证封装性。 公共构造方法:提供无参构造(JavaBean规范)或有参构造(POJO常见)。 Setter/Getter方法&…...
信息科技伦理与道德0:课程安排
1 课程安排 分组讨论的议题如下: 1.1 生成对抗网络(GAN) (1)GAN生成伪造人脸与身份冒用风险 算法原理: GAN通过生成器(Generator)和判别器(Discriminator)…...
STM32F103C8T6-基于FreeRTOS系统实现步进电机控制
引言 上一篇文章讲述了如何使用蓝牙连接stm32进行数据收发控制步进电机,这篇在之前的基础上通过移植操作系统(FreeRTOS或者其他的也可以,原理操作都类似)实现步进电机控制。 上篇博客指路:STM32蓝牙连接Android实现云…...
数字资产和交易解决方案
数字资产和交易解决方案 一、背景 (一)数字经济的蓬勃发展 随着信息技术的飞速发展,数字经济已成为全球经济增长的新引擎。数字资产作为数字经济的重要组成部分,其价值逐渐被人们所认识和重视。数字资产包括但不限于数字货币、…...
计算机网络 实验四 静态路由的配置与应用
一、实验目的 熟悉路由器的工作原理;熟悉静态路由的原理;熟悉华为网络模拟器的使用方法;掌握网络拓扑图的绘制;掌握路由器的配置。 二、实验设备 PC、华为模拟器ENSP。 三、实验步骤 知识准备:路由器和静态路由的…...
二进制求和 - 简单
************* C topic: 67. 二进制求和 - 力扣(LeetCode) ************* Give the topic an inspection. Too many works these days. And no spare time for code learning. However here I am gagin. This topic is an easy one and I want to pra…...
【C++】 —— 笔试刷题day_18
一、压缩字符串(一) 题目解析 题目给定一个字符str,让我们将这个字符串进行压缩; **压缩规则:**出现多次的字符压缩成字符数字;例如aaa压缩成a3。如果字符值出现一次,1不用写。 算法思路 这道题总的来说就非常简单了…...
LeetCode 热题 100_最长递增子序列(87_300_中等_C++)(动态规划)
LeetCode 热题 100_最长递增子序列(87_300) 题目描述:输入输出样例:题解:解题思路:思路一(动态规划): 代码实现代码实现(思路一(动态规划…...
asp-for等常用的HTML辅助标记?
在ASP.NET Core Razor Pages 和 MVC 中,除了asp-for之外,还有许多常用的 HTML 辅助标记,下面为你详细介绍: 表单与路由相关 asp-action 和 asp-controller 用途:这两个标记用于生成表单或链接的 URL,指定…...
map用法介绍
在 C 里,map是标准库提供的一种关联容器,它以键 - 值对的形式存储元素,并且按键的升序排列。下面为你展示如何在 C 用map。 如果没有用万能头的时候,需要加入#include 用法介绍: 映射[需要注意map的映射是1对1的不能出…...
AIGC-十款知识付费类智能体完整指令直接用(DeepSeek,豆包,千问,Kimi,GPT)
Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列AIGC(GPT、DeepSeek、豆包、千问、Kimi)👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资…...
一页概览:桌面虚拟化方案
2010年左右手绘的,用的是公司的信纸,马克笔。当时在买VMware和Citrix的桌面虚拟化方案,以及Wyse的瘦客户端。...
通过导入 Excel 的方式复制文件或文件夹
在进行文件或文件夹的批量整理时,许多人都会遇到需要将大量文件或文件夹复制到另一个文件夹中的问题。传统的手动复制粘贴方法不仅繁琐,而且效率低下。今天给大家介绍一种方法,可以实现将多个不同文件夹中的文件复制到一个或者多个文件夹&…...
Python单例设计模式深度解析
目录 一、什么是单例设计模式 核心特点 二、为什么需要单例模式 典型应用场景 优势对比 三、Python实现单例的三种方式 1. 使用__new__方法(经典实现) 2. 使用装饰器实现 3. 使用模块实现(Python特有) 四、深入理解__new…...
WPF 图标原地旋转
如何使元素原地旋转 - WPF .NET Framework | Microsoft Learn <ButtonRenderTransformOrigin"0.5,0.5"HorizontalAlignment"Left">Hello,World<Button.RenderTransform><RotateTransform x:Name"MyAnimatedTransform" Angle"…...
深入解析Java日志框架Logback:从原理到最佳实践
Logback作为Java领域最主流的日志框架之一,由Log4j创始人Ceki Glc设计开发,凭借其卓越的性能、灵活的配置以及与SLF4J的无缝集成,成为企业级应用开发的首选日志组件。本文将从架构设计、核心机制、配置优化等维度全面剖析Logback的技术细节。…...
【设计模式——装饰器模式】
在 Unity 游戏开发中,装饰模式是一种非常灵活的设计模式,用于在运行时动态地为对象添加功能。以下是装饰模式的设计思路和实现步骤,以角色的装备系统为例进行说明。 设计思路 装饰模式的核心思想是通过创建一个装饰器类来包装原有的对象&am…...
在 macOS 上切换默认 Java 版本
下载javasdk 打开android studio -> setting -> build.execution,dep -> build tools -> gradle -> Gradle JDK -> download JDK… 点击下载,就下载到了 ~/Library/Java/JavaVirtualMachines/ 安装 jenv brew install jenv将 jenv 集成到 Shell …...
【Linux网络与网络编程】11.数据链路层mac帧协议ARP协议
前面在介绍网络层时我们提出来过一个问题:主机是怎么把数据交给路由器的?那里我们说这是由数据链路层来做的。 网络上的报文在物理结构上是以mac帧的形式流动的,但在逻辑上是以IP流动的,IP的流动是需要mac帧支持的。 数据链路层解…...
158页PPT | 某大型研发制造集团信息化IT规划整体方案
该文档是某大型研发制造集团信息化IT规划整体方案,涵盖项目过程回顾、信息平台分析、现状评估、规划及治理建议和下阶段工作计划。项目旨在理解集团战略目标,评估信息化应用现状,制定可扩展的蓝图,明确未来3年管理与IT建设子项目&…...
ON DUPLICATE KEY UPDATE 更底层解释它的优势
从更底层来看,ON DUPLICATE KEY UPDATE 的优势主要源于以下几个方面: 1. 减少网络往返次数 先查询再更新:这种方式需要客户端和数据库服务器之间进行多次网络通信。首先,客户端发送一个 SELECT 查询请求,然后等待服务…...
Python 赋能区块链金融——从零构建智能交易系统
Python 赋能区块链金融——从零构建智能交易系统 引言:区块链金融系统的崛起 区块链技术正在颠覆传统金融体系,带来去中心化、透明化和高效的交易模式。从 DeFi(去中心化金融)到 NFT 市场,区块链金融系统已成为 Web 3.0 生态的重要支柱。如何用 Python 构建一个区块链金…...
基础(测试用例设计方法:流程图法,等价类划分法,边界值分析法,判定表法,正交分析法,错误推测法,其他方法,案例)
目录 流程图法(场景法) 业务流程 流程图 流程图法设计测试用例 案例-退款泳道图 案例-刷视频流程 等价类划分法 等价类 等价类设计测试用例 案例1-验证电话号码 案例2-验证邮箱格式 边界值分析法 测试数据的选取 边界值法设计测试用例 案例…...
QT —— 信号和槽(槽函数)
QT —— 信号和槽 信号和槽信号(Signal)槽(Slot)声明方式工作原理连接方式1. 传统连接方式(Qt4风格)2. 新式连接方式(Qt5风格) 区分槽函数和信号通过QtCreator生成信号槽代码自动生成槽函数显式连接的优势命名约定自动连接的局限性最佳实践建议结论 我们之前对QT,有…...
ROS2模块库概览
一、核心通信与基础库(最常用) 客户端库 rclcpp (ROS Client Library for C) 核心API:create_node(), create_publisher(), create_subscription()高级特性: 生命周期节点:通过rclcpp_lifecycle实现configure/activate…...
HADOOP——序列化
1.创建一个data目录在主目录下,并且在data目录下新建log.txt文件 2.新建flow软件包,在example软件包下 FlowBean package com.example.flow;import org.apache.hadoop.io.Writable;import java.io.DataInput; import java.io.DataOutput; import java.i…...
第五章 5.2ESP32物联网应用:HTTP与Web服务器详细教学
本文将详细讲解如何在ESP32上搭建Web服务器,通过HTTP协议实现远程控制LED灯。每行代码均有详细注释,适合零基础学习。 一、HTTP协议基础 HTTP是客户端(浏览器)和服务器之间的通信协议,常用请求方法: GET&a…...
c++11 绑定器bind
文章目录 std::bind 使用总结(C11)1. 绑定普通函数2. 使用占位符 _1, _2,调用时传参数3. 绑定类的成员函数(类外)4. 绑定类的成员函数(类内)5. 占位符结合成员函数小结 std::bind 使用总结&…...
实现时间最优轨迹生成/轨迹规划方法(TOTG),不使用moveit,可用于ROS驱动机械臂FollowJointTrajectoryGoal()
前言 在我的这篇文章:https://blog.csdn.net/weixin_45702459/article/details/139293391?spm1011.2415.3001.5331中,写了不使用moveit来ros驱动机械臂的方法,也就是用FollowJointTrajectoryGoal()来进行一系列点的关节运动,其实…...
2025年推荐使用的开源大语言模型top20:核心特性、选择指标和开源优势
李升伟 编译 随着人工智能技术的持续发展,开源大型语言模型(LLMs)正变得愈发强大,使最先进的AI能力得以普及。到2025年,开源生态系统中涌现出多个关键模型,它们在各类应用场景中展现出独特优势。 大型语言…...
高并发多级缓存架构实现思路
目录 1.整体架构 3.安装环境 1.1 使用docket安装redis 1.2 配置redis缓存链接: 1.3 使用redisTemplate实现 1.4 缓存注解优化 1.4.1 常用缓存注解简绍 1.4.2 EnableCaching注解的使用 1.4.3使用Cacheable 1.4.4CachePut注解的使用 1.4.5 优化 2.安装Ngin…...
Qt 的 事件队列
Qt 的 事件队列 是其核心事件处理机制之一,用于管理和分发系统与用户生成的事件(如鼠标点击、键盘输入、定时器、信号槽中的队列连接等)。理解 Qt 的事件队列对多线程、界面响应以及异步处理尤为关键。 一、Qt 的事件处理模型概览 Qt 是基于…...