diff --git a/xdclass-common/pom.xml b/xdclass-common/pom.xml
index 2f8bacf..cf6b753 100644
--- a/xdclass-common/pom.xml
+++ b/xdclass-common/pom.xml
@@ -108,6 +108,12 @@
redisson
+
+ com.alibaba
+ fastjson
+ 1.2.75
+
+
diff --git a/xdclass-common/src/main/java/net/jieyuu/constant/CacheKey.java b/xdclass-common/src/main/java/net/jieyuu/constant/CacheKey.java
index 697ba96..52c14cc 100644
--- a/xdclass-common/src/main/java/net/jieyuu/constant/CacheKey.java
+++ b/xdclass-common/src/main/java/net/jieyuu/constant/CacheKey.java
@@ -4,5 +4,10 @@ public class CacheKey {
/**
* 注册验证码,第一个是类型,第二个是接收号码
*/
- public final static String CHECK_CODE_KEY="code:%s:%s";
+ public final static String CHECK_CODE_KEY = "code:%s:%s";
+
+ /**
+ * 购物车 hash 结果 , key是用户唯一标识
+ */
+ public final static String CART_KEY = "cart:%s";
}
diff --git a/xdclass-common/src/main/java/net/jieyuu/enums/BizCodeEnum.java b/xdclass-common/src/main/java/net/jieyuu/enums/BizCodeEnum.java
index 9773ff7..8af4ac4 100644
--- a/xdclass-common/src/main/java/net/jieyuu/enums/BizCodeEnum.java
+++ b/xdclass-common/src/main/java/net/jieyuu/enums/BizCodeEnum.java
@@ -14,75 +14,109 @@ public enum BizCodeEnum {
*/
OPS_REPEAT(110001, "重复操作"),
+ /**
+ * 购物车
+ */
+ CART_FILE(220001, "添加购物车失败"),
+
/**
* 验证码
*/
CODE_TO_ERROR(240001, "接收号码不合规"),
+
CODE_LIMITED(240002, "验证码发送过快"),
+
CODE_ERROR(240003, "验证码错误"),
+
CODE_CAPTCHA(240101, "图形验证码错误"),
/**
* 账号
*/
ACCOUNT_REPEAT(250001, "账号已经存在"),
+
ACCOUNT_UNREGISTER(250002, "账号不存在"),
+
ACCOUNT_PWD_ERROR(250003, "账号或者密码错误"),
+
ACCOUNT_UNLOGIN(250004, "账号未登录"),
/**
* 优惠券
*/
- COUPON_CONDITION_ERROR(270001,"优惠券条件错误"),
- COUPON_UNAVAILABLE(270002,"没有可用的优惠券"),
- COUPON_NO_EXITS(270003,"优惠券不存在"),
- COUPON_NO_STOCK(270005,"优惠券库存不足"),
- COUPON_OUT_OF_LIMIT(270006,"优惠券领取超过限制次数"),
- COUPON_OUT_OF_TIME(270407,"优惠券不在领取时间范围"),
- COUPON_GET_FAIL(270407,"优惠券领取失败"),
- COUPON_RECORD_LOCK_FAIL(270409,"优惠券锁定失败"),
+ COUPON_CONDITION_ERROR(270001, "优惠券条件错误"),
+
+ COUPON_UNAVAILABLE(270002, "没有可用的优惠券"),
+
+ COUPON_NO_EXITS(270003, "优惠券不存在"),
+
+ COUPON_NO_STOCK(270005, "优惠券库存不足"),
+
+ COUPON_OUT_OF_LIMIT(270006, "优惠券领取超过限制次数"),
+
+ COUPON_OUT_OF_TIME(270407, "优惠券不在领取时间范围"),
+
+ COUPON_GET_FAIL(270407, "优惠券领取失败"),
+
+ COUPON_RECORD_LOCK_FAIL(270409, "优惠券锁定失败"),
/**
* 订单
*/
- ORDER_CONFIRM_COUPON_FAIL(280001,"创建订单-优惠券使用失败,不满足价格条件"),
- ORDER_CONFIRM_PRICE_FAIL(280002,"创建订单-验价失败"),
- ORDER_CONFIRM_LOCK_PRODUCT_FAIL(280003,"创建订单-商品库存不足锁定失败"),
- ORDER_CONFIRM_ADD_STOCK_TASK_FAIL(280004,"创建订单-新增商品库存锁定任务"),
- ORDER_CONFIRM_TOKEN_NOT_EXIST(280008,"订单令牌缺少"),
- ORDER_CONFIRM_TOKEN_EQUAL_FAIL(280009,"订单令牌不正确"),
- ORDER_CONFIRM_NOT_EXIST(280010,"订单不存在"),
- ORDER_CONFIRM_CART_ITEM_NOT_EXIST(280011,"购物车商品项不存在"),
+ ORDER_CONFIRM_COUPON_FAIL(280001, "创建订单-优惠券使用失败,不满足价格条件"),
+
+ ORDER_CONFIRM_PRICE_FAIL(280002, "创建订单-验价失败"),
+
+ ORDER_CONFIRM_LOCK_PRODUCT_FAIL(280003, "创建订单-商品库存不足锁定失败"),
+
+ ORDER_CONFIRM_ADD_STOCK_TASK_FAIL(280004, "创建订单-新增商品库存锁定任务"),
+
+ ORDER_CONFIRM_TOKEN_NOT_EXIST(280008, "订单令牌缺少"),
+
+ ORDER_CONFIRM_TOKEN_EQUAL_FAIL(280009, "订单令牌不正确"),
+
+ ORDER_CONFIRM_NOT_EXIST(280010, "订单不存在"),
+
+ ORDER_CONFIRM_CART_ITEM_NOT_EXIST(280011, "购物车商品项不存在"),
/**
* 收货地址
*/
- ADDRESS_ADD_FAIL(290001,"新增收货地址失败"),
- ADDRESS_DEL_FAIL(290002,"删除收货地址失败"),
- ADDRESS_NO_EXITS(290003,"地址不存在"),
+ ADDRESS_ADD_FAIL(290001, "新增收货地址失败"),
+
+ ADDRESS_DEL_FAIL(290002, "删除收货地址失败"),
+
+ ADDRESS_NO_EXITS(290003, "地址不存在"),
/**
* 支付
*/
- PAY_ORDER_FAIL(300001,"创建支付订单失败"),
- PAY_ORDER_CALLBACK_SIGN_FAIL(300002,"支付订单回调验证签失败"),
- PAY_ORDER_CALLBACK_NOT_SUCCESS(300003,"创建支付订单失败"),
- PAY_ORDER_NOT_EXIST(300005,"订单不存在"),
- PAY_ORDER_STATE_ERROR(300006,"订单状态不正常"),
- PAY_ORDER_PAY_TIMEOUT(300007,"订单支付超时"),
+ PAY_ORDER_FAIL(300001, "创建支付订单失败"),
+
+ PAY_ORDER_CALLBACK_SIGN_FAIL(300002, "支付订单回调验证签失败"),
+
+ PAY_ORDER_CALLBACK_NOT_SUCCESS(300003, "创建支付订单失败"),
+
+ PAY_ORDER_NOT_EXIST(300005, "订单不存在"),
+
+ PAY_ORDER_STATE_ERROR(300006, "订单状态不正常"),
+
+ PAY_ORDER_PAY_TIMEOUT(300007, "订单支付超时"),
/**
* 流控操作
*/
- CONTROL_FLOW(500101,"限流控制"),
- CONTROL_DEGRADE(500201,"降级控制"),
- CONTROL_AUTH(500301,"认证控制"),
+ CONTROL_FLOW(500101, "限流控制"),
+
+ CONTROL_DEGRADE(500201, "降级控制"),
+
+ CONTROL_AUTH(500301, "认证控制"),
/**
* 文件相关
*/
- FILE_UPLOAD_USER_IMG_FAIL(600101,"用户头像文件上传失败");
+ FILE_UPLOAD_USER_IMG_FAIL(600101, "用户头像文件上传失败");
@Getter
private int code;
diff --git a/xdclass-product-service/src/main/java/net/jieyuu/config/InterceptorConfig.java b/xdclass-product-service/src/main/java/net/jieyuu/config/InterceptorConfig.java
index 0e5ffbe..ff0d6d9 100644
--- a/xdclass-product-service/src/main/java/net/jieyuu/config/InterceptorConfig.java
+++ b/xdclass-product-service/src/main/java/net/jieyuu/config/InterceptorConfig.java
@@ -16,7 +16,7 @@ public class InterceptorConfig implements WebMvcConfigurer {
registry
.addInterceptor(new LoginInterceptor())
//拦截的路径
- .addPathPatterns("")
+ .addPathPatterns("api/cart/*/**")
//放行的路径
.excludePathPatterns("", "");
diff --git a/xdclass-product-service/src/main/java/net/jieyuu/controller/CartController.java b/xdclass-product-service/src/main/java/net/jieyuu/controller/CartController.java
new file mode 100644
index 0000000..2ef371d
--- /dev/null
+++ b/xdclass-product-service/src/main/java/net/jieyuu/controller/CartController.java
@@ -0,0 +1,45 @@
+package net.jieyuu.controller;
+
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import net.jieyuu.request.CartItemRequest;
+import net.jieyuu.service.CartService;
+import net.jieyuu.service.ProductService;
+import net.jieyuu.utils.JsonData;
+import net.jieyuu.vo.ProductVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author jieyuu
+ * @since 2024-08-07
+ */
+
+@Api("购物车")
+@RestController
+@RequestMapping("/api/cart/v1")
+public class CartController {
+
+ @Autowired
+ private CartService cartService;
+
+
+ @ApiOperation("添加到购物车")
+ @PostMapping("add")
+ public JsonData addToCart(@ApiParam("购物项") @RequestBody CartItemRequest cartItemRequest) {
+ cartService.addToCart(cartItemRequest);
+ return JsonData.buildSuccess();
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/xdclass-product-service/src/main/java/net/jieyuu/model/ProductDO.java b/xdclass-product-service/src/main/java/net/jieyuu/model/ProductDO.java
index 98a9982..6f9a00c 100644
--- a/xdclass-product-service/src/main/java/net/jieyuu/model/ProductDO.java
+++ b/xdclass-product-service/src/main/java/net/jieyuu/model/ProductDO.java
@@ -45,12 +45,12 @@ public class ProductDO implements Serializable {
/**
* 老价格
*/
- private BigDecimal oldPrice;
+ private BigDecimal oldAmount;
/**
* 新价格
*/
- private BigDecimal price;
+ private BigDecimal amount;
/**
* 库存
diff --git a/xdclass-product-service/src/main/java/net/jieyuu/request/CartItemRequest.java b/xdclass-product-service/src/main/java/net/jieyuu/request/CartItemRequest.java
new file mode 100644
index 0000000..7fd2e80
--- /dev/null
+++ b/xdclass-product-service/src/main/java/net/jieyuu/request/CartItemRequest.java
@@ -0,0 +1,21 @@
+package net.jieyuu.request;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+@Data
+@ApiModel
+public class CartItemRequest {
+
+
+ @ApiModelProperty(value = "商品id", example = "11")
+ @JsonProperty("product_id")
+ private long productId;
+
+ @ApiModelProperty(value = "购买数量", example = "11")
+ @JsonProperty("buy_num")
+ private int buyNum;
+}
diff --git a/xdclass-product-service/src/main/java/net/jieyuu/service/CartService.java b/xdclass-product-service/src/main/java/net/jieyuu/service/CartService.java
new file mode 100644
index 0000000..43e6c3e
--- /dev/null
+++ b/xdclass-product-service/src/main/java/net/jieyuu/service/CartService.java
@@ -0,0 +1,11 @@
+package net.jieyuu.service;
+
+import net.jieyuu.request.CartItemRequest;
+
+public interface CartService {
+ /**
+ * 添加商品到购物车
+ * @param cartItemRequest
+ */
+ public void addToCart(CartItemRequest cartItemRequest);
+}
diff --git a/xdclass-product-service/src/main/java/net/jieyuu/service/impl/CartServiceImpl.java b/xdclass-product-service/src/main/java/net/jieyuu/service/impl/CartServiceImpl.java
new file mode 100644
index 0000000..5e48991
--- /dev/null
+++ b/xdclass-product-service/src/main/java/net/jieyuu/service/impl/CartServiceImpl.java
@@ -0,0 +1,92 @@
+package net.jieyuu.service.impl;
+
+
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import net.jieyuu.constant.CacheKey;
+import net.jieyuu.enums.BizCodeEnum;
+import net.jieyuu.exception.BizException;
+import net.jieyuu.interceptor.LoginInterceptor;
+import net.jieyuu.model.LoginUser;
+import net.jieyuu.request.CartItemRequest;
+import net.jieyuu.service.CartService;
+import net.jieyuu.service.ProductService;
+import net.jieyuu.vo.CartItemVO;
+import net.jieyuu.vo.ProductVO;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.BoundHashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+public class CartServiceImpl implements CartService {
+
+ @Autowired
+ private ProductService productService;
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+ @Override
+ public void addToCart(CartItemRequest cartItemRequest) {
+ long productId = cartItemRequest.getProductId();
+ int buyNum = cartItemRequest.getBuyNum();
+
+ //获取购物车
+ BoundHashOperations myCart = getMyCartOps();
+
+ Object cacheObj = myCart.get(productId);
+ String result = "";
+
+ if (cacheObj != null) {
+ result = (String) cacheObj;
+ }
+ if (StringUtils.isBlank(result)) {
+ //不存在
+
+ CartItemVO cartItemVO = new CartItemVO();
+
+ ProductVO productVO = productService.findDetailById(productId);
+
+ if (productVO == null) {
+ throw new BizException(BizCodeEnum.CART_FILE);
+ }
+
+ cartItemVO.setAmount(productVO.getAmount());
+ cartItemVO.setBuyNum(buyNum);
+ cartItemVO.setProductId(productId);
+ cartItemVO.setProductImg(productVO.getCoverImg());
+ cartItemVO.setProductTitle(productVO.getTitle());
+
+ myCart.put(productId, JSON.toJSONString(cartItemVO));
+ } else {
+ //存在商品,修改购物车
+ CartItemVO cartItem = JSON.parseObject(result, CartItemVO.class);
+ cartItem.setBuyNum(cartItem.getBuyNum() + buyNum);
+ myCart.put(productId, JSON.toJSONString(cartItem));
+ }
+ }
+
+ /**
+ * 抽取购物车 通用方法
+ *
+ * @return
+ */
+ private BoundHashOperations getMyCartOps() {
+ String cartKey = getCartKey();
+ return redisTemplate.boundHashOps(cartKey);
+ }
+
+ /**
+ * 购物车 key
+ *
+ * @return
+ */
+ private String getCartKey() {
+ LoginUser loginUser = LoginInterceptor.threadLocal.get();
+ String cartKey = String.format(CacheKey.CART_KEY, loginUser.getId());
+
+ return cartKey;
+ }
+}
diff --git a/xdclass-product-service/src/main/java/net/jieyuu/vo/CartItemVO.java b/xdclass-product-service/src/main/java/net/jieyuu/vo/CartItemVO.java
new file mode 100644
index 0000000..8322789
--- /dev/null
+++ b/xdclass-product-service/src/main/java/net/jieyuu/vo/CartItemVO.java
@@ -0,0 +1,91 @@
+package net.jieyuu.vo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.math.BigDecimal;
+
+public class CartItemVO {
+
+ /**
+ * 商品id
+ */
+ @JsonProperty("product_id")
+ private Long productId;
+
+ /**
+ * 购买数量
+ */
+ @JsonProperty("buy_num")
+ private Integer buyNum;
+ /**
+ * 商品标题
+ */
+ @JsonProperty("product_title")
+ private String productTitle;
+ /**
+ * 商品图片
+ */
+ @JsonProperty("product_img")
+ private String productImg;
+
+ /**
+ * 商品单价
+ */
+ private BigDecimal amount;
+ /**
+ * 商品总价
+ */
+ @JsonProperty("total_amount")
+ private BigDecimal totalAmount;
+
+
+ public Long getProductId() {
+ return productId;
+ }
+
+ public void setProductId(Long productId) {
+ this.productId = productId;
+ }
+
+
+ public Integer getBuyNum() {
+ return buyNum;
+ }
+
+ public void setBuyNum(Integer buyNum) {
+ this.buyNum = buyNum;
+ }
+
+ public String getProductTitle() {
+ return productTitle;
+ }
+
+ public void setProductTitle(String productTitle) {
+ this.productTitle = productTitle;
+ }
+
+ public String getProductImg() {
+ return productImg;
+ }
+
+ public void setProductImg(String productImg) {
+ this.productImg = productImg;
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public void setAmount(BigDecimal amount) {
+ this.amount = amount;
+ }
+
+ /**
+ * 商品总价 * 商品数量
+ * @return
+ */
+ public BigDecimal getTotalAmount() {
+ return this.amount.multiply(new BigDecimal(this.buyNum));
+ }
+
+}
diff --git a/xdclass-product-service/src/main/java/net/jieyuu/vo/CartVO.java b/xdclass-product-service/src/main/java/net/jieyuu/vo/CartVO.java
new file mode 100644
index 0000000..6ad3158
--- /dev/null
+++ b/xdclass-product-service/src/main/java/net/jieyuu/vo/CartVO.java
@@ -0,0 +1,69 @@
+package net.jieyuu.vo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+public class CartVO {
+ @JsonProperty("cart_items")
+ private List cartItems;
+
+
+ @JsonProperty("total_num")
+ private Integer totalNum;
+ @JsonProperty("total_amount")
+ private BigDecimal totalAmount;
+
+ @JsonProperty("real_pay_amount")
+ private BigDecimal realPayAmount;
+
+ public void setCartItems(List cartItems) {
+ this.cartItems = cartItems;
+ }
+
+ public List getCartItems() {
+ return cartItems;
+ }
+
+ public Integer getTotalNum() {
+ if (this.cartItems != null) {
+ int total = cartItems.stream().mapToInt(CartItemVO::getBuyNum).sum();
+ return total;
+ }
+ return 0;
+ }
+
+ /**
+ * 总价格
+ *
+ * @return
+ */
+ public BigDecimal getTotalAmount() {
+ BigDecimal amount = new BigDecimal("0");
+
+ if (this.cartItems != null) {
+ for (CartItemVO cartItem : cartItems) {
+ BigDecimal itemTotalAmount = cartItem.getTotalAmount();
+ amount = amount.add(itemTotalAmount);
+ }
+ }
+ return amount;
+ }
+
+ /**
+ * 实际价格
+ *
+ * @return
+ */
+ public BigDecimal getRealPayAmount() {
+ BigDecimal amount = new BigDecimal("0");
+ if (this.cartItems != null) {
+ for (CartItemVO cartItem : cartItems) {
+ BigDecimal itemTotalAmount = cartItem.getAmount();
+ amount = amount.add(itemTotalAmount);
+ }
+ }
+ return amount;
+ }
+}
diff --git a/xdclass-product-service/src/main/java/net/jieyuu/vo/ProductVO.java b/xdclass-product-service/src/main/java/net/jieyuu/vo/ProductVO.java
index 17d9364..db00e07 100644
--- a/xdclass-product-service/src/main/java/net/jieyuu/vo/ProductVO.java
+++ b/xdclass-product-service/src/main/java/net/jieyuu/vo/ProductVO.java
@@ -41,13 +41,13 @@ public class ProductVO {
/**
* 老价格
*/
- @JsonProperty("old_price")
- private BigDecimal oldPrice;
+ @JsonProperty("old_amount")
+ private BigDecimal oldAmount;
/**
* 新价格
*/
- private BigDecimal price;
+ private BigDecimal amount;
/**
* 库存
diff --git a/xdclass-product-service/src/main/resources/mapper/ProductMapper.xml b/xdclass-product-service/src/main/resources/mapper/ProductMapper.xml
index 10dc521..adc4657 100644
--- a/xdclass-product-service/src/main/resources/mapper/ProductMapper.xml
+++ b/xdclass-product-service/src/main/resources/mapper/ProductMapper.xml
@@ -8,8 +8,8 @@
-
-
+
+
@@ -17,7 +17,7 @@
- id, title, cover_img, detail, old_price, price, stock, create_time, lock_stock
+ id, title, cover_img, detail, old_amount, amount, stock, create_time, lock_stock