添加商品到购物车

This commit is contained in:
jieyuu 2024-08-16 13:59:39 +08:00
parent d1cf736317
commit 5934fea2b9
13 changed files with 413 additions and 39 deletions

View File

@ -108,6 +108,12 @@
<artifactId>redisson</artifactId> <artifactId>redisson</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
</dependencies> </dependencies>
<properties> <properties>

View File

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

View File

@ -14,75 +14,109 @@ public enum BizCodeEnum {
*/ */
OPS_REPEAT(110001, "重复操作"), OPS_REPEAT(110001, "重复操作"),
/**
* 购物车
*/
CART_FILE(220001, "添加购物车失败"),
/** /**
* 验证码 * 验证码
*/ */
CODE_TO_ERROR(240001, "接收号码不合规"), CODE_TO_ERROR(240001, "接收号码不合规"),
CODE_LIMITED(240002, "验证码发送过快"), CODE_LIMITED(240002, "验证码发送过快"),
CODE_ERROR(240003, "验证码错误"), CODE_ERROR(240003, "验证码错误"),
CODE_CAPTCHA(240101, "图形验证码错误"), CODE_CAPTCHA(240101, "图形验证码错误"),
/** /**
* 账号 * 账号
*/ */
ACCOUNT_REPEAT(250001, "账号已经存在"), ACCOUNT_REPEAT(250001, "账号已经存在"),
ACCOUNT_UNREGISTER(250002, "账号不存在"), ACCOUNT_UNREGISTER(250002, "账号不存在"),
ACCOUNT_PWD_ERROR(250003, "账号或者密码错误"), ACCOUNT_PWD_ERROR(250003, "账号或者密码错误"),
ACCOUNT_UNLOGIN(250004, "账号未登录"), ACCOUNT_UNLOGIN(250004, "账号未登录"),
/** /**
* 优惠券 * 优惠券
*/ */
COUPON_CONDITION_ERROR(270001,"优惠券条件错误"), COUPON_CONDITION_ERROR(270001, "优惠券条件错误"),
COUPON_UNAVAILABLE(270002,"没有可用的优惠券"),
COUPON_NO_EXITS(270003,"优惠券不存在"), COUPON_UNAVAILABLE(270002, "没有可用的优惠券"),
COUPON_NO_STOCK(270005,"优惠券库存不足"),
COUPON_OUT_OF_LIMIT(270006,"优惠券领取超过限制次数"), COUPON_NO_EXITS(270003, "优惠券不存在"),
COUPON_OUT_OF_TIME(270407,"优惠券不在领取时间范围"),
COUPON_GET_FAIL(270407,"优惠券领取失败"), COUPON_NO_STOCK(270005, "优惠券库存不足"),
COUPON_RECORD_LOCK_FAIL(270409,"优惠券锁定失败"),
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_COUPON_FAIL(280001, "创建订单-优惠券使用失败,不满足价格条件"),
ORDER_CONFIRM_PRICE_FAIL(280002,"创建订单-验价失败"),
ORDER_CONFIRM_LOCK_PRODUCT_FAIL(280003,"创建订单-商品库存不足锁定失败"), ORDER_CONFIRM_PRICE_FAIL(280002, "创建订单-验价失败"),
ORDER_CONFIRM_ADD_STOCK_TASK_FAIL(280004,"创建订单-新增商品库存锁定任务"),
ORDER_CONFIRM_TOKEN_NOT_EXIST(280008,"订单令牌缺少"), ORDER_CONFIRM_LOCK_PRODUCT_FAIL(280003, "创建订单-商品库存不足锁定失败"),
ORDER_CONFIRM_TOKEN_EQUAL_FAIL(280009,"订单令牌不正确"),
ORDER_CONFIRM_NOT_EXIST(280010,"订单不存在"), ORDER_CONFIRM_ADD_STOCK_TASK_FAIL(280004, "创建订单-新增商品库存锁定任务"),
ORDER_CONFIRM_CART_ITEM_NOT_EXIST(280011,"购物车商品项不存在"),
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_ADD_FAIL(290001, "新增收货地址失败"),
ADDRESS_DEL_FAIL(290002,"删除收货地址失败"),
ADDRESS_NO_EXITS(290003,"地址不存在"), ADDRESS_DEL_FAIL(290002, "删除收货地址失败"),
ADDRESS_NO_EXITS(290003, "地址不存在"),
/** /**
* 支付 * 支付
*/ */
PAY_ORDER_FAIL(300001,"创建支付订单失败"), PAY_ORDER_FAIL(300001, "创建支付订单失败"),
PAY_ORDER_CALLBACK_SIGN_FAIL(300002,"支付订单回调验证签失败"),
PAY_ORDER_CALLBACK_NOT_SUCCESS(300003,"创建支付订单失败"), PAY_ORDER_CALLBACK_SIGN_FAIL(300002, "支付订单回调验证签失败"),
PAY_ORDER_NOT_EXIST(300005,"订单不存在"),
PAY_ORDER_STATE_ERROR(300006,"订单状态不正常"), PAY_ORDER_CALLBACK_NOT_SUCCESS(300003, "创建支付订单失败"),
PAY_ORDER_PAY_TIMEOUT(300007,"订单支付超时"),
PAY_ORDER_NOT_EXIST(300005, "订单不存在"),
PAY_ORDER_STATE_ERROR(300006, "订单状态不正常"),
PAY_ORDER_PAY_TIMEOUT(300007, "订单支付超时"),
/** /**
* 流控操作 * 流控操作
*/ */
CONTROL_FLOW(500101,"限流控制"), CONTROL_FLOW(500101, "限流控制"),
CONTROL_DEGRADE(500201,"降级控制"),
CONTROL_AUTH(500301,"认证控制"), CONTROL_DEGRADE(500201, "降级控制"),
CONTROL_AUTH(500301, "认证控制"),
/** /**
* 文件相关 * 文件相关
*/ */
FILE_UPLOAD_USER_IMG_FAIL(600101,"用户头像文件上传失败"); FILE_UPLOAD_USER_IMG_FAIL(600101, "用户头像文件上传失败");
@Getter @Getter
private int code; private int code;

View File

@ -16,7 +16,7 @@ public class InterceptorConfig implements WebMvcConfigurer {
registry registry
.addInterceptor(new LoginInterceptor()) .addInterceptor(new LoginInterceptor())
//拦截的路径 //拦截的路径
.addPathPatterns("") .addPathPatterns("api/cart/*/**")
//放行的路径 //放行的路径
.excludePathPatterns("", ""); .excludePathPatterns("", "");

View File

@ -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;
/**
* <p>
* 前端控制器
* </p>
*
* @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();
}
}

View File

@ -45,12 +45,12 @@ public class ProductDO implements Serializable {
/** /**
* 老价格 * 老价格
*/ */
private BigDecimal oldPrice; private BigDecimal oldAmount;
/** /**
* 新价格 * 新价格
*/ */
private BigDecimal price; private BigDecimal amount;
/** /**
* 库存 * 库存

View File

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

View File

@ -0,0 +1,11 @@
package net.jieyuu.service;
import net.jieyuu.request.CartItemRequest;
public interface CartService {
/**
* 添加商品到购物车
* @param cartItemRequest
*/
public void addToCart(CartItemRequest cartItemRequest);
}

View File

@ -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<String, Object, Object> 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<String, Object, Object> 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;
}
}

View File

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

View File

@ -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<CartItemVO> cartItems;
@JsonProperty("total_num")
private Integer totalNum;
@JsonProperty("total_amount")
private BigDecimal totalAmount;
@JsonProperty("real_pay_amount")
private BigDecimal realPayAmount;
public void setCartItems(List<CartItemVO> cartItems) {
this.cartItems = cartItems;
}
public List<CartItemVO> 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;
}
}

View File

@ -41,13 +41,13 @@ public class ProductVO {
/** /**
* 老价格 * 老价格
*/ */
@JsonProperty("old_price") @JsonProperty("old_amount")
private BigDecimal oldPrice; private BigDecimal oldAmount;
/** /**
* 新价格 * 新价格
*/ */
private BigDecimal price; private BigDecimal amount;
/** /**
* 库存 * 库存

View File

@ -8,8 +8,8 @@
<result column="title" property="title" /> <result column="title" property="title" />
<result column="cover_img" property="coverImg" /> <result column="cover_img" property="coverImg" />
<result column="detail" property="detail" /> <result column="detail" property="detail" />
<result column="old_price" property="oldPrice" /> <result column="old_amount" property="oldAmount" />
<result column="price" property="price" /> <result column="amount" property="amount" />
<result column="stock" property="stock" /> <result column="stock" property="stock" />
<result column="create_time" property="createTime" /> <result column="create_time" property="createTime" />
<result column="lock_stock" property="lockStock" /> <result column="lock_stock" property="lockStock" />
@ -17,7 +17,7 @@
<!-- 通用查询结果列 --> <!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <sql id="Base_Column_List">
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
</sql> </sql>
</mapper> </mapper>