You've already forked FrameTour-BE
Merge branch 'refs/heads/order_v2'
# Conflicts: # src/main/java/com/ycwl/basic/controller/mobile/manage/AppScenicAccountController.java
This commit is contained in:
238
src/main/java/com/ycwl/basic/service/PriceCacheService.java
Normal file
238
src/main/java/com/ycwl/basic/service/PriceCacheService.java
Normal file
@@ -0,0 +1,238 @@
|
||||
package com.ycwl.basic.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ycwl.basic.pricing.dto.PriceCalculationResult;
|
||||
import com.ycwl.basic.pricing.dto.ProductItem;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 价格缓存服务
|
||||
* 使用 Redis 实现价格查询结果的缓存,缓存时间为5分钟
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PriceCacheService {
|
||||
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
// 缓存Key前缀
|
||||
private static final String CACHE_PREFIX = "pricing:cache:";
|
||||
|
||||
// 缓存过期时间:5分钟
|
||||
private static final Duration CACHE_DURATION = Duration.ofMinutes(5);
|
||||
|
||||
/**
|
||||
* 生成缓存键
|
||||
* 格式:pricing:cache:{userId}:{scenicId}:{productsHash}
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param scenicId 景区ID
|
||||
* @param products 商品列表
|
||||
* @return 缓存键
|
||||
*/
|
||||
public String generateCacheKey(Long userId, Long scenicId, List<ProductItem> products) {
|
||||
String productsHash = calculateProductsHash(products);
|
||||
return CACHE_PREFIX + userId + ":" + scenicId + ":" + productsHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算商品列表的哈希值
|
||||
* 基于商品类型、ID、购买数量等必传字段生成唯一哈希,忽略可选的quantity字段
|
||||
*
|
||||
* @param products 商品列表
|
||||
* @return 哈希值
|
||||
*/
|
||||
private String calculateProductsHash(List<ProductItem> products) {
|
||||
try {
|
||||
// 构建缓存用的商品信息字符串,只包含必传字段
|
||||
StringBuilder cacheInfo = new StringBuilder();
|
||||
for (ProductItem product : products) {
|
||||
cacheInfo.append(product.getProductType()).append(":")
|
||||
.append(product.getProductId()).append(":")
|
||||
.append(product.getPurchaseCount() != null ? product.getPurchaseCount() : 1).append(":")
|
||||
.append(product.getScenicId()).append(";");
|
||||
}
|
||||
|
||||
// 计算SHA-256哈希
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] hash = digest.digest(cacheInfo.toString().getBytes());
|
||||
|
||||
// 转换为16进制字符串
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte b : hash) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
|
||||
// 返回前16位作为哈希值(足够避免冲突)
|
||||
return hexString.substring(0, 16);
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
log.error("计算商品列表哈希值失败", e);
|
||||
// 降级策略:使用关键字段的hashCode
|
||||
StringBuilder fallback = new StringBuilder();
|
||||
for (ProductItem product : products) {
|
||||
fallback.append(product.getProductType()).append(":")
|
||||
.append(product.getProductId()).append(":")
|
||||
.append(product.getPurchaseCount() != null ? product.getPurchaseCount() : 1).append(";");
|
||||
}
|
||||
return String.valueOf(fallback.toString().hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存价格计算结果
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param scenicId 景区ID
|
||||
* @param products 商品列表
|
||||
* @param result 价格计算结果
|
||||
* @return 缓存键
|
||||
*/
|
||||
public String cachePriceResult(Long userId, Long scenicId, List<ProductItem> products, PriceCalculationResult result) {
|
||||
String cacheKey = generateCacheKey(userId, scenicId, products);
|
||||
|
||||
try {
|
||||
String resultJson = objectMapper.writeValueAsString(result);
|
||||
redisTemplate.opsForValue().set(cacheKey, resultJson, CACHE_DURATION);
|
||||
|
||||
log.info("价格计算结果已缓存: cacheKey={}, userId={}, scenicId={}",
|
||||
cacheKey, userId, scenicId);
|
||||
|
||||
return cacheKey;
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("缓存价格计算结果失败: userId={}, scenicId={}", userId, scenicId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存的价格计算结果
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param scenicId 景区ID
|
||||
* @param products 商品列表
|
||||
* @return 缓存的价格计算结果,如果不存在则返回null
|
||||
*/
|
||||
public PriceCalculationResult getCachedPriceResult(Long userId, Long scenicId, List<ProductItem> products) {
|
||||
String cacheKey = generateCacheKey(userId, scenicId, products);
|
||||
return getCachedPriceResult(cacheKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据缓存键获取价格计算结果
|
||||
*
|
||||
* @param cacheKey 缓存键
|
||||
* @return 缓存的价格计算结果,如果不存在则返回null
|
||||
*/
|
||||
public PriceCalculationResult getCachedPriceResult(String cacheKey) {
|
||||
try {
|
||||
String resultJson = redisTemplate.opsForValue().get(cacheKey);
|
||||
if (resultJson == null) {
|
||||
log.debug("价格缓存不存在: cacheKey={}", cacheKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
PriceCalculationResult result = objectMapper.readValue(resultJson, PriceCalculationResult.class);
|
||||
log.info("获取到缓存的价格计算结果: cacheKey={}", cacheKey);
|
||||
|
||||
return result;
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("解析缓存的价格计算结果失败: cacheKey={}", cacheKey, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查价格缓存是否存在
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param scenicId 景区ID
|
||||
* @param products 商品列表
|
||||
* @return true如果缓存存在且未过期
|
||||
*/
|
||||
public boolean isCacheExists(Long userId, Long scenicId, List<ProductItem> products) {
|
||||
String cacheKey = generateCacheKey(userId, scenicId, products);
|
||||
return Boolean.TRUE.equals(redisTemplate.hasKey(cacheKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证并消费价格缓存(一次性使用)
|
||||
* 查询缓存结果后立即删除,确保缓存只能被使用一次
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param scenicId 景区ID
|
||||
* @param products 商品列表
|
||||
* @return 缓存的价格计算结果,如果不存在则返回null
|
||||
*/
|
||||
public PriceCalculationResult validateAndConsumePriceCache(Long userId, Long scenicId, List<ProductItem> products) {
|
||||
String cacheKey = generateCacheKey(userId, scenicId, products);
|
||||
|
||||
try {
|
||||
// 使用 Redis 的 GETDEL 命令原子性地获取并删除缓存
|
||||
String resultJson = redisTemplate.opsForValue().getAndDelete(cacheKey);
|
||||
|
||||
if (resultJson == null) {
|
||||
log.warn("价格缓存不存在或已过期: userId={}, scenicId={}, cacheKey={}",
|
||||
userId, scenicId, cacheKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
PriceCalculationResult result = objectMapper.readValue(resultJson, PriceCalculationResult.class);
|
||||
log.info("价格缓存验证成功并已消费: userId={}, scenicId={}, cacheKey={}",
|
||||
userId, scenicId, cacheKey);
|
||||
|
||||
return result;
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("解析价格缓存失败: userId={}, scenicId={}, cacheKey={}",
|
||||
userId, scenicId, cacheKey, e);
|
||||
// 缓存解析失败时也要删除无效缓存
|
||||
redisTemplate.delete(cacheKey);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除价格缓存
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param scenicId 景区ID
|
||||
* @param products 商品列表
|
||||
* @return true如果删除成功
|
||||
*/
|
||||
public boolean deletePriceCache(Long userId, Long scenicId, List<ProductItem> products) {
|
||||
String cacheKey = generateCacheKey(userId, scenicId, products);
|
||||
return Boolean.TRUE.equals(redisTemplate.delete(cacheKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存剩余过期时间
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param scenicId 景区ID
|
||||
* @param products 商品列表
|
||||
* @return 剩余时间(秒),-1表示永不过期,-2表示不存在
|
||||
*/
|
||||
public long getCacheExpireTime(Long userId, Long scenicId, List<ProductItem> products) {
|
||||
String cacheKey = generateCacheKey(userId, scenicId, products);
|
||||
Long expire = redisTemplate.getExpire(cacheKey);
|
||||
return expire != null ? expire : -2;
|
||||
}
|
||||
}
|
@@ -13,7 +13,6 @@ import com.ycwl.basic.facebody.entity.AddFaceResp;
|
||||
import com.ycwl.basic.mapper.DeviceMapper;
|
||||
import com.ycwl.basic.mapper.CustomUploadTaskMapper;
|
||||
import com.ycwl.basic.mapper.FaceSampleMapper;
|
||||
import com.ycwl.basic.mapper.ScenicMapper;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import com.ycwl.basic.model.custom.entity.CustomUploadTaskEntity;
|
||||
|
@@ -9,6 +9,7 @@ import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginRespVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicRegisterReq;
|
||||
import com.ycwl.basic.model.mobile.scenic.account.ScenicRegisterRespVO;
|
||||
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
@@ -20,7 +21,7 @@ import java.util.List;
|
||||
* @Date:2024/12/6 10:23
|
||||
*/
|
||||
public interface AppScenicService {
|
||||
ApiResponse<PageInfo<ScenicAppVO>> pageQuery(ScenicReqQuery scenicReqQuery);
|
||||
ApiResponse<PageInfo<ScenicEntity>> pageQuery(ScenicReqQuery scenicReqQuery);
|
||||
|
||||
ApiResponse<ScenicDeviceCountVO> deviceCountByScenicId(Long scenicId);
|
||||
|
||||
|
@@ -1,10 +1,11 @@
|
||||
package com.ycwl.basic.service.mobile.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.mapper.*;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
|
||||
import com.ycwl.basic.mapper.DeviceMapper;
|
||||
import com.ycwl.basic.mapper.ExtraDeviceMapper;
|
||||
import com.ycwl.basic.mapper.ScenicAccountMapper;
|
||||
import com.ycwl.basic.model.jwt.JwtInfo;
|
||||
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
|
||||
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
||||
@@ -16,9 +17,11 @@ import com.ycwl.basic.model.mobile.scenic.account.ScenicRegisterRespVO;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.service.mobile.AppScenicService;
|
||||
import com.ycwl.basic.service.pc.ScenicAccountService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
@@ -30,6 +33,7 @@ import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@@ -43,8 +47,6 @@ import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
|
||||
@Service
|
||||
public class AppScenicServiceImpl implements AppScenicService {
|
||||
|
||||
@Autowired
|
||||
private ScenicMapper scenicMapper;
|
||||
@Autowired
|
||||
private DeviceMapper deviceMapper;
|
||||
@Autowired
|
||||
@@ -59,12 +61,19 @@ public class AppScenicServiceImpl implements AppScenicService {
|
||||
private ExtraDeviceMapper extraDeviceMapper;
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
@Override
|
||||
public ApiResponse<PageInfo<ScenicAppVO>> pageQuery(ScenicReqQuery scenicReqQuery) {
|
||||
PageHelper.startPage(scenicReqQuery.getPageNum(), scenicReqQuery.getPageSize());
|
||||
List<ScenicAppVO> list = scenicMapper.appList(scenicReqQuery);
|
||||
PageInfo<ScenicAppVO> pageInfo = new PageInfo<>(list);
|
||||
public ApiResponse<PageInfo<ScenicEntity>> pageQuery(ScenicReqQuery scenicReqQuery) {
|
||||
|
||||
ScenicReqQuery query = new ScenicReqQuery();
|
||||
query.setPageSize(1000);
|
||||
List<ScenicV2DTO> scenicList = scenicRepository.list(query);
|
||||
List<ScenicEntity> list = scenicList.stream().map(scenic -> {
|
||||
return scenicRepository.getScenic(Long.valueOf(scenic.getId()));
|
||||
}).toList();
|
||||
PageInfo<ScenicEntity> pageInfo = new PageInfo<>(list);
|
||||
return ApiResponse.success(pageInfo);
|
||||
}
|
||||
|
||||
@@ -77,7 +86,27 @@ public class AppScenicServiceImpl implements AppScenicService {
|
||||
|
||||
@Override
|
||||
public ApiResponse<ScenicRespVO> getDetails(Long id) {
|
||||
ScenicRespVO scenicRespVO = scenicMapper.getAppById(id);
|
||||
ScenicEntity scenic = scenicRepository.getScenic(id);
|
||||
ScenicRespVO scenicRespVO = new ScenicRespVO();
|
||||
|
||||
// 将ScenicEntity的值通过set/get方式写入到ScenicRespVO
|
||||
if (scenic != null) {
|
||||
scenicRespVO.setId(scenic.getId());
|
||||
scenicRespVO.setName(scenic.getName());
|
||||
scenicRespVO.setPhone(scenic.getPhone());
|
||||
scenicRespVO.setLogoUrl(scenic.getLogoUrl());
|
||||
scenicRespVO.setCoverUrl(scenic.getCoverUrl());
|
||||
scenicRespVO.setIntroduction(scenic.getIntroduction());
|
||||
scenicRespVO.setLongitude(scenic.getLongitude());
|
||||
scenicRespVO.setLatitude(scenic.getLatitude());
|
||||
scenicRespVO.setRadius(scenic.getRadius());
|
||||
scenicRespVO.setProvince(scenic.getProvince());
|
||||
scenicRespVO.setCity(scenic.getCity());
|
||||
scenicRespVO.setArea(scenic.getArea());
|
||||
scenicRespVO.setAddress(scenic.getAddress());
|
||||
scenicRespVO.setKfCodeUrl(scenic.getKfCodeUrl());
|
||||
}
|
||||
|
||||
ScenicDeviceCountVO scenicDeviceCountVO = deviceMapper.deviceCountByScenicId(id);
|
||||
scenicRespVO.setLensNum(scenicDeviceCountVO.getTotalDeviceCount());
|
||||
return ApiResponse.success(scenicRespVO);
|
||||
@@ -171,8 +200,59 @@ public class AppScenicServiceImpl implements AppScenicService {
|
||||
|
||||
@Override
|
||||
public List<ScenicAppVO> scenicListByLnLa(ScenicIndexVO scenicIndexVO) {
|
||||
List<ScenicAppVO> scenicAppVOS = scenicMapper.scenicListByLnLa(scenicIndexVO);
|
||||
return scenicAppVOS.stream().filter(scenic -> scenic.getDistance().compareTo(scenic.getRadius().multiply(BigDecimal.valueOf(1_000L))) < 0).toList();
|
||||
// 从 scenicRepository 获取所有景区(1000个)
|
||||
ScenicReqQuery query = new ScenicReqQuery();
|
||||
query.setPageNum(1);
|
||||
query.setPageSize(1000);
|
||||
List<ScenicV2DTO> scenicList = scenicRepository.list(query);
|
||||
|
||||
List<ScenicAppVO> list = new ArrayList<>();
|
||||
|
||||
// 为每个景区获取详细信息(包含经纬度)
|
||||
for (ScenicV2DTO scenicDTO : scenicList) {
|
||||
try {
|
||||
// 获取景区详细信息(包含经纬度)
|
||||
ScenicEntity scenicEntity = scenicRepository.getScenic(Long.parseLong(scenicDTO.getId()));
|
||||
if (scenicEntity != null && scenicEntity.getLatitude() != null && scenicEntity.getLongitude() != null) {
|
||||
// 计算距离
|
||||
BigDecimal distance = calculateDistance(
|
||||
scenicIndexVO.getLatitude(),
|
||||
scenicIndexVO.getLongitude(),
|
||||
scenicEntity.getLatitude(),
|
||||
scenicEntity.getLongitude()
|
||||
);
|
||||
|
||||
// 根据距离和范围筛选景区
|
||||
if (scenicEntity.getRadius() != null &&
|
||||
distance.compareTo(scenicEntity.getRadius().multiply(BigDecimal.valueOf(1_000L))) < 0) {
|
||||
|
||||
// 转换为 ScenicAppVO
|
||||
ScenicAppVO scenicAppVO = new ScenicAppVO();
|
||||
scenicAppVO.setId(scenicEntity.getId());
|
||||
scenicAppVO.setName(scenicEntity.getName());
|
||||
scenicAppVO.setPhone(scenicEntity.getPhone());
|
||||
scenicAppVO.setIntroduction(scenicEntity.getIntroduction());
|
||||
scenicAppVO.setCoverUrl(scenicEntity.getCoverUrl());
|
||||
scenicAppVO.setLongitude(scenicEntity.getLongitude());
|
||||
scenicAppVO.setLatitude(scenicEntity.getLatitude());
|
||||
scenicAppVO.setRadius(scenicEntity.getRadius());
|
||||
scenicAppVO.setProvince(scenicEntity.getProvince());
|
||||
scenicAppVO.setCity(scenicEntity.getCity());
|
||||
scenicAppVO.setArea(scenicEntity.getArea());
|
||||
scenicAppVO.setAddress(scenicEntity.getAddress());
|
||||
scenicAppVO.setDistance(distance);
|
||||
scenicAppVO.setDeviceNum(deviceRepository.getAllDeviceByScenicId(scenicEntity.getId()).size());
|
||||
|
||||
list.add(scenicAppVO);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 单个景区获取失败,继续处理下一个
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -214,4 +294,29 @@ public class AppScenicServiceImpl implements AppScenicService {
|
||||
deviceRespVOList.addAll(0, extraDeviceList);
|
||||
return ApiResponse.success(deviceRespVOList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两点之间的距离(米)
|
||||
* 使用 Haversine 公式
|
||||
*/
|
||||
private BigDecimal calculateDistance(BigDecimal lat1, BigDecimal lon1, BigDecimal lat2, BigDecimal lon2) {
|
||||
if (lat1 == null || lon1 == null || lat2 == null || lon2 == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
final double R = 6371000; // 地球半径(米)
|
||||
|
||||
double lat1Rad = Math.toRadians(lat1.doubleValue());
|
||||
double lat2Rad = Math.toRadians(lat2.doubleValue());
|
||||
double deltaLat = Math.toRadians(lat2.subtract(lat1).doubleValue());
|
||||
double deltaLon = Math.toRadians(lon2.subtract(lon1).doubleValue());
|
||||
|
||||
double a = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) +
|
||||
Math.cos(lat1Rad) * Math.cos(lat2Rad) *
|
||||
Math.sin(deltaLon/2) * Math.sin(deltaLon/2);
|
||||
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
||||
|
||||
double distance = R * c;
|
||||
return BigDecimal.valueOf(distance);
|
||||
}
|
||||
}
|
||||
|
@@ -139,9 +139,9 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
List<SourceRespVO> goods = faceEntry.getValue();
|
||||
return goods.stream().collect(Collectors.groupingBy(SourceRespVO::getType)).keySet().stream().filter(type -> {
|
||||
if (Integer.valueOf(1).equals(type)) {
|
||||
return !Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo());
|
||||
return !Boolean.TRUE.equals(scenicConfig.getDisableSourceVideo());
|
||||
} else if (Integer.valueOf(2).equals(type)) {
|
||||
return !Integer.valueOf(1).equals(scenicConfig.getDisableSourceImage());
|
||||
return !Boolean.TRUE.equals(scenicConfig.getDisableSourceImage());
|
||||
}
|
||||
return true;
|
||||
}).map(type -> {
|
||||
|
@@ -1,11 +1,8 @@
|
||||
package com.ycwl.basic.service.pc;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||
import com.ycwl.basic.pay.adapter.IPayAdapter;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
@@ -17,23 +14,7 @@ import java.util.List;
|
||||
* @Date:2024/12/3 15:22
|
||||
*/
|
||||
public interface ScenicService {
|
||||
ApiResponse<PageInfo<ScenicRespVO>> pageQuery(ScenicReqQuery scenicReqQuery);
|
||||
ApiResponse<List<ScenicRespVO>> list(ScenicReqQuery scenicReqQuery);
|
||||
ApiResponse<ScenicRespVO> getById(Long id);
|
||||
ApiResponse<Boolean> add(ScenicAddOrUpdateReq scenicAddOrUpdateReq);
|
||||
ApiResponse<Boolean> deleteById(Long id);
|
||||
ApiResponse<Boolean> update(ScenicAddOrUpdateReq scenicAddOrUpdateReq);
|
||||
ApiResponse<Boolean> updateStatus(Long id);
|
||||
ApiResponse<Boolean> addConfig(ScenicConfigEntity scenicConfig);
|
||||
/**
|
||||
* 修改景区配置
|
||||
* @param scenicConfig
|
||||
* @return
|
||||
*/
|
||||
ApiResponse<Boolean> updateConfigById(ScenicConfigEntity scenicConfig);
|
||||
|
||||
ScenicConfigEntity getConfig(Long id);
|
||||
void saveConfig(Long configId, ScenicConfigEntity config);
|
||||
ApiResponse<List<ScenicV2DTO>> list(ScenicReqQuery scenicReqQuery);
|
||||
|
||||
IStorageAdapter getScenicStorageAdapter(Long scenicId);
|
||||
|
||||
|
@@ -324,7 +324,7 @@ public class FaceServiceImpl implements FaceService {
|
||||
}
|
||||
} else {
|
||||
// 重新切视频逻辑
|
||||
if (scenicConfig != null && !Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo())) {
|
||||
if (scenicConfig != null && !Boolean.TRUE.equals(scenicConfig.getDisableSourceVideo())) {
|
||||
long videoCount = memberSourceEntityList.stream().filter(item -> item.getType().equals(1)).count();
|
||||
long photoCount = memberSourceEntityList.stream().filter(item -> item.getType().equals(2)).count();
|
||||
if (photoCount > videoCount) {
|
||||
@@ -443,7 +443,7 @@ public class FaceServiceImpl implements FaceService {
|
||||
sourceVideoContent.setLockType(-1);
|
||||
sourceImageContent.setLockType(-1);
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(faceRespVO.getScenicId());
|
||||
if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceImage())) {
|
||||
if (!Boolean.TRUE.equals(scenicConfig.getDisableSourceImage())) {
|
||||
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(userId, faceRespVO.getScenicId(), 2, faceId);
|
||||
sourceImageContent.setSourceType(isBuyRespVO.getGoodsType());
|
||||
sourceImageContent.setContentId(isBuyRespVO.getGoodsId());
|
||||
@@ -462,7 +462,7 @@ public class FaceServiceImpl implements FaceService {
|
||||
sourceImageContent.setFreeCount((int) freeCount);
|
||||
contentList.add(sourceImageContent);
|
||||
}
|
||||
if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo())) {
|
||||
if (!Boolean.TRUE.equals(scenicConfig.getDisableSourceVideo())) {
|
||||
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(userId, faceRespVO.getScenicId(), 1, faceId);
|
||||
sourceVideoContent.setSourceType(isBuyRespVO.getGoodsType());
|
||||
sourceVideoContent.setContentId(isBuyRespVO.getGoodsId());
|
||||
|
@@ -57,6 +57,7 @@ import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -78,7 +79,7 @@ import java.util.stream.Collectors;
|
||||
* @Date:2024/12/3 13:54
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@Service("OrderServiceOldImpl")
|
||||
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public class OrderServiceImpl implements OrderService {
|
||||
|
||||
@@ -86,6 +87,7 @@ public class OrderServiceImpl implements OrderService {
|
||||
private OrderMapper orderMapper;
|
||||
|
||||
@Autowired
|
||||
@Qualifier(value = "OrderServiceOldImpl")
|
||||
private OrderServiceImpl self;
|
||||
@Autowired
|
||||
private SourceMapper sourceMapper;
|
||||
|
@@ -1,38 +1,29 @@
|
||||
package com.ycwl.basic.service.pc.impl;
|
||||
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ycwl.basic.facebody.FaceBodyFactory;
|
||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||
import com.ycwl.basic.mapper.ScenicAccountMapper;
|
||||
import com.ycwl.basic.mapper.ScenicMapper;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
|
||||
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq;
|
||||
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
|
||||
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||
import com.ycwl.basic.pay.PayFactory;
|
||||
import com.ycwl.basic.pay.adapter.IPayAdapter;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.service.task.TaskFaceService;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.exceptions.StorageUnsupportedException;
|
||||
import com.ycwl.basic.util.ScenicConfigManager;
|
||||
import com.ycwl.basic.util.TtlCacheMap;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
@@ -41,199 +32,39 @@ import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ScenicServiceImpl implements ScenicService {
|
||||
@Autowired
|
||||
private ScenicMapper scenicMapper;
|
||||
@Autowired
|
||||
private ScenicAccountMapper scenicAccountMapper;
|
||||
@Autowired
|
||||
private TaskFaceService taskFaceService;
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
// TTL缓存配置,默认10分钟过期
|
||||
private static final long DEFAULT_CACHE_TTL_MINUTES = 10;
|
||||
|
||||
// 使用TTL缓存替代静态Map
|
||||
private static final TtlCacheMap<Long, IStorageAdapter> scenicStorageAdapterCache =
|
||||
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
|
||||
private static final TtlCacheMap<Long, IStorageAdapter> scenicTmpStorageAdapterCache =
|
||||
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
|
||||
private static final TtlCacheMap<Long, IStorageAdapter> scenicLocalStorageAdapterCache =
|
||||
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
|
||||
private static final TtlCacheMap<Long, IFaceBodyAdapter> scenicFaceBodyAdapterCache =
|
||||
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
|
||||
private static final TtlCacheMap<Long, IPayAdapter> scenicPayAdapterCache =
|
||||
new TtlCacheMap<>(TimeUnit.MINUTES.toMillis(DEFAULT_CACHE_TTL_MINUTES));
|
||||
|
||||
@Override
|
||||
public ApiResponse<PageInfo<ScenicRespVO>> pageQuery(ScenicReqQuery scenicReqQuery) {
|
||||
PageHelper.startPage(scenicReqQuery.getPageNum(), scenicReqQuery.getPageSize());
|
||||
List<ScenicRespVO> list = scenicMapper.list(scenicReqQuery);
|
||||
PageInfo<ScenicRespVO> pageInfo = new PageInfo<>(list);
|
||||
return ApiResponse.success(pageInfo);
|
||||
@Deprecated
|
||||
public ApiResponse<List<ScenicV2DTO>> list(ScenicReqQuery scenicReqQuery) {
|
||||
return ApiResponse.success(scenicRepository.list(scenicReqQuery));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<List<ScenicRespVO>> list(ScenicReqQuery scenicReqQuery) {
|
||||
return ApiResponse.success(scenicMapper.list(scenicReqQuery));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<ScenicRespVO> getById(Long id) {
|
||||
return ApiResponse.success(scenicMapper.getById(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResponse<Boolean> add(ScenicAddOrUpdateReq scenicAddReq) {
|
||||
Long scenicId = SnowFlakeUtil.getLongId();
|
||||
scenicAddReq.setId(scenicId);
|
||||
int add = scenicMapper.add(scenicAddReq);
|
||||
ScenicAccountEntity scenicAccount = scenicAccountMapper.getByAccount(scenicAddReq.getAccount());
|
||||
if (scenicAccount == null) {
|
||||
scenicAccount = new ScenicAccountEntity();
|
||||
scenicAccount.setId(SnowFlakeUtil.getLongId());
|
||||
scenicAccount.setName(scenicAddReq.getName() + "管理员");
|
||||
scenicAccount.setAccount(scenicAddReq.getAccount());
|
||||
scenicAccount.setPassword(scenicAddReq.getPassword());
|
||||
scenicAccount.setIsSuper(1);
|
||||
scenicAccountMapper.add(scenicAccount);
|
||||
}
|
||||
scenicAccountMapper.addAccountScenicRelation(scenicAccount.getId(), scenicId, 1);
|
||||
if (add > 0) {
|
||||
return ApiResponse.success(true);
|
||||
} else {
|
||||
return ApiResponse.fail("景区添加失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResponse<Boolean> deleteById(Long id) {
|
||||
int i = scenicMapper.deleteById(id);
|
||||
if (i > 0) {
|
||||
scenicAccountMapper.deleteRelationByScenicId(id);
|
||||
IFaceBodyAdapter adapter = getScenicFaceBodyAdapter(id);
|
||||
Thread.ofVirtual().start(() -> {
|
||||
adapter.deleteFaceDb(id.toString());
|
||||
adapter.deleteFaceDb(USER_FACE_DB_NAME + id);
|
||||
});
|
||||
scenicMapper.deleteConfigByScenicId(id);
|
||||
scenicRepository.clearCache(id);
|
||||
scenicFaceBodyAdapterMap.remove(id);
|
||||
scenicStorageAdapterMap.remove(id);
|
||||
scenicPayAdapterMap.remove(id);
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
return ApiResponse.fail("景区删除失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<Boolean> update(ScenicAddOrUpdateReq scenicUpdateReq) {
|
||||
if (scenicUpdateReq.getId() == null) {
|
||||
return ApiResponse.fail("参数错误");
|
||||
}
|
||||
if (StringUtils.isNotBlank(scenicUpdateReq.getAccount()) && StringUtils.isNotBlank(scenicUpdateReq.getPassword())) {
|
||||
ScenicAccountEntity scenicAccount = scenicAccountMapper.getByAccount(scenicUpdateReq.getAccount());
|
||||
if (scenicAccount != null) {
|
||||
if (!scenicAccount.getScenicId().equals(scenicUpdateReq.getId())) {
|
||||
return ApiResponse.fail("账号已存在");
|
||||
}
|
||||
}
|
||||
ScenicAccountEntity account = scenicAccountMapper.getSuperAccountOfScenic(scenicUpdateReq.getId());
|
||||
if (account != null) {
|
||||
account.setAccount(scenicUpdateReq.getAccount());
|
||||
account.setPassword(scenicUpdateReq.getPassword());
|
||||
scenicAccountMapper.update(account);
|
||||
} else {
|
||||
account = new ScenicAccountEntity();
|
||||
account.setId(SnowFlakeUtil.getLongId());
|
||||
account.setName(scenicUpdateReq.getName() + "管理员");
|
||||
account.setAccount(scenicUpdateReq.getAccount());
|
||||
account.setPassword(scenicUpdateReq.getPassword());
|
||||
account.setIsSuper(1);
|
||||
scenicAccountMapper.add(account);
|
||||
}
|
||||
scenicAccountMapper.addAccountScenicRelation(account.getId(), scenicUpdateReq.getId(), 1);
|
||||
}
|
||||
int i = scenicMapper.update(scenicUpdateReq);
|
||||
if (i > 0) {
|
||||
scenicRepository.clearCache(scenicUpdateReq.getId());
|
||||
scenicFaceBodyAdapterMap.remove(scenicUpdateReq.getId());
|
||||
scenicStorageAdapterMap.remove(scenicUpdateReq.getId());
|
||||
scenicTmpStorageAdapterMap.remove(scenicUpdateReq.getId());
|
||||
scenicLocalStorageAdapterMap.remove(scenicUpdateReq.getId());
|
||||
scenicPayAdapterMap.remove(scenicUpdateReq.getId());
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
return ApiResponse.fail("景区修改失败");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<Boolean> updateStatus(Long id) {
|
||||
int i = scenicMapper.updateStatus(id);
|
||||
if (i > 0) {
|
||||
scenicRepository.clearCache(id);
|
||||
scenicFaceBodyAdapterMap.remove(id);
|
||||
scenicStorageAdapterMap.remove(id);
|
||||
scenicTmpStorageAdapterMap.remove(id);
|
||||
scenicLocalStorageAdapterMap.remove(id);
|
||||
scenicPayAdapterMap.remove(id);
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
return ApiResponse.fail("景区状态修改失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<Boolean> addConfig(ScenicConfigEntity scenicConfig) {
|
||||
if (scenicConfig.getId() == null) {
|
||||
scenicConfig.setId(SnowFlakeUtil.getLongId());
|
||||
}
|
||||
int i = scenicMapper.addConfig(scenicConfig);
|
||||
if (i > 0) {
|
||||
scenicRepository.clearCache(scenicConfig.getScenicId());
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
return ApiResponse.fail("景区配置添加失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<Boolean> updateConfigById(ScenicConfigEntity scenicConfig) {
|
||||
int i = scenicMapper.updateConfigById(scenicConfig);
|
||||
if (i > 0) {
|
||||
scenicRepository.clearCache(scenicConfig.getScenicId());
|
||||
scenicFaceBodyAdapterMap.remove(scenicConfig.getScenicId());
|
||||
scenicStorageAdapterMap.remove(scenicConfig.getScenicId());
|
||||
scenicTmpStorageAdapterMap.remove(scenicConfig.getScenicId());
|
||||
scenicLocalStorageAdapterMap.remove(scenicConfig.getScenicId());
|
||||
scenicPayAdapterMap.remove(scenicConfig.getScenicId());
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
return ApiResponse.fail("景区配置修改失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScenicConfigEntity getConfig(Long id) {
|
||||
return scenicRepository.getScenicConfig(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig(Long configId, ScenicConfigEntity config) {
|
||||
config.setId(configId);
|
||||
if (config.getScenicId() == null) {
|
||||
throw new RuntimeException("景区ID不能为空");
|
||||
}
|
||||
scenicMapper.updateConfigById(config);
|
||||
scenicRepository.clearCache(config.getScenicId());
|
||||
scenicFaceBodyAdapterMap.remove(config.getScenicId());
|
||||
scenicStorageAdapterMap.remove(config.getScenicId());
|
||||
scenicTmpStorageAdapterMap.remove(config.getScenicId());
|
||||
scenicLocalStorageAdapterMap.remove(config.getScenicId());
|
||||
scenicPayAdapterMap.remove(config.getScenicId());
|
||||
}
|
||||
|
||||
|
||||
private static final Map<Long, IStorageAdapter> scenicStorageAdapterMap = new ConcurrentHashMap<>();
|
||||
@Override
|
||||
public IStorageAdapter getScenicStorageAdapter(Long scenicId) {
|
||||
return scenicStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
|
||||
return scenicStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||
IStorageAdapter adapter;
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null && scenicConfig.getStoreType() != null) {
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||
if (Strings.isNotBlank(scenicConfig.getString("store_type"))) {
|
||||
try {
|
||||
adapter = StorageFactory.get(scenicConfig.getStoreType());
|
||||
adapter.loadConfig(JacksonUtil.parseObject(scenicConfig.getStoreConfigJson(), Map.class));
|
||||
adapter = StorageFactory.get(scenicConfig.getString("store_type"));
|
||||
adapter.loadConfig(scenicConfig.getObject("store_config_json", Map.class));
|
||||
} catch (StorageUnsupportedException ignored) {
|
||||
return StorageFactory.use("video");
|
||||
}
|
||||
@@ -243,16 +74,15 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
return adapter;
|
||||
});
|
||||
}
|
||||
private static final Map<Long, IStorageAdapter> scenicTmpStorageAdapterMap = new ConcurrentHashMap<>();
|
||||
@Override
|
||||
public IStorageAdapter getScenicTmpStorageAdapter(Long scenicId) {
|
||||
return scenicTmpStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
|
||||
return scenicTmpStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||
IStorageAdapter adapter;
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null && scenicConfig.getTmpStoreType() != null) {
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||
if (Strings.isNotBlank(scenicConfig.getString("tmp_store_type"))) {
|
||||
try {
|
||||
adapter = StorageFactory.get(scenicConfig.getTmpStoreType());
|
||||
adapter.loadConfig(JacksonUtil.parseObject(scenicConfig.getTmpStoreConfigJson(), Map.class));
|
||||
adapter = StorageFactory.get(scenicConfig.getString("tmp_store_type"));
|
||||
adapter.loadConfig(scenicConfig.getObject("tmp_store_config_json", Map.class));
|
||||
} catch (StorageUnsupportedException ignored) {
|
||||
return getScenicStorageAdapter(scenicId);
|
||||
}
|
||||
@@ -262,16 +92,15 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
return adapter;
|
||||
});
|
||||
}
|
||||
private static final Map<Long, IStorageAdapter> scenicLocalStorageAdapterMap = new ConcurrentHashMap<>();
|
||||
@Override
|
||||
public IStorageAdapter getScenicLocalStorageAdapter(Long scenicId) {
|
||||
return scenicLocalStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
|
||||
return scenicLocalStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||
IStorageAdapter adapter;
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null && scenicConfig.getLocalStoreType() != null) {
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||
if (Strings.isNotBlank(scenicConfig.getString("local_store_type"))) {
|
||||
try {
|
||||
adapter = StorageFactory.get(scenicConfig.getLocalStoreType());
|
||||
adapter.loadConfig(JacksonUtil.parseObject(scenicConfig.getLocalStoreConfigJson(), Map.class));
|
||||
adapter = StorageFactory.get(scenicConfig.getString("local_store_type"));
|
||||
adapter.loadConfig(scenicConfig.getObject("local_store_config_json", Map.class));
|
||||
} catch (StorageUnsupportedException ignored) {
|
||||
return getScenicStorageAdapter(scenicId);
|
||||
}
|
||||
@@ -282,15 +111,14 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
});
|
||||
}
|
||||
|
||||
private static final Map<Long, IFaceBodyAdapter> scenicFaceBodyAdapterMap = new ConcurrentHashMap<>();
|
||||
@Override
|
||||
public IFaceBodyAdapter getScenicFaceBodyAdapter(Long scenicId) {
|
||||
return scenicFaceBodyAdapterMap.computeIfAbsent(scenicId, (key) -> {
|
||||
return scenicFaceBodyAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||
IFaceBodyAdapter adapter;
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null && scenicConfig.getFaceType() != null) {
|
||||
adapter = FaceBodyFactory.getAdapter(scenicConfig.getFaceType());
|
||||
adapter.loadConfig(JacksonUtil.parseObject(scenicConfig.getFaceConfigJson(), Map.class));
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||
if (Strings.isNotBlank(scenicConfig.getString("face_type"))) {
|
||||
adapter = FaceBodyFactory.getAdapter(scenicConfig.getString("face_type"));
|
||||
adapter.loadConfig(scenicConfig.getObject("face_config_json", Map.class));
|
||||
} else {
|
||||
adapter = FaceBodyFactory.use();
|
||||
}
|
||||
@@ -298,19 +126,108 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
});
|
||||
}
|
||||
|
||||
private static final Map<Long, IPayAdapter> scenicPayAdapterMap = new ConcurrentHashMap<>();
|
||||
@Override
|
||||
public IPayAdapter getScenicPayAdapter(Long scenicId) {
|
||||
return scenicPayAdapterMap.computeIfAbsent(scenicId, (key) -> {
|
||||
return scenicPayAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||
IPayAdapter adapter;
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null && scenicConfig.getPayType() != null) {
|
||||
adapter = PayFactory.getAdapter(scenicConfig.getPayType());
|
||||
adapter.loadConfig(JacksonUtil.parseObject(scenicConfig.getPayConfigJson(), Map.class));
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||
if (Strings.isNotBlank(scenicConfig.getString("pay_type"))) {
|
||||
adapter = PayFactory.getAdapter(scenicConfig.getString("pay_type"));
|
||||
adapter.loadConfig(scenicConfig.getObject("pay_config_json", Map.class));
|
||||
} else {
|
||||
adapter = PayFactory.use();
|
||||
}
|
||||
return adapter;
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 缓存管理方法 ====================
|
||||
|
||||
/**
|
||||
* 清除指定景区的所有适配器缓存
|
||||
*
|
||||
* @param scenicId 景区ID
|
||||
*/
|
||||
public void clearScenicAdapterCache(Long scenicId) {
|
||||
log.info("清除景区 {} 的所有适配器缓存", scenicId);
|
||||
scenicStorageAdapterCache.remove(scenicId);
|
||||
scenicTmpStorageAdapterCache.remove(scenicId);
|
||||
scenicLocalStorageAdapterCache.remove(scenicId);
|
||||
scenicFaceBodyAdapterCache.remove(scenicId);
|
||||
scenicPayAdapterCache.remove(scenicId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有适配器缓存
|
||||
*/
|
||||
public void clearAllAdapterCache() {
|
||||
log.info("清除所有适配器缓存");
|
||||
scenicStorageAdapterCache.clear();
|
||||
scenicTmpStorageAdapterCache.clear();
|
||||
scenicLocalStorageAdapterCache.clear();
|
||||
scenicFaceBodyAdapterCache.clear();
|
||||
scenicPayAdapterCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发过期缓存清理
|
||||
*
|
||||
* @return 清理的过期缓存项总数
|
||||
*/
|
||||
public int cleanupExpiredCache() {
|
||||
log.info("手动触发过期缓存清理");
|
||||
int totalCleaned = 0;
|
||||
totalCleaned += scenicStorageAdapterCache.cleanupExpired();
|
||||
totalCleaned += scenicTmpStorageAdapterCache.cleanupExpired();
|
||||
totalCleaned += scenicLocalStorageAdapterCache.cleanupExpired();
|
||||
totalCleaned += scenicFaceBodyAdapterCache.cleanupExpired();
|
||||
totalCleaned += scenicPayAdapterCache.cleanupExpired();
|
||||
log.info("清理了 {} 个过期缓存项", totalCleaned);
|
||||
return totalCleaned;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存统计信息
|
||||
*
|
||||
* @return 缓存统计信息
|
||||
*/
|
||||
public String getCacheStats() {
|
||||
StringBuilder stats = new StringBuilder();
|
||||
stats.append("=== ScenicServiceImpl 缓存统计信息 ===\n");
|
||||
stats.append("Storage Adapter Cache: ").append(scenicStorageAdapterCache.getStats()).append("\n");
|
||||
stats.append("Tmp Storage Adapter Cache: ").append(scenicTmpStorageAdapterCache.getStats()).append("\n");
|
||||
stats.append("Local Storage Adapter Cache: ").append(scenicLocalStorageAdapterCache.getStats()).append("\n");
|
||||
stats.append("FaceBody Adapter Cache: ").append(scenicFaceBodyAdapterCache.getStats()).append("\n");
|
||||
stats.append("Pay Adapter Cache: ").append(scenicPayAdapterCache.getStats()).append("\n");
|
||||
return stats.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置所有缓存统计信息
|
||||
*/
|
||||
public void resetCacheStats() {
|
||||
log.info("重置所有缓存统计信息");
|
||||
scenicStorageAdapterCache.resetStats();
|
||||
scenicTmpStorageAdapterCache.resetStats();
|
||||
scenicLocalStorageAdapterCache.resetStats();
|
||||
scenicFaceBodyAdapterCache.resetStats();
|
||||
scenicPayAdapterCache.resetStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定景区缓存的剩余TTL时间
|
||||
*
|
||||
* @param scenicId 景区ID
|
||||
* @return 各类型适配器缓存的剩余TTL时间(毫秒)
|
||||
*/
|
||||
public String getScenicCacheTtl(Long scenicId) {
|
||||
StringBuilder ttlInfo = new StringBuilder();
|
||||
ttlInfo.append("景区 ").append(scenicId).append(" 缓存TTL信息:\n");
|
||||
ttlInfo.append("Storage: ").append(scenicStorageAdapterCache.getRemainTtl(scenicId)).append("ms\n");
|
||||
ttlInfo.append("TmpStorage: ").append(scenicTmpStorageAdapterCache.getRemainTtl(scenicId)).append("ms\n");
|
||||
ttlInfo.append("LocalStorage: ").append(scenicLocalStorageAdapterCache.getRemainTtl(scenicId)).append("ms\n");
|
||||
ttlInfo.append("FaceBody: ").append(scenicFaceBodyAdapterCache.getRemainTtl(scenicId)).append("ms\n");
|
||||
ttlInfo.append("Pay: ").append(scenicPayAdapterCache.getRemainTtl(scenicId)).append("ms\n");
|
||||
return ttlInfo.toString();
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,8 @@ import com.ycwl.basic.model.pc.template.entity.TemplateConfigEntity;
|
||||
import com.ycwl.basic.model.pc.template.entity.TemplateEntity;
|
||||
import com.ycwl.basic.model.pc.template.req.TemplateReqQuery;
|
||||
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||
import com.ycwl.basic.pricing.enums.ProductType;
|
||||
import com.ycwl.basic.pricing.service.IPricingManagementService;
|
||||
import com.ycwl.basic.service.pc.TemplateService;
|
||||
import com.ycwl.basic.repository.TemplateRepository;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
@@ -30,6 +32,8 @@ public class TemplateServiceImpl implements TemplateService {
|
||||
private TemplateMapper templateMapper;
|
||||
@Autowired
|
||||
private TemplateRepository templateRepository;
|
||||
@Autowired
|
||||
private IPricingManagementService pricingManagementService;
|
||||
|
||||
@Override
|
||||
public ApiResponse<PageInfo<TemplateRespVO>> pageQuery(TemplateReqQuery templateReqQuery) {
|
||||
@@ -75,6 +79,7 @@ public class TemplateServiceImpl implements TemplateService {
|
||||
templateMapper.add(item);
|
||||
});
|
||||
}
|
||||
pricingManagementService.quickSetupProductPrice(ProductType.VLOG_VIDEO.getCode(), template.getId().toString(), template.getScenicId().toString(), template.getName(), template.getPrice(), template.getSlashPrice(), "个");
|
||||
if (i > 0) {
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
@@ -112,6 +117,7 @@ public class TemplateServiceImpl implements TemplateService {
|
||||
});
|
||||
}
|
||||
templateRepository.clearTemplateCache(template.getId());
|
||||
pricingManagementService.quickSetupProductPrice(ProductType.VLOG_VIDEO.getCode(), template.getId().toString(), template.getScenicId().toString(), template.getName(), template.getPrice(), template.getSlashPrice(), "个");
|
||||
if (i > 0) {
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
|
Reference in New Issue
Block a user