添加购物车

master
DongZeLiang 2024-04-07 11:41:25 +08:00
parent 8a35299496
commit e4eeac9c41
24 changed files with 330 additions and 32 deletions

View File

@ -94,4 +94,11 @@ public interface HashCache <K, HK, HV> extends DecorationKey<K> {
*/ */
public void remove(K key, HK hashKey); public void remove(K key, HK hashKey);
/**
* redishashKey
* @param key redis
* @param hashKey hash
*/
public boolean hasKey(K key, HK hashKey);
} }

View File

@ -21,7 +21,13 @@ public abstract class AtomicSequenceCacheAbs<K> implements AtomicSequenceCache<K
*/ */
@Override @Override
public Long get (K key) { 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;
} }
/** /**

View File

@ -164,6 +164,17 @@ public abstract class HashCacheAbs<K, HK, HV> implements HashCache<K, HK, HV> {
redisService.deleteCacheMapValue(encode(key), encodeHashKey(hashKey)); redisService.deleteCacheMapValue(encode(key), encodeHashKey(hashKey));
} }
/**
* redishashKey
*
* @param key redis
* @param hashKey hash
*/
@Override
public boolean hasKey (K key, HK hashKey) {
return redisService.hashKey(encode(key), encodeHashKey(hashKey));
}
/** /**
* *
* @param dataMap * @param dataMap

View File

@ -20,4 +20,9 @@ public class ServiceNameConstants {
* serviceid * serviceid
*/ */
public static final String FILE_SERVICE = "muyu-file"; public static final String FILE_SERVICE = "muyu-file";
/**
*
*/
public static final String PRODUCT_SERVICE = "muyu-product";
} }

View File

@ -232,6 +232,15 @@ public class RedisService {
public <T> List<T> getMultiCacheMapValue (final String key, final Collection<?> hKeys) { public <T> List<T> getMultiCacheMapValue (final String key, final Collection<?> hKeys) {
return redisTemplate.opsForHash().multiGet(key, hKeys); return redisTemplate.opsForHash().multiGet(key, hKeys);
} }
/**
* redishashKey
* @param key redis
* @param hashKey hash
*/
public boolean hashKey(final String key, final String hashKey){
return this.redisTemplate.opsForHash().hasKey(key, hashKey);
}
/** /**
* Hash * Hash

View File

@ -0,0 +1,3 @@
com.muyu.product.cache.ProjectInfoCache
com.muyu.product.cache.ProjectSkuCache
com.muyu.product.cache.ProjectSkuStockCache

View File

@ -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 {
/**
* IDSKUSKU
* @param projectId ID
* @param projectSku SKU
* @return SKU
*/
@GetMapping("/info/{projectId}/{projectSku}")
public Result<ProjectSkuInfo> getInfoByProjectIdAndSku(@PathVariable("projectId") Long projectId,
@PathVariable("projectSku") String projectSku);
}

View File

@ -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());
}
};
}
}

View File

@ -21,10 +21,7 @@ public class ProjectSkuStockDataImpl implements ProjectSkuStockData {
@Override @Override
public Long getData (SkuStockKey key) { public Long getData (SkuStockKey key) {
LambdaQueryWrapper<ProjectSkuInfo> queryWrapper = new LambdaQueryWrapper<>(); ProjectSkuInfo projectSkuInfo = projectSkuInfoService.getInfoByProjectIdAndSku(key.getProjectId(), key.getSku());
queryWrapper.eq(ProjectSkuInfo::getProjectId, key.getProjectId());
queryWrapper.eq(ProjectSkuInfo::getSku, key.getSku());
ProjectSkuInfo projectSkuInfo = projectSkuInfoService.getOne(queryWrapper);
return projectSkuInfo.getStock(); return projectSkuInfo.getStock();
} }
} }

View File

@ -75,6 +75,18 @@ public class ProjectSkuInfoController extends BaseController {
return Result.success(projectSkuInfoService.getById(id)); return Result.success(projectSkuInfoService.getById(id));
} }
/**
* IDSKUSKU
* @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 * SKU
*/ */

View File

@ -19,4 +19,11 @@ public interface ProjectSkuInfoService extends IService<ProjectSkuInfo> {
*/ */
public List<ProjectSkuInfo> list(ProjectSkuInfo projectSkuInfo); public List<ProjectSkuInfo> list(ProjectSkuInfo projectSkuInfo);
/**
* IDSKUSKU
* @param projectId ID
* @param projectSku SKU
* @return SKU
*/
ProjectSkuInfo getInfoByProjectIdAndSku (Long projectId, String projectSku);
} }

View File

@ -58,4 +58,20 @@ public class ProjectSkuInfoServiceImpl extends ServiceImpl<ProjectSkuInfoMapper,
return list(queryWrapper); return list(queryWrapper);
} }
/**
* IDSKUSKU
*
* @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);
}
} }

View File

@ -82,9 +82,7 @@ public class CartInfo extends BaseEntity {
return CartInfo.builder() return CartInfo.builder()
.projectId(cartInfoSaveReq.getProjectId()) .projectId(cartInfoSaveReq.getProjectId())
.projectSku(cartInfoSaveReq.getProjectSku()) .projectSku(cartInfoSaveReq.getProjectSku())
.userId(cartInfoSaveReq.getUserId())
.num(cartInfoSaveReq.getNum()) .num(cartInfoSaveReq.getNum())
.isSelected(cartInfoSaveReq.getIsSelected())
.build(); .build();
} }

View File

@ -23,34 +23,17 @@ public class CartInfoSaveReq extends BaseEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 主键 */
@ApiModelProperty(name = "主键", value = "主键")
private Long id;
/** 商品 */ /** 商品 */
@ApiModelProperty(name = "商品", value = "商品", required = true) @ApiModelProperty(name = "商品", value = "商品", required = true)
private Long projectId; private Long projectId;
/** SKU */ /** SKU */
@ApiModelProperty(name = "SKU", value = "SKU", required = true) @ApiModelProperty(name = "SKU", value = "SKU", required = true)
private String projectSku; private String projectSku;
/** 用户 */
@ApiModelProperty(name = "用户", value = "用户", required = true)
private Long userId;
/** 数量 */ /** 数量 */
@ApiModelProperty(name = "数量", value = "数量", required = true) @ApiModelProperty(name = "数量", value = "数量", required = true)
private Long num; private Long num;
/** 是否选中 */
@ApiModelProperty(name = "是否选中", value = "是否选中", required = true)
private String isSelected;
} }

View File

@ -92,6 +92,18 @@
<artifactId>muyu-shop-cart-cache</artifactId> <artifactId>muyu-shop-cart-cache</artifactId>
</dependency> </dependency>
<!-- 商品模块 缓存 依赖 -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-product-cache</artifactId>
</dependency>
<!-- 商品模块 远程调用 依赖 -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-product-remote</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -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();
}
}

View File

@ -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<>();
}
/**
* hashhash
* @param projectId ID
* @param projectSku SKU
* @return hash
*/
@Override
public ProjectSkuInfo getData (Long projectId, String projectSku) {
return new ProjectSkuInfo();
}
}

View File

@ -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;
}
}

View File

@ -83,7 +83,7 @@ public class CartInfoController extends BaseController {
@PostMapping @PostMapping
@ApiOperation("新增购物车") @ApiOperation("新增购物车")
public Result<String> add(@RequestBody CartInfoSaveReq cartInfoSaveReq) { public Result<String> add(@RequestBody CartInfoSaveReq cartInfoSaveReq) {
return toAjax(cartInfoService.save(CartInfo.saveBuild(cartInfoSaveReq))); return toAjax(cartInfoService.add(CartInfo.saveBuild(cartInfoSaveReq)));
} }
/** /**

View File

@ -19,4 +19,10 @@ public interface CartInfoService extends IService<CartInfo> {
*/ */
public List<CartInfo> list(CartInfo cartInfo); public List<CartInfo> list(CartInfo cartInfo);
/**
*
* @param cartInfo
* @return
*/
boolean add (CartInfo cartInfo);
} }

View File

@ -1,9 +1,19 @@
package com.muyu.shop.cart.service.impl; package com.muyu.shop.cart.service.impl;
import java.util.Date;
import java.util.List; 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.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 lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.muyu.shop.cart.mapper.CartInfoMapper; import com.muyu.shop.cart.mapper.CartInfoMapper;
import com.muyu.shop.cart.domain.CartInfo; import com.muyu.shop.cart.domain.CartInfo;
@ -21,6 +31,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@Service @Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService { 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()); queryWrapper.eq(CartInfo::getIsSelected, cartInfo.getIsSelected());
} }
return list(queryWrapper); 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;
}
} }

View File

@ -42,13 +42,17 @@ public class CartDataImpl implements CartData {
/** /**
* hashhash * hashhash
* *
* @param key * @param userId
* @param hashKey hash * @param hashKey hash
* *
* @return hash * @return hash
*/ */
@Override @Override
public CartInfo getData (Long key, CartHashKey hashKey) { public CartInfo getData (Long userId, CartHashKey hashKey) {
return null; 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);
} }
} }

View File

@ -4,6 +4,8 @@ server:
# Spring # Spring
spring: spring:
main:
allow-circular-references: true
application: application:
# 应用名称 # 应用名称
name: muyu-shop-cart name: muyu-shop-cart