添加购物车
parent
8a35299496
commit
e4eeac9c41
|
@ -94,4 +94,11 @@ public interface HashCache <K, HK, HV> extends DecorationKey<K> {
|
|||
*/
|
||||
public void remove(K key, HK hashKey);
|
||||
|
||||
/**
|
||||
* 判断redis中hashKey是否存在
|
||||
* @param key redis键
|
||||
* @param hashKey hash键
|
||||
*/
|
||||
public boolean hasKey(K key, HK hashKey);
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,13 @@ public abstract class AtomicSequenceCacheAbs<K> implements AtomicSequenceCache<K
|
|||
*/
|
||||
@Override
|
||||
public Long get (K key) {
|
||||
return this.redisService.getCacheObject(encode(key));
|
||||
Long cacheValue = this.redisService.getCacheObject(encode(key));
|
||||
if (cacheValue == null){
|
||||
Long data = getData(key);
|
||||
cacheValue = data == null ? 0L : data;
|
||||
this.redisService.setCacheObject(encode(key), cacheValue);
|
||||
}
|
||||
return cacheValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -164,6 +164,17 @@ public abstract class HashCacheAbs<K, HK, HV> implements HashCache<K, HK, HV> {
|
|||
redisService.deleteCacheMapValue(encode(key), encodeHashKey(hashKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断redis中hashKey是否存在
|
||||
*
|
||||
* @param key redis键
|
||||
* @param hashKey hash键
|
||||
*/
|
||||
@Override
|
||||
public boolean hasKey (K key, HK hashKey) {
|
||||
return redisService.hashKey(encode(key), encodeHashKey(hashKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* 原始数据转编码数据
|
||||
* @param dataMap 原始数据
|
||||
|
|
|
@ -20,4 +20,9 @@ public class ServiceNameConstants {
|
|||
* 文件服务的serviceid
|
||||
*/
|
||||
public static final String FILE_SERVICE = "muyu-file";
|
||||
|
||||
/**
|
||||
* 商品服务
|
||||
*/
|
||||
public static final String PRODUCT_SERVICE = "muyu-product";
|
||||
}
|
||||
|
|
|
@ -232,6 +232,15 @@ public class RedisService {
|
|||
public <T> List<T> getMultiCacheMapValue (final String key, final Collection<?> hKeys) {
|
||||
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断redis中hashKey是否存在
|
||||
* @param key redis键
|
||||
* @param hashKey hash键
|
||||
*/
|
||||
public boolean hashKey(final String key, final String hashKey){
|
||||
return this.redisTemplate.opsForHash().hasKey(key, hashKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除Hash中的某条数据
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
com.muyu.product.cache.ProjectInfoCache
|
||||
com.muyu.product.cache.ProjectSkuCache
|
||||
com.muyu.product.cache.ProjectSkuStockCache
|
|
@ -0,0 +1,33 @@
|
|||
package com.muyu.product.remote;
|
||||
|
||||
import com.muyu.common.core.constant.ServiceNameConstants;
|
||||
import com.muyu.common.core.domain.Result;
|
||||
import com.muyu.product.domain.ProjectSkuInfo;
|
||||
import com.muyu.product.remote.factory.RemoteProjectSkuFactory;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
/**
|
||||
* @author DongZl
|
||||
* @description: 远程调用业务层
|
||||
* @Date 2024-4-7 上午 10:58
|
||||
*/
|
||||
@FeignClient(
|
||||
contextId = "remoteProjectSkuService",
|
||||
value = ServiceNameConstants.PRODUCT_SERVICE,
|
||||
fallbackFactory = RemoteProjectSkuFactory.class,
|
||||
path = "/sku"
|
||||
)
|
||||
public interface RemoteProjectSkuService {
|
||||
|
||||
/**
|
||||
* 通过商品ID和SKU获取SKU信息
|
||||
* @param projectId 商品ID
|
||||
* @param projectSku 商品SKU
|
||||
* @return 商品SKU信息
|
||||
*/
|
||||
@GetMapping("/info/{projectId}/{projectSku}")
|
||||
public Result<ProjectSkuInfo> getInfoByProjectIdAndSku(@PathVariable("projectId") Long projectId,
|
||||
@PathVariable("projectSku") String projectSku);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.muyu.product.remote.factory;
|
||||
|
||||
import com.muyu.common.core.domain.Result;
|
||||
import com.muyu.product.domain.ProjectSkuInfo;
|
||||
import com.muyu.product.remote.RemoteProjectSkuService;
|
||||
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
|
||||
/**
|
||||
* @author DongZl
|
||||
* @description: 远程调熔断器
|
||||
* @Date 2024-4-7 上午 10:59
|
||||
*/
|
||||
public class RemoteProjectSkuFactory implements FallbackFactory<RemoteProjectSkuService> {
|
||||
@Override
|
||||
public RemoteProjectSkuService create (Throwable cause) {
|
||||
return new RemoteProjectSkuService() {
|
||||
@Override
|
||||
public Result<ProjectSkuInfo> getInfoByProjectIdAndSku (Long projectId, String projectSku) {
|
||||
return Result.error(cause.getMessage());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
com.muyu.product.remote.factory.RemoteProjectSkuFactory
|
|
@ -21,10 +21,7 @@ public class ProjectSkuStockDataImpl implements ProjectSkuStockData {
|
|||
|
||||
@Override
|
||||
public Long getData (SkuStockKey key) {
|
||||
LambdaQueryWrapper<ProjectSkuInfo> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(ProjectSkuInfo::getProjectId, key.getProjectId());
|
||||
queryWrapper.eq(ProjectSkuInfo::getSku, key.getSku());
|
||||
ProjectSkuInfo projectSkuInfo = projectSkuInfoService.getOne(queryWrapper);
|
||||
ProjectSkuInfo projectSkuInfo = projectSkuInfoService.getInfoByProjectIdAndSku(key.getProjectId(), key.getSku());
|
||||
return projectSkuInfo.getStock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,18 @@ public class ProjectSkuInfoController extends BaseController {
|
|||
return Result.success(projectSkuInfoService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过商品ID和SKU获取SKU信息
|
||||
* @param projectId 商品ID
|
||||
* @param projectSku 商品SKU
|
||||
* @return 商品SKU信息
|
||||
*/
|
||||
@GetMapping("/info/{projectId}/{projectSku}")
|
||||
public Result<ProjectSkuInfo> getInfoByProjectIdAndSku(@PathVariable("projectId") Long projectId,
|
||||
@PathVariable("projectSku") String projectSku){
|
||||
return Result.success(projectSkuInfoService.getInfoByProjectIdAndSku(projectId, projectSku));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增商品SKU
|
||||
*/
|
||||
|
|
|
@ -19,4 +19,11 @@ public interface ProjectSkuInfoService extends IService<ProjectSkuInfo> {
|
|||
*/
|
||||
public List<ProjectSkuInfo> list(ProjectSkuInfo projectSkuInfo);
|
||||
|
||||
/**
|
||||
* 通过商品ID和SKU获取SKU信息
|
||||
* @param projectId 商品ID
|
||||
* @param projectSku 商品SKU
|
||||
* @return 商品SKU信息
|
||||
*/
|
||||
ProjectSkuInfo getInfoByProjectIdAndSku (Long projectId, String projectSku);
|
||||
}
|
||||
|
|
|
@ -58,4 +58,20 @@ public class ProjectSkuInfoServiceImpl extends ServiceImpl<ProjectSkuInfoMapper,
|
|||
|
||||
return list(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过商品ID和SKU获取SKU信息
|
||||
*
|
||||
* @param projectId 商品ID
|
||||
* @param projectSku 商品SKU
|
||||
*
|
||||
* @return 商品SKU信息
|
||||
*/
|
||||
@Override
|
||||
public ProjectSkuInfo getInfoByProjectIdAndSku (Long projectId, String projectSku) {
|
||||
LambdaQueryWrapper<ProjectSkuInfo> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(ProjectSkuInfo::getProjectId, projectId);
|
||||
queryWrapper.eq(ProjectSkuInfo::getSku, projectSku);
|
||||
return this.getOne(queryWrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,9 +82,7 @@ public class CartInfo extends BaseEntity {
|
|||
return CartInfo.builder()
|
||||
.projectId(cartInfoSaveReq.getProjectId())
|
||||
.projectSku(cartInfoSaveReq.getProjectSku())
|
||||
.userId(cartInfoSaveReq.getUserId())
|
||||
.num(cartInfoSaveReq.getNum())
|
||||
.isSelected(cartInfoSaveReq.getIsSelected())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,34 +23,17 @@ public class CartInfoSaveReq extends BaseEntity {
|
|||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键 */
|
||||
|
||||
@ApiModelProperty(name = "主键", value = "主键")
|
||||
private Long id;
|
||||
|
||||
/** 商品 */
|
||||
|
||||
@ApiModelProperty(name = "商品", value = "商品", required = true)
|
||||
private Long projectId;
|
||||
|
||||
/** SKU */
|
||||
|
||||
@ApiModelProperty(name = "SKU", value = "SKU", required = true)
|
||||
private String projectSku;
|
||||
|
||||
/** 用户 */
|
||||
|
||||
@ApiModelProperty(name = "用户", value = "用户", required = true)
|
||||
private Long userId;
|
||||
|
||||
/** 数量 */
|
||||
|
||||
@ApiModelProperty(name = "数量", value = "数量", required = true)
|
||||
private Long num;
|
||||
|
||||
/** 是否选中 */
|
||||
|
||||
@ApiModelProperty(name = "是否选中", value = "是否选中", required = true)
|
||||
private String isSelected;
|
||||
|
||||
}
|
||||
|
|
|
@ -92,6 +92,18 @@
|
|||
<artifactId>muyu-shop-cart-cache</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 商品模块 缓存 依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.muyu</groupId>
|
||||
<artifactId>muyu-product-cache</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 商品模块 远程调用 依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.muyu</groupId>
|
||||
<artifactId>muyu-product-remote</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package com.muyu.shop.cart.cache.impl;
|
||||
|
||||
import com.muyu.product.cache.datasource.ProjectInfoData;
|
||||
import com.muyu.product.domain.ProjectInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author DongZl
|
||||
* @description: 缓存数据获取
|
||||
* @Date 2024-3-27 下午 03:37
|
||||
*/
|
||||
@Service
|
||||
public class ProjectInfoDataImpl implements ProjectInfoData {
|
||||
|
||||
/**
|
||||
* 从数据库获取数据
|
||||
* @param key ID
|
||||
* @return 缓存对象
|
||||
*/
|
||||
@Override
|
||||
public ProjectInfo getData (Long key) {
|
||||
return new ProjectInfo();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.muyu.shop.cart.cache.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.muyu.product.cache.datasource.ProjectSkuData;
|
||||
import com.muyu.product.domain.ProjectSkuInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author DongZl
|
||||
* @description: 商品SKU实现类
|
||||
* @Date 2024-4-1 上午 11:38
|
||||
*/
|
||||
@Service
|
||||
public class ProjectSkuDataImpl implements ProjectSkuData {
|
||||
|
||||
|
||||
/**
|
||||
* 通过键获取所有的hash数据
|
||||
* @param projectId 商品ID
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map<String, ProjectSkuInfo> getData (Long projectId) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过缓存键和hash键获取hash值
|
||||
* @param projectId 商品ID
|
||||
* @param projectSku 商品SKU
|
||||
* @return hash值
|
||||
*/
|
||||
@Override
|
||||
public ProjectSkuInfo getData (Long projectId, String projectSku) {
|
||||
return new ProjectSkuInfo();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.muyu.shop.cart.cache.impl;
|
||||
|
||||
import com.muyu.common.core.domain.Result;
|
||||
import com.muyu.product.cache.datasource.ProjectSkuStockData;
|
||||
import com.muyu.product.cache.key.SkuStockKey;
|
||||
import com.muyu.product.domain.ProjectSkuInfo;
|
||||
import com.muyu.product.remote.RemoteProjectSkuService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author DongZl
|
||||
* @description: sku库存实现类
|
||||
* @Date 2024-4-2 上午 10:53
|
||||
*/
|
||||
@Service
|
||||
public class ProjectSkuStockDataRemoteImpl implements ProjectSkuStockData {
|
||||
|
||||
@Autowired
|
||||
private RemoteProjectSkuService remoteProjectSkuService;
|
||||
|
||||
@Override
|
||||
public Long getData (SkuStockKey key) {
|
||||
Result<ProjectSkuInfo> result
|
||||
= remoteProjectSkuService.getInfoByProjectIdAndSku(key.getProjectId(), key.getSku());
|
||||
if (Result.isSuccess(result)){
|
||||
ProjectSkuInfo projectSkuInfo = result.getData();
|
||||
if (!Objects.isNull(projectSkuInfo)){
|
||||
return projectSkuInfo.getStock();
|
||||
}
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
}
|
|
@ -83,7 +83,7 @@ public class CartInfoController extends BaseController {
|
|||
@PostMapping
|
||||
@ApiOperation("新增购物车")
|
||||
public Result<String> add(@RequestBody CartInfoSaveReq cartInfoSaveReq) {
|
||||
return toAjax(cartInfoService.save(CartInfo.saveBuild(cartInfoSaveReq)));
|
||||
return toAjax(cartInfoService.add(CartInfo.saveBuild(cartInfoSaveReq)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,4 +19,10 @@ public interface CartInfoService extends IService<CartInfo> {
|
|||
*/
|
||||
public List<CartInfo> list(CartInfo cartInfo);
|
||||
|
||||
/**
|
||||
* 添加购物车
|
||||
* @param cartInfo 购物车信息
|
||||
* @return 是否添加成功
|
||||
*/
|
||||
boolean add (CartInfo cartInfo);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
package com.muyu.shop.cart.service.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.muyu.common.core.exception.ServiceException;
|
||||
import com.muyu.common.core.text.Convert;
|
||||
import com.muyu.common.core.utils.ObjUtils;
|
||||
import com.muyu.common.security.utils.SecurityUtils;
|
||||
import com.muyu.product.cache.ProjectSkuStockCache;
|
||||
import com.muyu.product.cache.key.SkuStockKey;
|
||||
import com.muyu.shop.cart.cache.CartCache;
|
||||
import com.muyu.shop.cart.cache.key.CartHashKey;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.muyu.shop.cart.mapper.CartInfoMapper;
|
||||
import com.muyu.shop.cart.domain.CartInfo;
|
||||
|
@ -21,6 +31,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||
@Service
|
||||
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {
|
||||
|
||||
@Autowired
|
||||
private CartCache cartCache;
|
||||
|
||||
@Autowired
|
||||
private ProjectSkuStockCache projectSkuStockCache;
|
||||
|
||||
/**
|
||||
* 查询购物车列表
|
||||
*
|
||||
|
@ -52,10 +68,53 @@ public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo>
|
|||
queryWrapper.eq(CartInfo::getIsSelected, cartInfo.getIsSelected());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return list(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加购物车
|
||||
*
|
||||
* @param cartInfo 购物车信息
|
||||
*
|
||||
* @return 是否添加成功
|
||||
*/
|
||||
@Override
|
||||
public boolean add (CartInfo cartInfo) {
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
CartHashKey cartHashKey = CartHashKey.builder()
|
||||
.projectId(cartInfo.getProjectId())
|
||||
.projectSku(cartInfo.getProjectSku())
|
||||
.build();
|
||||
SkuStockKey skuStockKey = SkuStockKey.builder()
|
||||
.projectId(cartInfo.getProjectId())
|
||||
.sku(cartInfo.getProjectSku())
|
||||
.build();
|
||||
Long skuStock = Convert.toLong(projectSkuStockCache.get(skuStockKey), -1L);
|
||||
if (cartCache.hasKey(userId, cartHashKey)){
|
||||
// 取出来修改
|
||||
CartInfo cartInfoCache = cartCache.get(userId, cartHashKey);
|
||||
cartInfoCache.setNum( cartInfoCache.getNum() + cartInfo.getNum());
|
||||
if (skuStock < cartInfoCache.getNum()){
|
||||
throw new ServiceException("当前库存不足");
|
||||
}
|
||||
LambdaUpdateWrapper<CartInfo> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.set(CartInfo::getNum, cartInfoCache.getNum());
|
||||
updateWrapper.eq(CartInfo::getId, cartInfoCache.getId());
|
||||
this.update(updateWrapper);
|
||||
this.cartCache.put(userId, cartHashKey, cartInfoCache);
|
||||
}else {
|
||||
// 存进去
|
||||
if (skuStock < cartInfo.getNum()){
|
||||
throw new ServiceException("当前库存不足");
|
||||
}
|
||||
cartInfo.setIsSelected("Y");
|
||||
cartInfo.setUserId(userId);
|
||||
cartInfo.setCreateBy(SecurityUtils.getUsername());
|
||||
cartInfo.setCreateTime(new Date());
|
||||
this.save(cartInfo);
|
||||
this.cartCache.put(userId, cartHashKey, cartInfo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,13 +42,17 @@ public class CartDataImpl implements CartData {
|
|||
/**
|
||||
* 通过缓存键和hash键获取hash值
|
||||
*
|
||||
* @param key 缓存键
|
||||
* @param userId 缓存键
|
||||
* @param hashKey hash键
|
||||
*
|
||||
* @return hash值
|
||||
*/
|
||||
@Override
|
||||
public CartInfo getData (Long key, CartHashKey hashKey) {
|
||||
return null;
|
||||
public CartInfo getData (Long userId, CartHashKey hashKey) {
|
||||
LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(CartInfo::getUserId, userId);
|
||||
queryWrapper.eq(CartInfo::getProjectId, hashKey.getProjectId());
|
||||
queryWrapper.eq(CartInfo::getProjectSku, hashKey.getProjectSku());
|
||||
return cartInfoService.getOne(queryWrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ server:
|
|||
|
||||
# Spring
|
||||
spring:
|
||||
main:
|
||||
allow-circular-references: true
|
||||
application:
|
||||
# 应用名称
|
||||
name: muyu-shop-cart
|
||||
|
|
Loading…
Reference in New Issue