You've already forked FrameTour-BE
refactor(order): 重构订单相关代码并优化商品哈希计算逻辑
- 修改 DiscountType 枚举,将 FLASH_SALE 改为 LIMITED_TIME - 优化 OrderServiceImpl 中的商品信息设置逻辑,增加空值判断 - 更新 IDiscountProvider 接口和 FlashSaleDiscountProvider 类中的提供者类型标识- 优化 ScenicServiceImpl 中的字符串判空逻辑,使用 Strings.isNotBlank 方法 - 重构 PriceCacheService 中的商品列表哈希值计算逻辑,仅基于必传字段生成哈希
This commit is contained in:
@@ -18,7 +18,7 @@ public enum DiscountType {
|
|||||||
/**
|
/**
|
||||||
* 限时立减
|
* 限时立减
|
||||||
*/
|
*/
|
||||||
FLASH_SALE("FLASH_SALE", "限时立减"),
|
LIMITED_TIME("LIMITED_TIME", "限时立减"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 套餐优惠
|
* 套餐优惠
|
||||||
|
@@ -109,10 +109,10 @@ public class OrderServiceImpl implements IOrderService {
|
|||||||
orderItem.setProductType(product.getProductType().name());
|
orderItem.setProductType(product.getProductType().name());
|
||||||
orderItem.setProductId(product.getProductId());
|
orderItem.setProductId(product.getProductId());
|
||||||
orderItem.setProductName(getProductName(product)); // 根据商品类型和ID获取商品名称
|
orderItem.setProductName(getProductName(product)); // 根据商品类型和ID获取商品名称
|
||||||
orderItem.setQuantity(product.getQuantity());
|
orderItem.setQuantity(product.getQuantity() != null ? product.getQuantity() : 1);
|
||||||
orderItem.setUnitPrice(product.getUnitPrice());
|
orderItem.setUnitPrice(product.getUnitPrice() != null ? product.getUnitPrice() : BigDecimal.ZERO);
|
||||||
orderItem.setOriginalAmount(product.getOriginalPrice());
|
orderItem.setOriginalAmount(product.getOriginalPrice() != null ? product.getOriginalPrice() : BigDecimal.ZERO);
|
||||||
orderItem.setFinalAmount(product.getSubtotal());
|
orderItem.setFinalAmount(product.getSubtotal() != null ? product.getSubtotal() : BigDecimal.ZERO);
|
||||||
orderItem.setCreateTime(now);
|
orderItem.setCreateTime(now);
|
||||||
orderItem.setUpdateTime(now);
|
orderItem.setUpdateTime(now);
|
||||||
|
|
||||||
|
@@ -438,7 +438,7 @@ public interface IDiscountDetectionService {
|
|||||||
@Component
|
@Component
|
||||||
public class FlashSaleDiscountProvider implements IDiscountProvider {
|
public class FlashSaleDiscountProvider implements IDiscountProvider {
|
||||||
@Override
|
@Override
|
||||||
public String getProviderType() { return "FLASH_SALE"; }
|
public String getProviderType() { return "LIMITED_TIME"; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPriority() { return 90; } // 介于券码和优惠券之间
|
public int getPriority() { return 90; } // 介于券码和优惠券之间
|
||||||
|
@@ -14,7 +14,7 @@ public interface IDiscountProvider {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取提供者类型
|
* 获取提供者类型
|
||||||
* @return 提供者类型标识,如 "COUPON", "VOUCHER", "FLASH_SALE" 等
|
* @return 提供者类型标识,如 "COUPON", "VOUCHER", "LIMITED_TIME" 等
|
||||||
*/
|
*/
|
||||||
String getProviderType();
|
String getProviderType();
|
||||||
|
|
||||||
|
@@ -48,19 +48,25 @@ public class PriceCacheService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算商品列表的哈希值
|
* 计算商品列表的哈希值
|
||||||
* 基于商品类型、ID、数量等信息生成唯一哈希
|
* 基于商品类型、ID、购买数量等必传字段生成唯一哈希,忽略可选的quantity字段
|
||||||
*
|
*
|
||||||
* @param products 商品列表
|
* @param products 商品列表
|
||||||
* @return 哈希值
|
* @return 哈希值
|
||||||
*/
|
*/
|
||||||
private String calculateProductsHash(List<ProductItem> products) {
|
private String calculateProductsHash(List<ProductItem> products) {
|
||||||
try {
|
try {
|
||||||
// 将商品列表转换为JSON字符串
|
// 构建缓存用的商品信息字符串,只包含必传字段
|
||||||
String productsJson = objectMapper.writeValueAsString(products);
|
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哈希
|
// 计算SHA-256哈希
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||||
byte[] hash = digest.digest(productsJson.getBytes());
|
byte[] hash = digest.digest(cacheInfo.toString().getBytes());
|
||||||
|
|
||||||
// 转换为16进制字符串
|
// 转换为16进制字符串
|
||||||
StringBuilder hexString = new StringBuilder();
|
StringBuilder hexString = new StringBuilder();
|
||||||
@@ -75,10 +81,16 @@ public class PriceCacheService {
|
|||||||
// 返回前16位作为哈希值(足够避免冲突)
|
// 返回前16位作为哈希值(足够避免冲突)
|
||||||
return hexString.substring(0, 16);
|
return hexString.substring(0, 16);
|
||||||
|
|
||||||
} catch (JsonProcessingException | NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
log.error("计算商品列表哈希值失败", e);
|
log.error("计算商品列表哈希值失败", e);
|
||||||
// 降级策略:使用商品列表的hashCode
|
// 降级策略:使用关键字段的hashCode
|
||||||
return String.valueOf(products.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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,6 +17,7 @@ import com.ycwl.basic.util.TtlCacheMap;
|
|||||||
import com.ycwl.basic.utils.ApiResponse;
|
import com.ycwl.basic.utils.ApiResponse;
|
||||||
import com.ycwl.basic.utils.JacksonUtil;
|
import com.ycwl.basic.utils.JacksonUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.logging.log4j.util.Strings;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ public class ScenicServiceImpl implements ScenicService {
|
|||||||
return scenicStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
return scenicStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||||
IStorageAdapter adapter;
|
IStorageAdapter adapter;
|
||||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||||
if (scenicConfig.getString("store_type") != null) {
|
if (Strings.isNotBlank(scenicConfig.getString("store_type"))) {
|
||||||
try {
|
try {
|
||||||
adapter = StorageFactory.get(scenicConfig.getString("store_type"));
|
adapter = StorageFactory.get(scenicConfig.getString("store_type"));
|
||||||
adapter.loadConfig(scenicConfig.getObject("store_config_json", Map.class));
|
adapter.loadConfig(scenicConfig.getObject("store_config_json", Map.class));
|
||||||
@@ -78,7 +79,7 @@ public class ScenicServiceImpl implements ScenicService {
|
|||||||
return scenicTmpStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
return scenicTmpStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||||
IStorageAdapter adapter;
|
IStorageAdapter adapter;
|
||||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||||
if (scenicConfig.getString("tmp_store_type") != null) {
|
if (Strings.isNotBlank(scenicConfig.getString("tmp_store_type"))) {
|
||||||
try {
|
try {
|
||||||
adapter = StorageFactory.get(scenicConfig.getString("tmp_store_type"));
|
adapter = StorageFactory.get(scenicConfig.getString("tmp_store_type"));
|
||||||
adapter.loadConfig(scenicConfig.getObject("tmp_store_config_json", Map.class));
|
adapter.loadConfig(scenicConfig.getObject("tmp_store_config_json", Map.class));
|
||||||
@@ -96,7 +97,7 @@ public class ScenicServiceImpl implements ScenicService {
|
|||||||
return scenicLocalStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
return scenicLocalStorageAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||||
IStorageAdapter adapter;
|
IStorageAdapter adapter;
|
||||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||||
if (scenicConfig.getString("local_store_type") != null) {
|
if (Strings.isNotBlank(scenicConfig.getString("local_store_type"))) {
|
||||||
try {
|
try {
|
||||||
adapter = StorageFactory.get(scenicConfig.getString("local_store_type"));
|
adapter = StorageFactory.get(scenicConfig.getString("local_store_type"));
|
||||||
adapter.loadConfig(scenicConfig.getObject("local_store_config_json", Map.class));
|
adapter.loadConfig(scenicConfig.getObject("local_store_config_json", Map.class));
|
||||||
@@ -115,7 +116,7 @@ public class ScenicServiceImpl implements ScenicService {
|
|||||||
return scenicFaceBodyAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
return scenicFaceBodyAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||||
IFaceBodyAdapter adapter;
|
IFaceBodyAdapter adapter;
|
||||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||||
if (scenicConfig.getString("face_type") != null) {
|
if (Strings.isNotBlank(scenicConfig.getString("face_type"))) {
|
||||||
adapter = FaceBodyFactory.getAdapter(scenicConfig.getString("face_type"));
|
adapter = FaceBodyFactory.getAdapter(scenicConfig.getString("face_type"));
|
||||||
adapter.loadConfig(scenicConfig.getObject("face_config_json", Map.class));
|
adapter.loadConfig(scenicConfig.getObject("face_config_json", Map.class));
|
||||||
} else {
|
} else {
|
||||||
@@ -130,7 +131,7 @@ public class ScenicServiceImpl implements ScenicService {
|
|||||||
return scenicPayAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
return scenicPayAdapterCache.computeIfAbsent(scenicId, (key) -> {
|
||||||
IPayAdapter adapter;
|
IPayAdapter adapter;
|
||||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||||
if (scenicConfig.getString("pay_type") != null) {
|
if (Strings.isNotBlank(scenicConfig.getString("pay_type"))) {
|
||||||
adapter = PayFactory.getAdapter(scenicConfig.getString("pay_type"));
|
adapter = PayFactory.getAdapter(scenicConfig.getString("pay_type"));
|
||||||
adapter.loadConfig(scenicConfig.getObject("pay_config_json", Map.class));
|
adapter.loadConfig(scenicConfig.getObject("pay_config_json", Map.class));
|
||||||
} else {
|
} else {
|
||||||
|
Reference in New Issue
Block a user