feat(新增): 添加购物车
This commit is contained in:
parent
4a5477af0f
commit
6fd45be415
|
@ -33,4 +33,5 @@ public class MessageConstant {
|
||||||
public static final String TOKEN_IS_EMPTY = "token为空";
|
public static final String TOKEN_IS_EMPTY = "token为空";
|
||||||
public static final String DATA_IS_EMPTY = "数据为空";
|
public static final String DATA_IS_EMPTY = "数据为空";
|
||||||
public static final String STOCK_LESS = "库存不足";
|
public static final String STOCK_LESS = "库存不足";
|
||||||
|
public static final String SKU_NUM_CANNOT_BE_LESS = "商品数量不能再少了";
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.atguigu</groupId>
|
||||||
|
<artifactId>service-product-client</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -13,8 +13,7 @@ import org.springframework.context.annotation.ComponentScan;
|
||||||
"com.atguigu.ssyx.cart",
|
"com.atguigu.ssyx.cart",
|
||||||
})
|
})
|
||||||
@EnableDiscoveryClient
|
@EnableDiscoveryClient
|
||||||
// @EnableFeignClients(basePackages = "com.atguigu.ssyx.client")
|
@EnableFeignClients(basePackages = "com.atguigu.ssyx.client")
|
||||||
@EnableFeignClients()
|
|
||||||
public class ServiceCartApplication {
|
public class ServiceCartApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(ServiceCartApplication.class, args);
|
SpringApplication.run(ServiceCartApplication.class, args);
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package com.atguigu.ssyx.cart.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import springfox.documentation.builders.ApiInfoBuilder;
|
||||||
|
import springfox.documentation.builders.ParameterBuilder;
|
||||||
|
import springfox.documentation.builders.PathSelectors;
|
||||||
|
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||||
|
import springfox.documentation.schema.ModelRef;
|
||||||
|
import springfox.documentation.service.ApiInfo;
|
||||||
|
import springfox.documentation.service.Contact;
|
||||||
|
import springfox.documentation.service.Parameter;
|
||||||
|
import springfox.documentation.spi.DocumentationType;
|
||||||
|
import springfox.documentation.spring.web.plugins.Docket;
|
||||||
|
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableSwagger2WebMvc
|
||||||
|
public class Knife4jConfig {
|
||||||
|
@Bean
|
||||||
|
public Docket adminApiConfig() {
|
||||||
|
List<Parameter> pars = new ArrayList<>();
|
||||||
|
ParameterBuilder tokenPar = new ParameterBuilder();
|
||||||
|
tokenPar.name("adminId")
|
||||||
|
.description("用户token")
|
||||||
|
.defaultValue("1")
|
||||||
|
.modelRef(new ModelRef("string"))
|
||||||
|
.parameterType("header")
|
||||||
|
.required(false)
|
||||||
|
.build();
|
||||||
|
pars.add(tokenPar.build());
|
||||||
|
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.groupName("购物车相关接口")
|
||||||
|
.apiInfo(adminApiInfo())
|
||||||
|
.select()
|
||||||
|
.apis(RequestHandlerSelectors.basePackage("com.atguigu.ssyx.activity.controller"))
|
||||||
|
.paths(PathSelectors.regex("/admin/.*"))
|
||||||
|
.build()
|
||||||
|
.globalOperationParameters(pars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiInfo adminApiInfo() {
|
||||||
|
return new ApiInfoBuilder()
|
||||||
|
.title("后台管理系统-API文档")
|
||||||
|
.description("本文档描述了尚上优选后台系统服务接口定义")
|
||||||
|
.version("1.0")
|
||||||
|
.contact(new Contact("atguigu", "http://atguigu.com", "atguigu"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,53 @@
|
||||||
package com.atguigu.ssyx.cart.controller;
|
package com.atguigu.ssyx.cart.controller;
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import com.atguigu.ssyx.cart.service.CartInfoService;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import com.atguigu.ssyx.common.context.BaseContext;
|
||||||
|
import com.atguigu.ssyx.common.result.Result;
|
||||||
|
import com.atguigu.ssyx.model.order.CartInfo;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Api(tags = "购物车相关接口")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/cart")
|
@RequestMapping("/api/cart")
|
||||||
public class CartApiController {
|
public class CartApiController {
|
||||||
|
@Autowired
|
||||||
|
private CartInfoService cartInfoService;
|
||||||
|
|
||||||
|
@ApiOperation(value = "添加购物车")
|
||||||
|
@GetMapping("addToCart/{skuId}/{skuNum}")
|
||||||
|
public Result<CartInfo> addToCart(@PathVariable Long skuId, @PathVariable Integer skuNum) {
|
||||||
|
Long userId = BaseContext.getUserId();
|
||||||
|
cartInfoService.addToCart(skuId, userId, skuNum);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "删除购物车内容")
|
||||||
|
@DeleteMapping("deleteCart/{skuId}")
|
||||||
|
public Result<CartInfo> deleteCart(@PathVariable Long skuId) {
|
||||||
|
Long userId = BaseContext.getUserId();
|
||||||
|
cartInfoService.deleteCart(skuId, userId);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "清空购物车")
|
||||||
|
@DeleteMapping("deleteAllCart")
|
||||||
|
public Result<CartInfo> deleteAllCart(HttpServletRequest request) {
|
||||||
|
Long userId = BaseContext.getUserId();
|
||||||
|
cartInfoService.deleteAllCart(userId);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "批量删除购物车")
|
||||||
|
@PostMapping("batchDeleteCart")
|
||||||
|
public Result<CartInfo> batchDeleteCart(@RequestBody List<Long> skuIdList, HttpServletRequest request) {
|
||||||
|
Long userId = BaseContext.getUserId();
|
||||||
|
cartInfoService.batchDeleteCart(userId);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,34 @@ package com.atguigu.ssyx.cart.service;
|
||||||
|
|
||||||
public interface CartInfoService {
|
public interface CartInfoService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 添加购物车
|
||||||
|
*
|
||||||
|
* @param skuId 商品id
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param skuNum 商品数量
|
||||||
|
*/
|
||||||
|
void addToCart(Long skuId, Long userId, Integer skuNum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 删除购物车内容
|
||||||
|
*
|
||||||
|
* @param skuId 商品id
|
||||||
|
* @param userId 用户id
|
||||||
|
*/
|
||||||
|
void deleteCart(Long skuId, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 清空购物车
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
*/
|
||||||
|
void deleteAllCart(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 批量删除购物车
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
*/
|
||||||
|
void batchDeleteCart(Long userId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,115 @@
|
||||||
package com.atguigu.ssyx.cart.service.impl;
|
package com.atguigu.ssyx.cart.service.impl;
|
||||||
|
|
||||||
import com.atguigu.ssyx.cart.service.CartInfoService;
|
import com.atguigu.ssyx.cart.service.CartInfoService;
|
||||||
|
import com.atguigu.ssyx.cart.service.module.CartInfoServiceModule;
|
||||||
|
import com.atguigu.ssyx.client.product.ProductFeignClient;
|
||||||
|
import com.atguigu.ssyx.common.constant.MessageConstant;
|
||||||
|
import com.atguigu.ssyx.common.exception.BunnyException;
|
||||||
|
import com.atguigu.ssyx.common.result.ResultCodeEnum;
|
||||||
|
import com.atguigu.ssyx.enums.SkuType;
|
||||||
|
import com.atguigu.ssyx.model.order.CartInfo;
|
||||||
|
import com.atguigu.ssyx.model.product.SkuInfo;
|
||||||
|
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;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class CartInfoServiceImpl implements CartInfoService {
|
public class CartInfoServiceImpl implements CartInfoService {
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
@Autowired
|
||||||
|
private CartInfoServiceModule module;
|
||||||
|
@Autowired
|
||||||
|
private ProductFeignClient productFeignClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 添加购物车
|
||||||
|
*
|
||||||
|
* @param skuId 商品id
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param skuNum 商品数量
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addToCart(Long skuId, Long userId, Integer skuNum) {
|
||||||
|
CartInfo cartInfo = null;
|
||||||
|
// 因为购物车数据存储在REdis中
|
||||||
|
String cartKey = module.getCartKey(userId);
|
||||||
|
BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
|
||||||
|
// 根据第一步查询的结果,得到skuId+skuNum关系
|
||||||
|
if (Boolean.TRUE.equals(hashOperations.hasKey(skuId))) {
|
||||||
|
cartInfo = hashOperations.get(skuId);
|
||||||
|
int currentSkuNum = cartInfo.getSkuNum() + skuNum;
|
||||||
|
if (currentSkuNum <= 1) throw new BunnyException(MessageConstant.SKU_NUM_CANNOT_BE_LESS);
|
||||||
|
|
||||||
|
// 更新cartInfo对象
|
||||||
|
cartInfo.setSkuNum(currentSkuNum);
|
||||||
|
cartInfo.setCurrentBuyNum(currentSkuNum);
|
||||||
|
// 判断商品不能大于限购数量
|
||||||
|
if (currentSkuNum > cartInfo.getPerLimit()) throw new BunnyException(ResultCodeEnum.SKU_LIMIT_ERROR);
|
||||||
|
// 更新其他值,加入购物车商品默认选中
|
||||||
|
cartInfo.setIsChecked(1);
|
||||||
|
cartInfo.setUpdateTime(new Date());
|
||||||
|
} else {
|
||||||
|
skuNum = 1;
|
||||||
|
cartInfo = new CartInfo();
|
||||||
|
SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId).getData();
|
||||||
|
if (skuInfo == null) {
|
||||||
|
throw new BunnyException(ResultCodeEnum.DATA_ERROR);
|
||||||
|
}
|
||||||
|
cartInfo.setSkuId(skuId);
|
||||||
|
cartInfo.setCategoryId(skuInfo.getCategoryId());
|
||||||
|
cartInfo.setSkuType(skuInfo.getSkuType());
|
||||||
|
cartInfo.setIsNewPerson(skuInfo.getIsNewPerson());
|
||||||
|
cartInfo.setUserId(userId);
|
||||||
|
cartInfo.setCartPrice(skuInfo.getPrice());
|
||||||
|
cartInfo.setSkuNum(skuNum);
|
||||||
|
cartInfo.setCurrentBuyNum(skuNum);
|
||||||
|
cartInfo.setSkuType(SkuType.COMMON.getCode());
|
||||||
|
cartInfo.setPerLimit(skuInfo.getPerLimit());
|
||||||
|
cartInfo.setImgUrl(skuInfo.getImgUrl());
|
||||||
|
cartInfo.setSkuName(skuInfo.getSkuName());
|
||||||
|
cartInfo.setWareId(skuInfo.getWareId());
|
||||||
|
cartInfo.setIsChecked(1);
|
||||||
|
cartInfo.setStatus(1);
|
||||||
|
cartInfo.setCreateTime(new Date());
|
||||||
|
cartInfo.setUpdateTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
hashOperations.put(skuId.toString(), cartInfo);
|
||||||
|
module.setCartKeyExpire(cartKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 删除购物车内容
|
||||||
|
*
|
||||||
|
* @param skuId 商品id
|
||||||
|
* @param userId 用户id
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void deleteCart(Long skuId, Long userId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 清空购物车
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void deleteAllCart(Long userId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 批量删除购物车
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void batchDeleteCart(Long userId) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.atguigu.ssyx.cart.service.module;
|
||||||
|
|
||||||
|
import com.atguigu.ssyx.common.constant.RedisConst;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class CartInfoServiceModule {
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 获取购物车的id
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
* @return 购物车的key
|
||||||
|
*/
|
||||||
|
public String getCartKey(Long userId) {
|
||||||
|
return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 过期时间
|
||||||
|
*
|
||||||
|
* @param key Redis中的key
|
||||||
|
*/
|
||||||
|
public void setCartKeyExpire(String key) {
|
||||||
|
redisTemplate.expire(key, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,12 @@ bunny:
|
||||||
username: root
|
username: root
|
||||||
password: "02120212"
|
password: "02120212"
|
||||||
|
|
||||||
|
redis:
|
||||||
|
host: 47.120.65.66
|
||||||
|
port: 6379
|
||||||
|
database: 3
|
||||||
|
password: "02120212"
|
||||||
|
|
||||||
nacos:
|
nacos:
|
||||||
server-addr: z-bunny.cn:8848
|
server-addr: z-bunny.cn:8848
|
||||||
discovery:
|
discovery:
|
||||||
|
|
|
@ -14,6 +14,18 @@ spring:
|
||||||
username: ${bunny.datasource.username}
|
username: ${bunny.datasource.username}
|
||||||
password: ${bunny.datasource.password}
|
password: ${bunny.datasource.password}
|
||||||
|
|
||||||
|
redis:
|
||||||
|
host: ${bunny.redis.host}
|
||||||
|
port: ${bunny.redis.port}
|
||||||
|
database: ${bunny.redis.database}
|
||||||
|
password: ${bunny.redis.password}
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
max-active: 20 #最大连接数
|
||||||
|
max-wait: -1 #最大阻塞等待时间(负数表示没限制)
|
||||||
|
max-idle: 5 #最大空闲
|
||||||
|
min-idle: 0 #最小空闲
|
||||||
|
|
||||||
cloud:
|
cloud:
|
||||||
sentinel:
|
sentinel:
|
||||||
log:
|
log:
|
||||||
|
|
Loading…
Reference in New Issue