From 144a55c1cffb5af267ad1ad7c7c569013b43f021 Mon Sep 17 00:00:00 2001
From: zhangsan <646228430@qq.com>
Date: Thu, 13 Mar 2025 18:27:29 +0800
Subject: [PATCH] =?UTF-8?q?3.13=20=E5=88=86=E5=B8=83=E5=BC=8F=E7=BC=93?=
=?UTF-8?q?=E5=AD=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 15 +++++
.../controller/PictureController.java | 64 +++++++++++++++++++
src/main/resources/application.yml | 7 ++
.../smilepicturebackend/RedisStringTest.java | 48 ++++++++++++++
4 files changed, 134 insertions(+)
create mode 100644 src/test/java/edu/whut/smilepicturebackend/RedisStringTest.java
diff --git a/pom.xml b/pom.xml
index 7468a95..14b2e0d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,21 @@
jsoup
1.15.3
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+ com.github.ben-manes.caffeine
+ caffeine
+ 3.1.8
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+
com.mysql
mysql-connector-j
diff --git a/src/main/java/edu/whut/smilepicturebackend/controller/PictureController.java b/src/main/java/edu/whut/smilepicturebackend/controller/PictureController.java
index 714ec0f..34447ed 100644
--- a/src/main/java/edu/whut/smilepicturebackend/controller/PictureController.java
+++ b/src/main/java/edu/whut/smilepicturebackend/controller/PictureController.java
@@ -1,7 +1,10 @@
package edu.whut.smilepicturebackend.controller;
+import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
import edu.whut.smilepicturebackend.annotation.AuthCheck;
import edu.whut.smilepicturebackend.common.BaseResponse;
import edu.whut.smilepicturebackend.common.DeleteRequest;
@@ -21,12 +24,17 @@ import edu.whut.smilepicturebackend.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
+import java.time.Duration;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.TimeUnit;
@Slf4j
@RestController
@@ -35,6 +43,16 @@ import java.util.List;
public class PictureController {
private final UserService userService;
private final PictureService pictureService;
+ private final StringRedisTemplate stringRedisTemplate;
+
+ /**
+ * 本地缓存
+ */
+ private final Cache LOCAL_CACHE = Caffeine.newBuilder()
+ .initialCapacity(1024)
+ .maximumSize(10_000L) // 最大 10000 条
+ .expireAfterWrite(Duration.ofMinutes(5)) // 缓存 5 分钟后移除
+ .build();
/**
* 上传图片(可重新上传)
@@ -188,6 +206,52 @@ public class PictureController {
return ResultUtils.success(pictureService.getPictureVOPage(picturePage, request));
}
+ /**
+ * 分页获取图片列表(封装类,有缓存)
+ */
+ @Deprecated
+ @PostMapping("/list/page/vo/cache")
+ public BaseResponse> listPictureVOByPageWithCache(@RequestBody PictureQueryRequest pictureQueryRequest,
+ HttpServletRequest request) {
+ long current = pictureQueryRequest.getCurrent();
+ long size = pictureQueryRequest.getPageSize();
+ // 限制爬虫
+ ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
+ // 普通用户默认只能看到审核通过的数据
+ pictureQueryRequest.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
+ // 查询缓存,缓存中没有,再查询数据库
+ // 构建缓存的 key,根据查询条件来构建->json
+ String queryCondition = JSONUtil.toJsonStr(pictureQueryRequest); //json->md5,更轻量化,去除括号,双引号
+ String hashKey = DigestUtils.md5DigestAsHex(queryCondition.getBytes());
+ String cacheKey = String.format("smilepicture:listPictureVOByPage:%s", hashKey);
+// // 1. 先从本地缓存中查询
+// String cachedValue = LOCAL_CACHE.getIfPresent(cacheKey);
+// if (cachedValue != null) {
+// // 如果缓存命中,返回结果
+// Page cachedPage = JSONUtil.toBean(cachedValue, Page.class);
+// return ResultUtils.success(cachedPage);
+// }
+ // 2. 本地缓存未命中,查询 Redis 分布式缓存
+ ValueOperations opsForValue = stringRedisTemplate.opsForValue();
+ String cachedValue = opsForValue.get(cacheKey);
+ if (cachedValue != null) {
+ Page cachedPage = JSONUtil.toBean(cachedValue, Page.class);
+ return ResultUtils.success(cachedPage);
+ }
+ // 3. 查询数据库
+ Page picturePage = pictureService.page(new Page<>(current, size),
+ pictureService.getQueryWrapper(pictureQueryRequest));
+ Page pictureVOPage = pictureService.getPictureVOPage(picturePage, request);
+ // 4. 更新缓存
+ // 更新 Redis 缓存
+ String cacheValue = JSONUtil.toJsonStr(pictureVOPage);
+ // 设置缓存的过期时间,5 - 10 分钟过期,防止缓存雪崩!
+ int cacheExpireTime = 300 + RandomUtil.randomInt(0, 300);
+ opsForValue.set(cacheKey, cacheValue, cacheExpireTime, TimeUnit.SECONDS);
+ // 获取封装类
+ return ResultUtils.success(pictureVOPage);
+ }
+
/**
* 编辑图片(给用户使用)
*/
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 875a642..e12c7a3 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -14,6 +14,13 @@ spring:
url: jdbc:mysql://localhost:3306/smile-picture
username: root
password: 123456
+ # Redis 配置
+ redis:
+ database: 1
+ host: 127.0.0.1
+ port: 6379
+ password: 123456
+ timeout: 5000
servlet:
multipart:
max-file-size: 10MB
diff --git a/src/test/java/edu/whut/smilepicturebackend/RedisStringTest.java b/src/test/java/edu/whut/smilepicturebackend/RedisStringTest.java
new file mode 100644
index 0000000..af1d11e
--- /dev/null
+++ b/src/test/java/edu/whut/smilepicturebackend/RedisStringTest.java
@@ -0,0 +1,48 @@
+package edu.whut.smilepicturebackend;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@SpringBootTest
+public class RedisStringTest {
+ @Autowired
+ private StringRedisTemplate stringRedisTemplate;
+
+ @Test
+ public void testRedisStringOperations() {
+ // 获取操作对象
+ ValueOperations valueOps = stringRedisTemplate.opsForValue();
+
+ // Key 和 Value
+ String key = "testKey";
+ String value = "testValue";
+
+ // 1. 测试新增或更新操作
+ valueOps.set(key, value);
+ String storedValue = valueOps.get(key);
+ assertEquals(value, storedValue, "存储的值与预期不一致");
+
+ // 2. 测试修改操作
+ String updatedValue = "updatedValue";
+ valueOps.set(key, updatedValue);
+ storedValue = valueOps.get(key);
+ assertEquals(updatedValue, storedValue, "更新后的值与预期不一致");
+
+ // 3. 测试查询操作
+ storedValue = valueOps.get(key);
+ assertNotNull(storedValue, "查询的值为空");
+ assertEquals(updatedValue, storedValue, "查询的值与预期不一致");
+
+// // 4. 测试删除操作
+// redisTemplate.delete(key);
+// storedValue = valueOps.get(key);
+// assertNull(storedValue, "删除后的值不为空");
+ }
+}
\ No newline at end of file