购物车

master
baize 2024-04-08 17:13:42 +08:00
parent 2155eeab10
commit 51049930ec
51 changed files with 1096 additions and 78 deletions

View File

@ -84,4 +84,13 @@ public interface HashCache <K,Hk,HV> extends DecorationKey<K> {
* @param hashKey hash
*/
public void remove(K key,Hk hashKey);
/**
* redishashKey
* @param key redis
* @param hashKey hash
* @return
*/
public boolean hashKey(K key , Hk hashKey);
}

View File

@ -22,7 +22,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;
}
/**

View File

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

View File

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

View File

@ -221,6 +221,15 @@ public class RedisService {
return opsForHash.get(key, hKey);
}
/**
* redishashKey
* @param key redis
* @param hashKey hash
*/
public Boolean hasKey (final String key,final String hashKey) {
return redisTemplate.opsForHash().hasKey(key,hashKey);
}
/**
* Hash
*

View File

@ -23,10 +23,10 @@
<artifactId>muyu-common-cache</artifactId>
</dependency>
<!--商品模块 common依赖-->
<!--商品模块 远程调用 依赖-->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-product-common</artifactId>
<artifactId>muyu-product-remote</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,38 @@
package com.muyu.product.cache;
import com.muyu.cache.abs.CacheAbs;
import com.muyu.common.core.text.Convert;
import com.muyu.product.cache.datasource.RuleCacheData;
import com.muyu.product.cache.model.RuleCacheModel;
import org.springframework.beans.factory.annotation.Autowired;
/**
* RuleInfoCache
*
* @author DeKangLiu
* on 2024/4/8
*/
public class RuleInfoCache extends CacheAbs<Long, RuleCacheModel> {
@Autowired
private RuleCacheData ruleCacheData;
@Override
public String keyPre() {
return "rule:info";
}
@Override
public Long decode(String redisKey) {
return Convert.toLong(redisKey.replace(keyPre(),""));
}
@Override
public RuleCacheModel getData(Long key) {
return ruleCacheData.getRuleCacheModel(key);
}
@Override
public RuleCacheModel defaultValue() {
return new RuleCacheModel();
}
}

View File

@ -0,0 +1,13 @@
package com.muyu.product.cache.datasource;
import com.muyu.product.cache.model.RuleCacheModel;
/**
* RuleCacheData
*
* @author DeKangLiu
* on 2024/4/8
*/
public interface RuleCacheData {
public RuleCacheModel getRuleCacheModel(Long ruleId);
}

View File

@ -0,0 +1,28 @@
package com.muyu.product.cache.datasource.impl;
import com.muyu.common.core.domain.Result;
import com.muyu.product.cache.datasource.ProjectInfoData;
import com.muyu.product.domain.ProjectInfo;
import com.muyu.product.remote.RemoteProjectInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* ProjectInfoDataRemoteImpl
*
* @author DeKangLiu
* on 2024/4/8
*/
@Service
public class ProjectInfoDataRemoteImpl implements ProjectInfoData{
@Autowired
private RemoteProjectInfoService remoteProjectInfoService;
@Override
public ProjectInfo getData(Long key) {
Result<ProjectInfo> projectInfoResult = remoteProjectInfoService.getInfo(key);
if (Result.isError(projectInfoResult)){
return new ProjectInfo();
}
return projectInfoResult.getData();
}
}

View File

@ -0,0 +1,48 @@
package com.muyu.product.cache.datasource.impl;
import com.muyu.common.core.domain.Result;
import com.muyu.product.cache.datasource.ProjectSkuData;
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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* ProjectSkuDataRemoteImpl
*
* @author DeKangLiu
* on 2024/4/8
*/
@Service
public class ProjectSkuDataRemoteImpl implements ProjectSkuData{
@Autowired
private RemoteProjectSkuService remoteProjectSkuService;
@Override
public Map<String, ProjectSkuInfo> getData(Long projectId) {
Result<List<ProjectSkuInfo>> projectListResult =
remoteProjectSkuService.listByProjectId(projectId);
if (Result.isError(projectListResult)){
return new HashMap<>();
}
List<ProjectSkuInfo> projectSkuInfoList = projectListResult.getData();
return projectSkuInfoList.stream()
.collect(Collectors.toMap(ProjectSkuInfo::getSku,projectSkuInfo -> projectSkuInfo));
}
@Override
public ProjectSkuInfo getData(Long projectId, String projectSku) {
Result<ProjectSkuInfo> projectSkuInfoResult = remoteProjectSkuService.getInfoByProjectIdAndSku(
projectId, projectSku
);
if (Result.isError(projectSkuInfoResult)){
return new ProjectSkuInfo();
}
return projectSkuInfoResult.getData();
}
}

View File

@ -0,0 +1,37 @@
package com.muyu.product.cache.datasource.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;
/**
* ProjectSkuStockDataImpl
*
* @author DeKangLiu
* on 2024/4/8
*/
@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

@ -0,0 +1,47 @@
package com.muyu.product.cache.datasource.impl;
import com.muyu.common.core.domain.Result;
import com.muyu.product.cache.datasource.RuleCacheData;
import com.muyu.product.cache.model.RuleAttrCacheModel;
import com.muyu.product.cache.model.RuleCacheModel;
import com.muyu.product.domain.RuleAttrInfo;
import com.muyu.product.domain.RuleInfo;
import com.muyu.product.remote.RemoteRuleAttrService;
import com.muyu.product.remote.RemoteRuleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* RuleCacheDataRemoteImpl
*
* @author DeKangLiu
* on 2024/4/8
*/
@Service
public class RuleCacheDataRemoteImpl implements RuleCacheData{
@Autowired
private RemoteRuleService remoteRuleService;
@Autowired
private RemoteRuleAttrService remoteRuleAttrService;
@Override
public RuleCacheModel getRuleCacheModel(Long ruleId) {
Result<RuleInfo> ruleInfoResult = remoteRuleService.getInfo(ruleId);
Result<List<RuleAttrInfo>> ruleAttrResult = remoteRuleAttrService.getInfoByRuleId(ruleId);
if (Result.isError(ruleInfoResult)||Result.isError(ruleAttrResult)){
return new RuleCacheModel();
}
RuleInfo ruleInfo = ruleInfoResult.getData();
List<RuleAttrInfo> ruleAttrInfoList = ruleAttrResult.getData();
List<RuleAttrCacheModel> attrCacheModelList = ruleAttrInfoList.stream()
.map(RuleAttrCacheModel::ruleAttrBuild)
.toList();
return RuleCacheModel.builder()
.ruleName(ruleInfo.getName())
.ruleAttrModelList(attrCacheModelList)
.build();
}
}

View File

@ -0,0 +1,40 @@
package com.muyu.product.cache.model;
import com.muyu.product.domain.RuleAttrInfo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Arrays;
import java.util.List;
/**
* RuleAttrCacheModel
*
* @author DeKangLiu
* on 2024/4/8
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RuleAttrCacheModel {
/**
*
*/
private String attrName;
/**
*
*/
private List<String> attrValueList;
public static RuleAttrCacheModel ruleAttrBuild(RuleAttrInfo ruleAttrInfo){
return RuleAttrCacheModel.builder()
.attrName(ruleAttrInfo.getName())
.attrValueList(Arrays.stream(ruleAttrInfo.getAttrValue().split(",")).toList())
.build();
}
}

View File

@ -0,0 +1,31 @@
package com.muyu.product.cache.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* RuleCacheModel
*
* @author DeKangLiu
* on 2024/4/8
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RuleCacheModel {
/**
*
*/
private String ruleName;
/**
*
*/
private List<RuleAttrCacheModel> ruleAttrModelList;
}

View File

@ -0,0 +1,8 @@
com.muyu.product.cache.ProjectInfoCache
com.muyu.product.cache.ProjectSkuCache
com.muyu.product.cache.ProjectSkuStockCache
com.muyu.product.cache.RuleInfoCache
com.muyu.product.cache.datasource.impl.RuleCacheDataRemoteImpl
com.muyu.product.cache.datasource.impl.ProjectInfoDataRemoteImpl
com.muyu.product.cache.datasource.impl.ProjectSkuDataRemoteImpl
com.muyu.product.cache.datasource.impl.ProjectSkuStockDataRemoteImpl

View File

@ -1,35 +0,0 @@
{
"品牌":
{
"id"
"品牌中间表"
}
"轮播图"
"名称":
"价格"
"商品规格"{
"规格详情表"
}
}
商品信息 商品品类 品类信息
{
"商品品类":[
"品类id":
"品类名称"
]
"商品轮播图":
"商品名称":
"商品价格":
"商品规格":[
{
"规格id"
"规格值"
}
]
"商品数量"
"商品图片"
自由属性:[]
}

View File

@ -0,0 +1,30 @@
package com.muyu.product.remote;
import com.muyu.common.core.constant.ServiceNameConstants;
import com.muyu.common.core.domain.Result;
import com.muyu.product.domain.ProjectInfo;
import com.muyu.product.remote.factory.RemoteProjectInfoFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* RemoteProjectInfoService
*
* @author DeKangLiu
* on 2024/4/8
*/
@FeignClient(
contextId = "remoteProjectInfoService",
value = ServiceNameConstants.PRODUCT_SERVICE,
fallbackFactory = RemoteProjectInfoFactory.class,
path = "/info"
)
public interface RemoteProjectInfoService {
/**
*
*/
@GetMapping(value = "/{id}")
public Result<ProjectInfo> getInfo(@PathVariable("id") Long id);
}

View File

@ -0,0 +1,38 @@
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;
import java.util.List;
/**
* @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);
@GetMapping("/list/{projectId}")
public Result<List<ProjectSkuInfo>> listByProjectId(@PathVariable("projectId") Long projectId);
}

View File

@ -0,0 +1,29 @@
package com.muyu.product.remote;
import com.muyu.common.core.constant.ServiceNameConstants;
import com.muyu.common.core.domain.Result;
import com.muyu.product.domain.RuleAttrInfo;
import com.muyu.product.remote.factory.RemoteRuleAttrFactory;
import com.muyu.product.remote.factory.RemoteRuleFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
/**
* RemoteRuleAttrService
*
* @author DeKangLiu
* on 2024/4/8
*/
@FeignClient(
contextId = "remoteRuleAttrService",
value = ServiceNameConstants.PRODUCT_SERVICE,
fallbackFactory = RemoteRuleAttrFactory.class,
path = "/ruleAttr"
)
public interface RemoteRuleAttrService {
@GetMapping(value = "/list/ruleId/{ruleId}")
public Result<List<RuleAttrInfo>> getInfoByRuleId(@PathVariable("ruleId") Long id);
}

View File

@ -0,0 +1,29 @@
package com.muyu.product.remote;
import com.muyu.common.core.constant.ServiceNameConstants;
import com.muyu.common.core.domain.Result;
import com.muyu.product.domain.RuleInfo;
import com.muyu.product.remote.factory.RemoteRuleAttrFactory;
import com.muyu.product.remote.factory.RemoteRuleFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* RemoteRuleService
*
* @author DeKangLiu
* on 2024/4/8
*/
@FeignClient(
contextId = "remoteRuleService",
value = ServiceNameConstants.PRODUCT_SERVICE,
fallbackFactory = RemoteRuleFactory.class,
path = "/rule"
)
public interface RemoteRuleService {
@GetMapping("/{id}")
public Result<RuleInfo> getInfo(@PathVariable("id") Long id);
}

View File

@ -0,0 +1,25 @@
package com.muyu.product.remote.factory;
import com.muyu.common.core.domain.Result;
import com.muyu.product.domain.ProjectInfo;
import com.muyu.product.remote.RemoteProjectInfoService;
import org.springframework.cloud.openfeign.FallbackFactory;
/**
* RemoteProjectInfoFactory
*
* @author DeKangLiu
* on 2024/4/8
*/
public class RemoteProjectInfoFactory implements FallbackFactory<RemoteProjectInfoService>{
@Override
public RemoteProjectInfoService create(Throwable cause) {
return new RemoteProjectInfoService() {
@Override
public Result<ProjectInfo> getInfo(Long id) {
return Result.error(cause.getMessage());
}
};
}
}

View File

@ -0,0 +1,30 @@
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;
import java.util.List;
/**
* @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());
}
@Override
public Result<List<ProjectSkuInfo>> listByProjectId(Long projectId) {
return Result.error(cause.getMessage());
}
};
}
}

View File

@ -0,0 +1,10 @@
package com.muyu.product.remote.factory;
/**
* RemoteRuleAttrFactory
*
* @author DeKangLiu
* on 2024/4/8
*/
public class RemoteRuleAttrFactory {
}

View File

@ -0,0 +1,10 @@
package com.muyu.product.remote.factory;
/**
* RemoteRuleFactory
*
* @author DeKangLiu
* on 2024/4/8
*/
public class RemoteRuleFactory {
}

View File

@ -0,0 +1,4 @@
com.muyu.product.remote.factory.RemoteProjectSkuFactory
com.muyu.product.remote.factory.RemoteProjectInfoFactory
com.muyu.product.remote.factory.RemoteRuleAttrFactory
com.muyu.product.remote.factory.RemoteRuleFactory

View File

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

View File

@ -75,6 +75,11 @@ public class ProjectSkuInfoController extends BaseController {
return Result.success(projectSkuInfoService.getById(id));
}
@GetMapping("/info/{projectId}/{projectSku}")
public Result<ProjectSkuInfo> getInfoByProjectIdAndSku(@PathVariable("projectId") Long projectId,
@PathVariable("projectSku") String projectSku){
return Result.success(projectSkuInfoService.getInfoByProjectIdAndSku(projectId,projectSku));
}
/**
* SKU
*/

View File

@ -75,6 +75,13 @@ public class RuleAttrInfoController extends BaseController {
return Result.success(ruleAttrInfoService.getById(id));
}
/**
*
*/
@GetMapping(value = "/list/ruleId/{ruleId}")
public Result<List<RuleAttrInfo>> getInfoByRuleId(@PathVariable("ruleId") Long ruleId){
return Result.success(ruleAttrInfoService.getInfoByRuleId(ruleId));
}
/**
*
*/

View File

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

View File

@ -19,4 +19,5 @@ public interface RuleAttrInfoService extends IService<RuleAttrInfo> {
*/
public List<RuleAttrInfo> list(RuleAttrInfo ruleAttrInfo);
List<RuleAttrInfo> getInfoByRuleId(Long ruleId);
}

View File

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

@ -50,4 +50,12 @@ public class RuleAttrInfoServiceImpl extends ServiceImpl<RuleAttrInfoMapper, Rul
return list(queryWrapper);
}
@Override
public List<RuleAttrInfo> getInfoByRuleId(Long ruleId) {
LambdaQueryWrapper<RuleAttrInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(RuleAttrInfo::getRuleId,ruleId);
return this.list(queryWrapper);
}
}

View File

@ -1,7 +1,7 @@
package com.muy.shop.cart.cache;
package com.muyu.shop.cart.cache;
import com.muy.shop.cart.cache.key.CartHashKey;
import com.muy.shop.cart.cache.sourcedata.CartData;
import com.muyu.shop.cart.cache.key.CartHashKey ;
import com.muyu.shop.cart.cache.sourcedata.CartData;
import com.muyu.cache.abs.HashCacheAbs;
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.exception.ServiceException;

View File

@ -0,0 +1,35 @@
package com.muyu.shop.cart.cache;
import com.muyu.cache.abs.CacheAbs;
import org.springframework.stereotype.Component;
/**
* RuleCache
*
* @author DeKangLiu
* on 2024/4/8
*/
@Component
public class RuleCache<K,V> extends CacheAbs<K,V>{
@Override
public V getData(K key) {
return null;
}
@Override
public V defaultValue() {
return null;
}
@Override
public String keyPre() {
return null;
}
@Override
public K decode(String redisKey) {
return null;
}
}

View File

@ -1,4 +1,4 @@
package com.muy.shop.cart.cache.key;
package com.muyu.shop.cart.cache.key;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -6,23 +6,23 @@ import lombok.Data;
import lombok.NoArgsConstructor;
/**
* CartHashKey
*
* @author DeKangLiu
* on 2024/4/2
* @author DongZl
* @description: HashKey
* @Date 2024-4-2 11:25
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CartHashKey {
/**
* ID
*/
private Long projectId;
/**
* sku
* SKU
*/
private String projectSku;
}

View File

@ -1,7 +1,7 @@
package com.muy.shop.cart.cache.sourcedata;
package com.muyu.shop.cart.cache.sourcedata;
import com.muy.shop.cart.cache.key.CartHashKey;
import com.muyu.shop.cart.domain.CartInfo;
import com.muyu.shop.cart.cache.key.CartHashKey;
import java.util.Map;

View File

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

View File

@ -0,0 +1,72 @@
package com.muyu.shop.cart.domain.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.List;
/**
* CartSkuModel
*
* @author DeKangLiu
* on 2024/4/7
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CartSkuModel {
/**
* id
*/
private Long cartInfoId;
/**
*
*/
private String images;
/**
* ID
*/
private Long projectId;
/**
*
*/
private String name;
/**
* SKU
*/
private BigDecimal price;
/**
* Sku
*/
private List<SkuRuleModel> skuRuleList;
/**
*
*/
private Long num;
/**
*
*/
private Long stock;
/**
*
*/
private BigDecimal subtotal;
/**
*
*/
private String isSelected;
}

View File

@ -0,0 +1,29 @@
package com.muyu.shop.cart.domain.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* SkuRuleModel
*
* @author DeKangLiu
* on 2024/4/7
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SkuRuleModel {
/**
*
*/
private String ruleName;
/**
*
*/
private String ruleValue;
}

View File

@ -0,0 +1,41 @@
package com.muyu.shop.cart.domain.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* StatisticsCartModel
*
* @author DeKangLiu
* on 2024/4/7
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class StatisticsCartModel {
/**
*
*/
private Long total;
/**
*
*/
private Long selectedTotal;
/**
*
*/
private BigDecimal priceTotal;
/**
*
*/
private BigDecimal actualTotal;
}

View File

@ -23,10 +23,6 @@ public class CartInfoSaveReq extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 购物车id */
@ApiModelProperty(name = "购物车id", value = "购物车id")
private Long id;
/** 商品ID */
@ -38,19 +34,12 @@ public class CartInfoSaveReq extends BaseEntity {
@ApiModelProperty(name = "SKU", value = "SKU")
private String projectSku;
/** 用户ID */
@ApiModelProperty(name = "用户ID", value = "用户ID")
private Long userId;
/** 数量 */
@ApiModelProperty(name = "数量", value = "数量")
private Long num;
/** 是否选中 */
@ApiModelProperty(name = "是否选中", value = "是否选中")
private String isSelected;
}

View File

@ -0,0 +1,33 @@
package com.muyu.shop.cart.domain.resp;
import com.muyu.shop.cart.domain.model.CartSkuModel;
import com.muyu.shop.cart.domain.model.StatisticsCartModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* CartDetailResp
*
* @author DeKangLiu
* on 2024/4/7
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CartDetailResp {
/**
*
*/
private List<CartSkuModel> cartSkuList;
/**
*
*/
private StatisticsCartModel statisticsCartModel;
}

View File

@ -29,6 +29,16 @@
<artifactId>muyu-shop-cart-cache</artifactId>
<version>${muyu.version}</version>
</dependency>
<!-- 商品模块 缓存 依赖-->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-product-cache</artifactId>
</dependency>
<!-- 商品模块 远程调用 依赖-->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-product-remote</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>

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.stereotype.Service;
/**
* ProjectInfoDataImpl
*
* @author DeKangLiu
* on 2024/4/7
*/
@Service
public class ProjectInfoDataImpl implements ProjectInfoData {
/**
*
* @param key ID
* @return
*/
@Override
public ProjectInfo getData(Long key) {
return new ProjectInfo();
}
}

View File

@ -0,0 +1,41 @@
package com.muyu.shop.cart.cache.impl;
import com.muyu.product.cache.datasource.ProjectInfoData;
import com.muyu.product.cache.datasource.ProjectSkuData;
import com.muyu.product.domain.ProjectInfo;
import com.muyu.product.domain.ProjectSkuInfo;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* ProjectSkuDataImpl
*
* @author DeKangLiu
* on 2024/4/7
*/
@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,37 @@
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;
/**
* ProjectSkuStockDataRemoteImpl
*
* @author DeKangLiu
* on 2024/4/7
*/
@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

@ -3,6 +3,7 @@ package com.muyu.shop.cart.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.muyu.shop.cart.domain.resp.CartDetailResp;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@ -75,6 +76,11 @@ public class CartInfoController extends BaseController {
return Result.success(cartInfoService.getById(id));
}
@GetMapping("/detail")
public Result<CartDetailResp> detail(){
return Result.success(cartInfoService.detail());
}
/**
*
*/
@ -83,7 +89,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)));
}
/**

View File

@ -3,6 +3,7 @@ package com.muyu.shop.cart.service;
import java.util.List;
import com.muyu.shop.cart.domain.CartInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import com.muyu.shop.cart.domain.resp.CartDetailResp;
/**
* Service
@ -19,4 +20,12 @@ public interface CartInfoService extends IService<CartInfo> {
*/
public List<CartInfo> list(CartInfo cartInfo);
CartDetailResp detail();
/**
*
* @param cartInfo
* @return
*/
boolean add(CartInfo cartInfo);
}

View File

@ -1,9 +1,32 @@
package com.muyu.shop.cart.service.impl;
import java.math.BigDecimal;
import java.util.ArrayList;
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.ProjectInfoCache;
import com.muyu.product.cache.ProjectSkuCache;
import com.muyu.product.cache.ProjectSkuStockCache;
import com.muyu.product.cache.RuleInfoCache;
import com.muyu.product.cache.key.SkuStockKey;
import com.muyu.product.cache.model.RuleAttrCacheModel;
import com.muyu.product.cache.model.RuleCacheModel;
import com.muyu.product.domain.ProjectInfo;
import com.muyu.product.domain.ProjectSkuInfo;
import com.muyu.shop.cart.cache.CartCache ;
import com.muyu.shop.cart.cache.key.CartHashKey;
import com.muyu.shop.cart.domain.model.CartSkuModel;
import com.muyu.shop.cart.domain.model.SkuRuleModel;
import com.muyu.shop.cart.domain.model.StatisticsCartModel;
import com.muyu.shop.cart.domain.resp.CartDetailResp;
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;
@ -14,13 +37,28 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
/**
* Service
*
* @author muyu
* @author DongZeLiang
* @date 2024-03-29
*/
@Slf4j
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {
@Autowired
private CartCache cartCache;
@Autowired
private ProjectSkuStockCache projectSkuStockCache;
@Autowired
private ProjectSkuCache projectSkuCache;
@Autowired
private ProjectInfoCache projectInfoCache;
@Autowired
private RuleInfoCache ruleInfoCache;
/**
*
*
@ -52,10 +90,135 @@ 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.hashKey(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;
}
/**
*
*
* @return
*/
@Override
public CartDetailResp detail () {
Long userId = SecurityUtils.getUserId();
List<CartInfo> cartInfoList = cartCache.getToList(userId);
//CartInfo->CartSkuModel
List<CartSkuModel> cartSkuModelList = cartInfoList.stream()
.map(cartInfo -> {
ProjectSkuInfo projectSkuInfo
= projectSkuCache.get(cartInfo.getProjectId(), cartInfo.getProjectSku());
ProjectInfo projectInfo =
projectInfoCache.get(cartInfo.getProjectId());
Long stock = projectSkuStockCache.get(SkuStockKey.builder()
.projectId(cartInfo.getProjectId())
.sku(cartInfo.getProjectSku())
.build()
);
//RuleCache
RuleCacheModel ruleInfoCacheModel = ruleInfoCache.getData(projectInfo.getRuleId());
List<RuleAttrCacheModel> ruleAttrModelList = ruleInfoCacheModel.getRuleAttrModelList();
ArrayList<SkuRuleModel> ruleModelList = new ArrayList<>();
String projectSku = cartInfo.getProjectSku();
String[] skuArr = projectSku.split("-");
for (int index = 0; index < skuArr.length; index++) {
ruleModelList.add(
SkuRuleModel.builder()
.ruleName(ruleAttrModelList.get(index).getAttrName())
.ruleValue(skuArr[index])
.build()
);
}
return CartSkuModel.builder()
.projectId(cartInfo.getProjectId())
.name(projectInfo.getName())
.images(projectSkuInfo.getImage())
.stock(stock)
.subtotal(projectSkuInfo.getPrice().multiply(new BigDecimal(cartInfo.getNum())))
.skuRuleList(ruleModelList)
.price(projectSkuInfo.getPrice())
.cartInfoId(cartInfo.getId())
.num(cartInfo.getNum())
.isSelected(cartInfo.getIsSelected())
.build();
}).toList();
ArrayList<CartSkuModel> cartSkuList = new ArrayList<>();
StatisticsCartModel statisticsCartModel = StatisticsCartModel.builder()
.total(
cartSkuModelList.stream()
.mapToLong(CartSkuModel::getNum)
.sum()
)
.selectedTotal(
cartSkuModelList.stream()
.filter(cartSkuModel -> "Y".equals(cartSkuModel.getIsSelected()))
.mapToLong(CartSkuModel::getNum)
.sum()
)
.priceTotal(
cartSkuModelList.stream()
.filter(cartSkuModel -> "Y".equals(cartSkuModel.getIsSelected()))
.map(CartSkuModel::getSubtotal)
.reduce(BigDecimal.ZERO,BigDecimal::add)
)
.actualTotal(
cartSkuModelList.stream()
.filter(cartSkuModel -> "Y".equals(cartSkuModel.getIsSelected()))
.map(CartSkuModel::getSubtotal)
.reduce(BigDecimal.ZERO,BigDecimal::add)
)
.build();
return CartDetailResp.builder()
.cartSkuList(cartSkuList)
.statisticsCartModel(statisticsCartModel)
.build();
}
}

View File

@ -1,8 +1,8 @@
package com.muyu.shop.cart.service.sourcedata;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.muy.shop.cart.cache.key.CartHashKey;
import com.muy.shop.cart.cache.sourcedata.CartData;
import com.muyu.shop.cart.cache.key.CartHashKey;
import com.muyu.shop.cart.cache.sourcedata.CartData;
import com.muyu.shop.cart.domain.CartInfo;
import com.muyu.shop.cart.service.CartInfoService;
import org.springframework.beans.factory.annotation.Autowired;
@ -39,15 +39,16 @@ public class CartDataImpl implements CartData{
/**
* hashhash
* @param key
* @param userId
* @param hashKey hash
* @return hash
*/
@Override
public CartInfo getData(Long key, CartHashKey hashKey) {
public CartInfo getData(Long userId, CartHashKey hashKey) {
LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CartInfo::getUserId,key);
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:
main:
allow-circular-references: true
application:
# 应用名称
name: muyu-shop-cart