3.13 分布式缓存
This commit is contained in:
parent
a6f7d83ecb
commit
144a55c1cf
15
pom.xml
15
pom.xml
@ -63,6 +63,21 @@
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.15.3</version>
|
||||
</dependency>
|
||||
<!-- Redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<!-- 本地缓存 Caffeine -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>3.1.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
|
@ -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<String, String> 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<Page<PictureVO>> 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<PictureVO> cachedPage = JSONUtil.toBean(cachedValue, Page.class);
|
||||
// return ResultUtils.success(cachedPage);
|
||||
// }
|
||||
// 2. 本地缓存未命中,查询 Redis 分布式缓存
|
||||
ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
|
||||
String cachedValue = opsForValue.get(cacheKey);
|
||||
if (cachedValue != null) {
|
||||
Page<PictureVO> cachedPage = JSONUtil.toBean(cachedValue, Page.class);
|
||||
return ResultUtils.success(cachedPage);
|
||||
}
|
||||
// 3. 查询数据库
|
||||
Page<Picture> picturePage = pictureService.page(new Page<>(current, size),
|
||||
pictureService.getQueryWrapper(pictureQueryRequest));
|
||||
Page<PictureVO> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑图片(给用户使用)
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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<String, String> 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, "删除后的值不为空");
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user