You've already forked FrameTour-BE
feat(puzzle): 实现拼图模板缓存功能
- 集成 PuzzleRepository 缓存层替代直接数据库查询 - 在 PriceBiz 中使用缓存查询拼图模板数据 - 在 AppTemplateController 中添加景区模板封面URL批量获取接口 - 在 PuzzleTemplateServiceImpl 中实现模板增改时的缓存清理逻辑 - 在 FaceServiceImpl 中使用缓存查询拼图模板 - 优化模板查询性能并减少数据库压力
This commit is contained in:
@@ -15,6 +15,7 @@ import com.ycwl.basic.product.capability.ProductTypeCapability;
|
|||||||
import com.ycwl.basic.product.service.IProductTypeCapabilityManagementService;
|
import com.ycwl.basic.product.service.IProductTypeCapabilityManagementService;
|
||||||
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
|
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
|
||||||
import com.ycwl.basic.puzzle.mapper.PuzzleTemplateMapper;
|
import com.ycwl.basic.puzzle.mapper.PuzzleTemplateMapper;
|
||||||
|
import com.ycwl.basic.puzzle.repository.PuzzleRepository;
|
||||||
import com.ycwl.basic.repository.FaceRepository;
|
import com.ycwl.basic.repository.FaceRepository;
|
||||||
import com.ycwl.basic.repository.MemberRelationRepository;
|
import com.ycwl.basic.repository.MemberRelationRepository;
|
||||||
import com.ycwl.basic.repository.OrderRepository;
|
import com.ycwl.basic.repository.OrderRepository;
|
||||||
@@ -50,6 +51,8 @@ public class PriceBiz {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PuzzleTemplateMapper puzzleTemplateMapper;
|
private PuzzleTemplateMapper puzzleTemplateMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private PuzzleRepository puzzleRepository;
|
||||||
|
@Autowired
|
||||||
private IProductTypeCapabilityManagementService productTypeCapabilityManagementService;
|
private IProductTypeCapabilityManagementService productTypeCapabilityManagementService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private OrderRepository orderRepository;
|
private OrderRepository orderRepository;
|
||||||
@@ -74,8 +77,8 @@ public class PriceBiz {
|
|||||||
goodsList.add(new GoodsListRespVO(2L, "照片集", 2));
|
goodsList.add(new GoodsListRespVO(2L, "照片集", 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 拼图
|
// 拼图(使用缓存)
|
||||||
puzzleTemplateMapper.list(scenicId, null, 1).forEach(puzzleTemplate -> {
|
puzzleRepository.listTemplateByScenic(scenicId).forEach(puzzleTemplate -> {
|
||||||
GoodsListRespVO goods = new GoodsListRespVO();
|
GoodsListRespVO goods = new GoodsListRespVO();
|
||||||
goods.setGoodsId(puzzleTemplate.getId());
|
goods.setGoodsId(puzzleTemplate.getId());
|
||||||
goods.setGoodsName(puzzleTemplate.getName());
|
goods.setGoodsName(puzzleTemplate.getName());
|
||||||
@@ -131,7 +134,7 @@ public class PriceBiz {
|
|||||||
|
|
||||||
case "PHOTO_LOG":
|
case "PHOTO_LOG":
|
||||||
// 从 template 表查询pLog模板
|
// 从 template 表查询pLog模板
|
||||||
List<PuzzleTemplateEntity> puzzleList = puzzleTemplateMapper.list(scenicId, null, null);
|
List<PuzzleTemplateEntity> puzzleList = puzzleRepository.listTemplateByScenic(scenicId);
|
||||||
puzzleList.stream()
|
puzzleList.stream()
|
||||||
.map(template -> new SimpleGoodsRespVO(template.getId(), template.getName(), productType))
|
.map(template -> new SimpleGoodsRespVO(template.getId(), template.getName(), productType))
|
||||||
.forEach(goodsList::add);
|
.forEach(goodsList::add);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.ycwl.basic.controller.mobile;
|
package com.ycwl.basic.controller.mobile;
|
||||||
|
|
||||||
import com.ycwl.basic.mapper.TemplateMapper;
|
|
||||||
import com.ycwl.basic.model.pc.template.entity.TemplateEntity;
|
|
||||||
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||||
|
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
|
||||||
|
import com.ycwl.basic.puzzle.repository.PuzzleRepository;
|
||||||
import com.ycwl.basic.repository.TemplateRepository;
|
import com.ycwl.basic.repository.TemplateRepository;
|
||||||
import com.ycwl.basic.utils.ApiResponse;
|
import com.ycwl.basic.utils.ApiResponse;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -11,6 +11,10 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移动端模板接口
|
* 移动端模板接口
|
||||||
*/
|
*/
|
||||||
@@ -20,6 +24,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
public class AppTemplateController {
|
public class AppTemplateController {
|
||||||
|
|
||||||
private final TemplateRepository templateRepository;
|
private final TemplateRepository templateRepository;
|
||||||
|
private final PuzzleRepository puzzleRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据模板ID获取封面URL
|
* 根据模板ID获取封面URL
|
||||||
@@ -45,4 +50,37 @@ public class AppTemplateController {
|
|||||||
|
|
||||||
return ApiResponse.success(coverUrl);
|
return ApiResponse.success(coverUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据景区ID获取所有模板封面URL列表(用于前端预缓存)
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 模板封面URL列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/scenic/{scenicId}/covers")
|
||||||
|
public ApiResponse<List<String>> getScenicTemplateCoverUrls(@PathVariable("scenicId") Long scenicId) {
|
||||||
|
if (scenicId == null) {
|
||||||
|
return ApiResponse.fail("景区ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> coverUrls = new ArrayList<>();
|
||||||
|
|
||||||
|
// 获取普通模板封面
|
||||||
|
List<TemplateRespVO> templateList = templateRepository.getTemplateListByScenicId(scenicId);
|
||||||
|
templateList.stream()
|
||||||
|
.map(TemplateRespVO::getCoverUrl)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(url -> !url.isEmpty())
|
||||||
|
.forEach(coverUrls::add);
|
||||||
|
|
||||||
|
// 获取拼图模板封面(使用缓存)
|
||||||
|
List<PuzzleTemplateEntity> puzzleTemplateList = puzzleRepository.listTemplateByScenic(scenicId);
|
||||||
|
puzzleTemplateList.stream()
|
||||||
|
.map(PuzzleTemplateEntity::getCoverImage)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(url -> !url.isEmpty())
|
||||||
|
.forEach(coverUrls::add);
|
||||||
|
|
||||||
|
return ApiResponse.success(coverUrls);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ public class PuzzleTemplateServiceImpl implements IPuzzleTemplateService {
|
|||||||
entity.setDeleted(0);
|
entity.setDeleted(0);
|
||||||
templateMapper.insert(entity);
|
templateMapper.insert(entity);
|
||||||
|
|
||||||
|
// 清除景区模板列表缓存
|
||||||
|
if (entity.getScenicId() != null) {
|
||||||
|
puzzleRepository.clearTemplateByScenicCache(entity.getScenicId());
|
||||||
|
}
|
||||||
|
|
||||||
log.info("拼图模板创建成功: id={}, code={}", entity.getId(), entity.getCode());
|
log.info("拼图模板创建成功: id={}, code={}", entity.getId(), entity.getCode());
|
||||||
return entity.getId();
|
return entity.getId();
|
||||||
}
|
}
|
||||||
@@ -71,8 +76,11 @@ public class PuzzleTemplateServiceImpl implements IPuzzleTemplateService {
|
|||||||
throw new IllegalArgumentException("模板不存在: " + id);
|
throw new IllegalArgumentException("模板不存在: " + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果修改了编码,检查新编码是否已存在
|
// 记录旧值
|
||||||
String oldCode = existing.getCode();
|
String oldCode = existing.getCode();
|
||||||
|
Long oldScenicId = existing.getScenicId();
|
||||||
|
|
||||||
|
// 如果修改了编码,检查新编码是否已存在
|
||||||
if (request.getCode() != null && !request.getCode().equals(existing.getCode())) {
|
if (request.getCode() != null && !request.getCode().equals(existing.getCode())) {
|
||||||
int count = templateMapper.countByCode(request.getCode(), id);
|
int count = templateMapper.countByCode(request.getCode(), id);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
@@ -85,12 +93,18 @@ public class PuzzleTemplateServiceImpl implements IPuzzleTemplateService {
|
|||||||
entity.setId(id);
|
entity.setId(id);
|
||||||
templateMapper.update(entity);
|
templateMapper.update(entity);
|
||||||
|
|
||||||
// 清除缓存(如果修改了code,需要同时清除新旧code的缓存)
|
// 清除缓存
|
||||||
puzzleRepository.clearTemplateCache(id, oldCode);
|
puzzleRepository.clearTemplateCache(id, oldCode);
|
||||||
if (request.getCode() != null && !request.getCode().equals(oldCode)) {
|
if (request.getCode() != null && !request.getCode().equals(oldCode)) {
|
||||||
puzzleRepository.clearTemplateCache(null, request.getCode());
|
puzzleRepository.clearTemplateCache(null, request.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果 scenicId 变更,清除新旧两个景区的缓存
|
||||||
|
Long newScenicId = request.getScenicId();
|
||||||
|
if (newScenicId != null && !newScenicId.equals(oldScenicId)) {
|
||||||
|
puzzleRepository.clearTemplateByScenicCache(newScenicId);
|
||||||
|
}
|
||||||
|
|
||||||
log.info("拼图模板更新成功: id={}", id);
|
log.info("拼图模板更新成功: id={}", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import com.ycwl.basic.puzzle.entity.PuzzleGenerationRecordEntity;
|
|||||||
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
|
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
|
||||||
import com.ycwl.basic.puzzle.mapper.PuzzleGenerationRecordMapper;
|
import com.ycwl.basic.puzzle.mapper.PuzzleGenerationRecordMapper;
|
||||||
import com.ycwl.basic.puzzle.mapper.PuzzleTemplateMapper;
|
import com.ycwl.basic.puzzle.mapper.PuzzleTemplateMapper;
|
||||||
|
import com.ycwl.basic.puzzle.repository.PuzzleRepository;
|
||||||
import com.ycwl.basic.repository.DeviceRepository;
|
import com.ycwl.basic.repository.DeviceRepository;
|
||||||
import com.ycwl.basic.repository.FaceRepository;
|
import com.ycwl.basic.repository.FaceRepository;
|
||||||
import com.ycwl.basic.repository.MemberRelationRepository;
|
import com.ycwl.basic.repository.MemberRelationRepository;
|
||||||
@@ -204,6 +205,8 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PuzzleTemplateMapper puzzleTemplateMapper;
|
private PuzzleTemplateMapper puzzleTemplateMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private PuzzleRepository puzzleRepository;
|
||||||
|
@Autowired
|
||||||
private FaceDetectLogAiCamService faceDetectLogAiCamService;
|
private FaceDetectLogAiCamService faceDetectLogAiCamService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private OrderRepository orderRepository;
|
private OrderRepository orderRepository;
|
||||||
@@ -523,7 +526,8 @@ public class FaceServiceImpl implements FaceService {
|
|||||||
}
|
}
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
List<PuzzleTemplateEntity> puzzleTemplateEntityList = puzzleTemplateMapper.list(face.getScenicId(), null, 1);
|
// 拼图模板(使用缓存)
|
||||||
|
List<PuzzleTemplateEntity> puzzleTemplateEntityList = puzzleRepository.listTemplateByScenic(face.getScenicId());
|
||||||
if (!puzzleTemplateEntityList.isEmpty()) {
|
if (!puzzleTemplateEntityList.isEmpty()) {
|
||||||
List<PuzzleGenerationRecordEntity> records = puzzleGenerationRecordMapper.listByFaceId(faceId);
|
List<PuzzleGenerationRecordEntity> records = puzzleGenerationRecordMapper.listByFaceId(faceId);
|
||||||
PuzzleTemplateEntity template = puzzleTemplateEntityList.getFirst();
|
PuzzleTemplateEntity template = puzzleTemplateEntityList.getFirst();
|
||||||
|
|||||||
Reference in New Issue
Block a user