商城业务--> 购物车功能完善

This commit is contained in:
Kirk Lin 2021-07-11 01:08:12 +08:00
parent c0eabe572b
commit 8985215608
18 changed files with 1619 additions and 969 deletions

View file

@ -617,24 +617,24 @@ none"><span style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体
mso-ascii-font-family:Calibri;mso-ascii-theme-font:minor-latin;mso-fareast-font-family:
宋体;mso-fareast-theme-font:minor-fareast;mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin">本协议是您与KK商城网站简称</span><span lang="EN-US"
style="mso-bidi-font-size:10.5pt;line-height:150%">;</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
style="mso-bidi-font-size:10.5pt;line-height:150%">;</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
Calibri;mso-ascii-theme-font:minor-latin;mso-fareast-font-family:宋体;mso-fareast-theme-font:
minor-fareast;mso-hansi-font-family:Calibri;mso-hansi-theme-font:minor-latin">本站</span><span lang="EN-US"
style="mso-bidi-font-size:10.5pt;line-height:150%">;</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
style="mso-bidi-font-size:10.5pt;line-height:150%">;</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
Calibri;mso-ascii-theme-font:minor-latin;mso-fareast-font-family:宋体;mso-fareast-theme-font:
minor-fareast;mso-hansi-font-family:Calibri;mso-hansi-theme-font:minor-latin">,网址:</span><span lang="EN-US"
style="mso-bidi-font-size:10.5pt;line-height:150%">www.gulimall.com</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
style="mso-bidi-font-size:10.5pt;line-height:150%">www.kkmall.com</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
Calibri;mso-ascii-theme-font:minor-latin;mso-fareast-font-family:宋体;mso-fareast-theme-font:
minor-fareast;mso-hansi-font-family:Calibri;mso-hansi-theme-font:minor-latin">)所有者(以下简称为</span><span lang="EN-US"
style="mso-bidi-font-size:10.5pt;line-height:150%">;</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
style="mso-bidi-font-size:10.5pt;line-height:150%">;</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
Calibri;mso-ascii-theme-font:minor-latin;mso-fareast-font-family:宋体;mso-fareast-theme-font:
minor-fareast;mso-hansi-font-family:Calibri;mso-hansi-theme-font:minor-latin">KK商城</span><span lang="EN-US"
style="mso-bidi-font-size:10.5pt;line-height:150%">;</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
style="mso-bidi-font-size:10.5pt;line-height:150%">;</span><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-font-family:
Calibri;mso-ascii-theme-font:minor-latin;mso-fareast-font-family:宋体;mso-fareast-theme-font:
minor-fareast;mso-hansi-font-family:Calibri;mso-hansi-theme-font:minor-latin">之间就KK商城网站服务等相关事宜所订立的契约请您仔细阅读<span
class="GramE">本注册</span>协议,您点击</span><span lang="EN-US" style="mso-bidi-font-size:
@ -1534,7 +1534,9 @@ bold">并<span class="GramE">确认您</span>已经充分理解本政策所写
line-height:150%;tab-stops:21.0pt;layout-grid-mode:char;mso-layout-grid-align:
none"><span style="mso-bookmark:OLE_LINK17"><span style="mso-bookmark:OLE_LINK18"><span style="mso-bidi-font-size:10.5pt;line-height:150%;mso-ascii-font-family:宋体;
mso-ascii-theme-font:minor-fareast;mso-fareast-font-family:宋体;mso-fareast-theme-font:
minor-fareast;mso-hansi-font-family:宋体;mso-hansi-theme-font:minor-fareast">如对本隐私政策或相关事宜有任何问题,您可随时通过访问<span lang="EN-US">https://help.gulimall.com</span>在线客服系统、发送邮件至<span lang="EN-US">privacy@gulimall.com</span>或拨打我们的任何一部客<span class="GramE">服电话</span>等多种方式与我们联系 。<span lang="EN-US"><o:p></o:p></span></span>
minor-fareast;mso-hansi-font-family:宋体;mso-hansi-theme-font:minor-fareast">如对本隐私政策或相关事宜有任何问题,您可随时通过访问<span lang="EN-US">https://help.kkmall.com</span>在线客服系统、发送邮件至<span
lang="EN-US">privacy@kkmall.com</span>或拨打我们的任何一部客<span class="GramE">服电话</span>等多种方式与我们联系 。<span
lang="EN-US"><o:p></o:p></span></span>
</span>
</span>
</p>
@ -3564,10 +3566,10 @@ mso-char-indent-count:2.0;line-height:150%;layout-grid-mode:char;mso-layout-grid
none"><span style="mso-bookmark:OLE_LINK17"><span style="mso-bookmark:OLE_LINK18"><span style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-theme-font:
minor-fareast;mso-fareast-font-family:宋体;mso-fareast-theme-font:minor-fareast;
mso-hansi-theme-font:minor-fareast;mso-bidi-font-weight:bold">如果您无法通过上述方式访问、更正或<span class="GramE">删除您</span>的个人信息,或您需要访问、更正或<span
class="GramE">删除您</span>在使用我们产品与<span lang="EN-US">/</span>或服务时所产生的其他个人信息或您认为KK商城存在任何违反法律法规或与您关于个人信息的收集或使用的约定<span
class="GramE">您均可以</span>发送电子邮件至<span lang="EN-US">privacy@gulimall.com</span>或通过本协议下方的其他方式与我们联系。为了保障安全,我们可能需要您提供书面请求,或以其他方式证明您的身份,我们将在收到您反馈并<span
class="GramE">验证您</span>的身份后的<span lang="EN-US">30</span>天内答复您的请求。对于<span class="GramE">您合理</span>的请求,我们原则上不收取费用,但对多次重复、超出合理限度的请求,我们将视情收取一定成本费用。对于那些无端重复、需要过多技术手段(例如,需要开发新系统或从根本上改变现行惯例)、给他人合法权益带来风险或者非常不切实际(例如,涉及备份磁带上存放的信息)的请求,我们可能会予以拒绝。<span
lang="EN-US"><o:p></o:p></span></span>
class="GramE">删除您</span>在使用我们产品与<span lang="EN-US">/</span>或服务时所产生的其他个人信息或您认为KK商城存在任何违反法律法规或与您关于个人信息的收集或使用的约定<span
class="GramE">您均可以</span>发送电子邮件至<span lang="EN-US">privacy@kkmall.com</span>或通过本协议下方的其他方式与我们联系。为了保障安全,我们可能需要您提供书面请求,或以其他方式证明您的身份,我们将在收到您反馈并<span
class="GramE">验证您</span>的身份后的<span lang="EN-US">30</span>天内答复您的请求。对于<span class="GramE">您合理</span>的请求,我们原则上不收取费用,但对多次重复、超出合理限度的请求,我们将视情收取一定成本费用。对于那些无端重复、需要过多技术手段(例如,需要开发新系统或从根本上改变现行惯例)、给他人合法权益带来风险或者非常不切实际(例如,涉及备份磁带上存放的信息)的请求,我们可能会予以拒绝。<span
lang="EN-US"><o:p></o:p></span></span>
</span>
</span>
</p>
@ -3830,13 +3832,15 @@ mso-fareast-theme-font:minor-fareast;mso-hansi-theme-font:minor-fareast">1</span
minor-fareast;mso-fareast-font-family:宋体;mso-fareast-theme-font:minor-fareast;
mso-hansi-theme-font:minor-fareast">、如您对本隐私政策或您个人信息的相关事宜有任何问题、意见或建议,<a name="OLE_LINK3"></a><a name="OLE_LINK4"><span style="mso-bookmark:OLE_LINK3">请通过访问</span></a>
</span><span style="mso-bookmark:OLE_LINK4"><span style="mso-bookmark:OLE_LINK3"></span></span>
<a href="/" target="_blank"><span style="mso-bookmark:OLE_LINK4"><span style="mso-bookmark:OLE_LINK3"><span lang="EN-US" style="mso-bidi-font-size:10.5pt;
<a href="/" target="_blank"><span style="mso-bookmark:OLE_LINK4"><span
style="mso-bookmark:OLE_LINK3"><span lang="EN-US" style="mso-bidi-font-size:10.5pt;
line-height:150%;font-family:宋体;mso-ascii-theme-font:minor-fareast;mso-fareast-font-family:
宋体;mso-fareast-theme-font:minor-fareast;mso-hansi-theme-font:minor-fareast">https://help.gulimall.com</span></span>
宋体;mso-fareast-theme-font:minor-fareast;mso-hansi-theme-font:minor-fareast">https://help.kkmall.com</span></span>
</span>
</a><span style="mso-bookmark:OLE_LINK4"><span style="mso-bookmark:OLE_LINK3"><span style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-theme-font:
minor-fareast;mso-fareast-font-family:宋体;mso-fareast-theme-font:minor-fareast;
mso-hansi-theme-font:minor-fareast">在线客服系统、发送邮件至<span lang="EN-US">privacy@gulimall.com</span>或拨打我们的任何一部客<span class="GramE">服电话</span>等多种方式与我们联系</span>
mso-hansi-theme-font:minor-fareast">在线客服系统、发送邮件至<span lang="EN-US">privacy@kkmall.com</span>或拨打我们的任何一部客<span
class="GramE">服电话</span>等多种方式与我们联系</span>
</span>
</span><span style="mso-bidi-font-size:
10.5pt;line-height:150%;font-family:宋体;mso-ascii-theme-font:minor-fareast;
@ -3849,9 +3853,11 @@ mso-char-indent-count:2.0;line-height:150%;layout-grid-mode:char;mso-layout-grid
none"><span style="mso-bookmark:OLE_LINK17"><span style="mso-bookmark:OLE_LINK18"><span lang="EN-US" style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;
mso-ascii-theme-font:minor-fareast;mso-fareast-font-family:宋体;mso-fareast-theme-font:
minor-fareast;mso-hansi-theme-font:minor-fareast">2</span></span>
</span><span style="mso-bookmark:OLE_LINK17"><span style="mso-bookmark:OLE_LINK18"><span style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-theme-font:
</span><span style="mso-bookmark:OLE_LINK17"><span style="mso-bookmark:OLE_LINK18"><span
style="mso-bidi-font-size:10.5pt;line-height:150%;font-family:宋体;mso-ascii-theme-font:
minor-fareast;mso-fareast-font-family:宋体;mso-fareast-theme-font:minor-fareast;
mso-hansi-theme-font:minor-fareast">、我们设立了个人信息保护专职部门(或个人信息保护专员),您可以通过发送邮件至<span lang="EN-US">privacy@gulimall.com</span>的方式与其联系。<span lang="EN-US"><o:p></o:p></span></span>
mso-hansi-theme-font:minor-fareast">、我们设立了个人信息保护专职部门(或个人信息保护专员),您可以通过发送邮件至<span lang="EN-US">privacy@kkmall.com</span>的方式与其联系。<span
lang="EN-US"><o:p></o:p></span></span>
</span>
</span>
</p>

View file

@ -0,0 +1,19 @@
package name.lkk.kkmall.cart.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Configuration
public class MyThreadConfig {
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties threadPoolConfigProperties) {
return new ThreadPoolExecutor(threadPoolConfigProperties.getCoreSize(), threadPoolConfigProperties.getMaxSize(), threadPoolConfigProperties.getKeepAliveTime(), TimeUnit.SECONDS, new LinkedBlockingDeque<>(10000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
}
}

View file

@ -0,0 +1,18 @@
package name.lkk.kkmall.cart.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "kkmall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
private Integer coreSize;
private Integer maxSize;
private Integer keepAliveTime;
}

View file

@ -1,10 +1,19 @@
package name.lkk.kkmall.cart.controller;
import lombok.extern.slf4j.Slf4j;
import name.lkk.kkmall.cart.interceptor.CartInterceptor;
import name.lkk.kkmall.cart.to.UserInfoTo;
import name.lkk.kkmall.cart.service.CartService;
import name.lkk.kkmall.cart.vo.CartItemVo;
import name.lkk.kkmall.cart.vo.CartVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.List;
import java.util.concurrent.ExecutionException;
/**
* @author: kirklin
@ -15,6 +24,9 @@ import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class CartController {
@Autowired
private CartService cartService;
/**
* 去购物车页面的请求
* 浏览器有一个cookie:user-key 标识用户的身份一个月过期
@ -28,11 +40,113 @@ public class CartController {
* @return
*/
@GetMapping({"/", "/cart.html"})
public String carListPage() {
public String carListPage(Model model) throws ExecutionException, InterruptedException {
//快速得到用户信息id,user-key
UserInfoTo userInfoTo = CartInterceptor.userInfoToThreadLocal.get();
log.info(userInfoTo.toString());
// UserInfoTo userInfoTo = CartInterceptor.userInfoToThreadLocal.get();
CartVo cartVo = cartService.getCart();
model.addAttribute("cart", cartVo);
return "cartList";
}
/**
* 获取当前用户的购物车商品项
*
* @return
*/
@GetMapping(value = "/currentUserCartItems")
@ResponseBody
public List<CartItemVo> getCurrentCartItems() {
List<CartItemVo> cartItemVoList = cartService.getUserCartItems();
return cartItemVoList;
}
/**
* 添加商品到购物车
* attributes.addFlashAttribute():将数据放在session中可以在页面中取出但是只能取一次
* attributes.addAttribute():将数据放在url后面
*
* @return
*/
@GetMapping(value = "/addToCart")
public String addCartItem(@RequestParam("skuId") Long skuId,
@RequestParam("num") Integer num,
RedirectAttributes attributes) throws ExecutionException, InterruptedException {
cartService.addToCart(skuId, num);
attributes.addAttribute("skuId", skuId);
return "redirect:http://cart.kkmall.com/addToCartSuccessPage.html";
}
/**
* 跳转到添加购物车成功页面
*
* @param skuId
* @param model
* @return
*/
@GetMapping(value = "/addToCartSuccessPage.html")
public String addToCartSuccessPage(@RequestParam("skuId") Long skuId,
Model model) {
//重定向到成功页面再次查询购物车数据即可
CartItemVo cartItemVo = cartService.getCartItem(skuId);
model.addAttribute("cartItem", cartItemVo);
return "success";
}
/**
* 商品是否选中
*
* @param skuId
* @param checked
* @return
*/
@GetMapping(value = "/checkItem")
public String checkItem(@RequestParam(value = "skuId") Long skuId,
@RequestParam(value = "checked") Integer checked) {
cartService.checkItem(skuId, checked);
return "redirect:http://cart.kkmall.com/cart.html";
}
/**
* 改变商品数量
*
* @param skuId
* @param num
* @return
*/
@GetMapping(value = "/countItem")
public String countItem(@RequestParam(value = "skuId") Long skuId,
@RequestParam(value = "num") Integer num) {
cartService.changeItemCount(skuId, num);
return "redirect:http://cart.kkmall.com/cart.html";
}
/**
* 删除商品信息
*
* @param skuId
* @return
*/
@GetMapping(value = "/deleteItem")
public String deleteItem(@RequestParam("skuId") Integer skuId) {
cartService.deleteIdCartInfo(skuId);
return "redirect:http://cart.kkmall.com/cart.html";
}
}

View file

@ -0,0 +1,5 @@
package name.lkk.kkmall.cart.exception;
public class CartExceptionHandler extends RuntimeException {
}

View file

@ -0,0 +1,30 @@
package name.lkk.kkmall.cart.exception;
import name.lkk.common.utils.R;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class RuntimeExceptionHandler {
/**
* 全局统一异常处理
*
* @param exception
* @return
*/
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public R handler(RuntimeException exception) {
return R.error(exception.getMessage());
}
@ExceptionHandler(CartExceptionHandler.class)
public R userHandler(CartExceptionHandler exception) {
return R.error("购物车无此商品");
}
}

View file

@ -0,0 +1,48 @@
package name.lkk.kkmall.cart.feign;
import name.lkk.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.math.BigDecimal;
import java.util.List;
/**
* 商品服务远程调用
*
* @author kirklin
*/
@FeignClient("kkmall-product")
public interface ProductFeignService {
/**
* 根据skuId查询sku信息
*
* @param skuId
* @return
*/
@RequestMapping("/product/skuinfo/info/{skuId}")
R getInfo(@PathVariable("skuId") Long skuId);
/**
* 根据skuId查询pms_sku_sale_attr_value表中的信息
*
* @param skuId
* @return
*/
@GetMapping(value = "/product/skusaleattrvalue/stringlist/{skuId}")
List<String> getSkuSaleAttrValues(@PathVariable("skuId") Long skuId);
/**
* 根据skuId查询当前商品的最新价格
*
* @param skuId
* @return
*/
@GetMapping(value = "/product/skuinfo/{skuId}/price")
BigDecimal getPrice(@PathVariable("skuId") Long skuId);
}

View file

@ -0,0 +1,70 @@
package name.lkk.kkmall.cart.service;
import name.lkk.kkmall.cart.vo.CartItemVo;
import name.lkk.kkmall.cart.vo.CartVo;
import java.util.List;
import java.util.concurrent.ExecutionException;
public interface CartService {
/**
* 将商品添加至购物车
*
* @param skuId
* @param num
* @return
*/
CartItemVo addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException;
/**
* 获取购物车某个购物项
*
* @param skuId
* @return
*/
CartItemVo getCartItem(Long skuId);
/**
* 获取购物车里面的信息
*
* @return
*/
CartVo getCart() throws ExecutionException, InterruptedException;
/**
* 清空购物车的数据
*
* @param cartKey
*/
public void clearCartInfo(String cartKey);
/**
* 勾选购物项
*
* @param skuId
* @param check
*/
void checkItem(Long skuId, Integer check);
/**
* 改变商品数量
*
* @param skuId
* @param num
*/
void changeItemCount(Long skuId, Integer num);
/**
* 删除购物项
*
* @param skuId
*/
void deleteIdCartInfo(Integer skuId);
List<CartItemVo> getUserCartItems();
}

View file

@ -0,0 +1,284 @@
package name.lkk.kkmall.cart.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import name.lkk.common.utils.R;
import name.lkk.kkmall.cart.exception.CartExceptionHandler;
import name.lkk.kkmall.cart.feign.ProductFeignService;
import name.lkk.kkmall.cart.interceptor.CartInterceptor;
import name.lkk.kkmall.cart.service.CartService;
import name.lkk.kkmall.cart.to.UserInfoTo;
import name.lkk.kkmall.cart.vo.CartItemVo;
import name.lkk.kkmall.cart.vo.CartVo;
import name.lkk.kkmall.cart.vo.SkuInfoVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
import static name.lkk.common.constant.CartConstant.CART_PREFIX;
@Slf4j
@Service("cartService")
public class CartServiceImpl implements CartService {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private ProductFeignService productFeignService;
@Autowired
private ThreadPoolExecutor executor;
@Override
public CartItemVo addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
//拿到要操作的购物车信息
BoundHashOperations<String, Object, Object> cartOps = getCartOps();
//判断Redis是否有该商品的信息
String productRedisValue = (String) cartOps.get(skuId.toString());
//如果没有就添加数据
if (StringUtils.isEmpty(productRedisValue)) {
//2添加新的商品到购物车(redis)
CartItemVo cartItemVo = new CartItemVo();
//开启第一个异步任务
CompletableFuture<Void> getSkuInfoFuture = CompletableFuture.runAsync(() -> {
//1远程查询当前要添加商品的信息
R productSkuInfo = productFeignService.getInfo(skuId);
SkuInfoVo skuInfo = productSkuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {
});
//数据赋值操作
cartItemVo.setSkuId(skuInfo.getSkuId());
cartItemVo.setTitle(skuInfo.getSkuTitle());
cartItemVo.setImage(skuInfo.getSkuDefaultImg());
cartItemVo.setPrice(skuInfo.getPrice());
cartItemVo.setCount(num);
}, executor);
//开启第二个异步任务
CompletableFuture<Void> getSkuAttrValuesFuture = CompletableFuture.runAsync(() -> {
//2远程查询skuAttrValues组合信息
List<String> skuSaleAttrValues = productFeignService.getSkuSaleAttrValues(skuId);
cartItemVo.setSkuAttrValues(skuSaleAttrValues);
}, executor);
//等待所有的异步任务全部完成
CompletableFuture.allOf(getSkuInfoFuture, getSkuAttrValuesFuture).get();
String cartItemJson = JSON.toJSONString(cartItemVo);
cartOps.put(skuId.toString(), cartItemJson);
return cartItemVo;
} else {
//购物车有此商品修改数量即可
CartItemVo cartItemVo = JSON.parseObject(productRedisValue, CartItemVo.class);
cartItemVo.setCount(cartItemVo.getCount() + num);
//修改redis的数据
String cartItemJson = JSON.toJSONString(cartItemVo);
cartOps.put(skuId.toString(), cartItemJson);
return cartItemVo;
}
}
@Override
public CartItemVo getCartItem(Long skuId) {
//拿到要操作的购物车信息
BoundHashOperations<String, Object, Object> cartOps = getCartOps();
String redisValue = (String) cartOps.get(skuId.toString());
CartItemVo cartItemVo = JSON.parseObject(redisValue, CartItemVo.class);
return cartItemVo;
}
/**
* 获取用户登录或者未登录购物车里所有的数据
*
* @return
* @throws ExecutionException
* @throws InterruptedException
*/
@Override
public CartVo getCart() throws ExecutionException, InterruptedException {
CartVo cartVo = new CartVo();
UserInfoTo userInfoTo = CartInterceptor.userInfoToThreadLocal.get();
if (userInfoTo.getUserId() != null) {
//1登录
String cartKey = CART_PREFIX + userInfoTo.getUserId();
//临时购物车的键
String temptCartKey = CART_PREFIX + userInfoTo.getUserKey();
//2如果临时购物车的数据还未进行合并
List<CartItemVo> tempCartItems = getCartItems(temptCartKey);
if (tempCartItems != null) {
//临时购物车有数据需要进行合并操作
for (CartItemVo item : tempCartItems) {
addToCart(item.getSkuId(), item.getCount());
}
//清除临时购物车的数据
clearCartInfo(temptCartKey);
}
//3获取登录后的购物车数据包含合并过来的临时购物车的数据和登录后购物车的数据
List<CartItemVo> cartItems = getCartItems(cartKey);
cartVo.setItems(cartItems);
} else {
//没登录
String cartKey = CART_PREFIX + userInfoTo.getUserKey();
//获取临时购物车里面的所有购物项
List<CartItemVo> cartItems = getCartItems(cartKey);
cartVo.setItems(cartItems);
}
return cartVo;
}
/**
* 获取到我们要操作的购物车
*
* @return
*/
private BoundHashOperations<String, Object, Object> getCartOps() {
//先得到当前用户信息
UserInfoTo userInfoTo = CartInterceptor.userInfoToThreadLocal.get();
String cartKey = "";
if (userInfoTo.getUserId() != null) {
//kkmall:cart:1
cartKey = CART_PREFIX + userInfoTo.getUserId();
} else {
cartKey = CART_PREFIX + userInfoTo.getUserKey();
}
//绑定指定的key操作Redis
BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
return operations;
}
/**
* 获取购物车里面的数据
*
* @param cartKey
* @return
*/
private List<CartItemVo> getCartItems(String cartKey) {
//获取购物车里面的所有商品
BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
List<Object> values = operations.values();
if (values != null && values.size() > 0) {
List<CartItemVo> cartItemVoStream = values.stream().map((obj) -> {
String str = (String) obj;
CartItemVo cartItem = JSON.parseObject(str, CartItemVo.class);
return cartItem;
}).collect(Collectors.toList());
return cartItemVoStream;
}
return null;
}
@Override
public void clearCartInfo(String cartKey) {
redisTemplate.delete(cartKey);
}
@Override
public void checkItem(Long skuId, Integer check) {
//查询购物车里面的商品
CartItemVo cartItem = getCartItem(skuId);
//修改商品状态
cartItem.setCheck(check == 1 ? true : false);
//序列化存入redis中
String redisValue = JSON.toJSONString(cartItem);
BoundHashOperations<String, Object, Object> cartOps = getCartOps();
cartOps.put(skuId.toString(), redisValue);
}
/**
* 修改购物项数量
*
* @param skuId
* @param num
*/
@Override
public void changeItemCount(Long skuId, Integer num) {
//查询购物车里面的商品
CartItemVo cartItem = getCartItem(skuId);
cartItem.setCount(num);
BoundHashOperations<String, Object, Object> cartOps = getCartOps();
//序列化存入redis中
String redisValue = JSON.toJSONString(cartItem);
cartOps.put(skuId.toString(), redisValue);
}
/**
* 删除购物项
*
* @param skuId
*/
@Override
public void deleteIdCartInfo(Integer skuId) {
BoundHashOperations<String, Object, Object> cartOps = getCartOps();
cartOps.delete(skuId.toString());
}
@Override
public List<CartItemVo> getUserCartItems() {
List<CartItemVo> cartItemVoList = new ArrayList<>();
//获取当前用户登录的信息
UserInfoTo userInfoTo = CartInterceptor.userInfoToThreadLocal.get();
//如果用户未登录直接返回null
if (userInfoTo.getUserId() == null) {
return null;
} else {
//获取购物车项
String cartKey = CART_PREFIX + userInfoTo.getUserId();
//获取所有的
List<CartItemVo> cartItems = getCartItems(cartKey);
if (cartItems == null) {
throw new CartExceptionHandler();
}
//筛选出选中的
cartItemVoList = cartItems.stream()
.filter(items -> items.getCheck())
.map(item -> {
//更新为最新的价格查询数据库
BigDecimal price = productFeignService.getPrice(item.getSkuId());
item.setPrice(price);
return item;
})
.collect(Collectors.toList());
}
return cartItemVoList;
}
}

View file

@ -1,87 +0,0 @@
package name.lkk.kkmall.cart.vo;
import java.math.BigDecimal;
import java.util.List;
/**
* 购物车本VO的GETSET方法非默认实现
*/
public class Cart {
private List<CartItem> items;
/**
* 商品的数量
*/
private Integer countNum;
/**
* 商品的类型数量
*/
private Integer countType;
/**
* 整个购物车的总价
*/
private BigDecimal totalAmount;
/**
* 减免的价格
*/
private BigDecimal reduce = new BigDecimal("0.00");
public List<CartItem> getItems() {
return items;
}
public void setItems(List<CartItem> items) {
this.items = items;
}
/**
* 计算商品的总量
*
* @return
*/
public Integer getCountNum() {
int count = 0;
if (this.items != null && this.items.size() > 0) {
for (CartItem item : this.items) {
count += item.getCount();
}
}
return count;
}
public Integer getCountType() {
int count = 0;
if (this.items != null && this.items.size() > 0) {
for (CartItem item : this.items) {
count += 1;
}
}
return count;
}
public BigDecimal getTotalAmount() {
BigDecimal amount = new BigDecimal("0");
if (this.items != null && this.items.size() > 0) {
for (CartItem item : this.items) {
if (item.getCheck()) {
BigDecimal totalPrice = item.getTotalPrice();
amount = amount.add(totalPrice);
}
}
}
return amount.subtract(this.getReduce());
}
public BigDecimal getReduce() {
return reduce;
}
public void setReduce(BigDecimal reduce) {
this.reduce = reduce;
}
}

View file

@ -6,7 +6,7 @@ import java.util.List;
/**
* 购物车商品项本VO的GETSET方法非默认实现
*/
public class CartItem {
public class CartItemVo {
private Long skuId;
@ -19,7 +19,7 @@ public class CartItem {
private String image;
private List<String> skuAttr;
private List<String> skuAttrValues;
/**
* 价格
@ -65,12 +65,12 @@ public class CartItem {
this.image = image;
}
public List<String> getSkuAttr() {
return skuAttr;
public List<String> getSkuAttrValues() {
return skuAttrValues;
}
public void setSkuAttr(List<String> skuAttr) {
this.skuAttr = skuAttr;
public void setSkuAttrValues(List<String> skuAttrValues) {
this.skuAttrValues = skuAttrValues;
}
public BigDecimal getPrice() {

View file

@ -0,0 +1,87 @@
package name.lkk.kkmall.cart.vo;
import java.math.BigDecimal;
import java.util.List;
/**
* 购物车本VO的GETSET方法非默认实现
*/
public class CartVo {
private List<CartItemVo> items;
/**
* 商品的数量
*/
private Integer countNum;
/**
* 商品的类型数量
*/
private Integer countType;
/**
* 整个购物车的总价
*/
private BigDecimal totalAmount;
/**
* 减免的价格
*/
private BigDecimal reduce = new BigDecimal("0.00");
public List<CartItemVo> getItems() {
return items;
}
public void setItems(List<CartItemVo> items) {
this.items = items;
}
/**
* 计算商品的总量
*
* @return
*/
public Integer getCountNum() {
int count = 0;
if (this.items != null && this.items.size() > 0) {
for (CartItemVo item : this.items) {
count += item.getCount();
}
}
return count;
}
public Integer getCountType() {
int count = 0;
if (this.items != null && this.items.size() > 0) {
for (CartItemVo item : this.items) {
count += 1;
}
}
return count;
}
public BigDecimal getTotalAmount() {
BigDecimal amount = new BigDecimal("0");
if (this.items != null && this.items.size() > 0) {
for (CartItemVo item : this.items) {
if (item.getCheck()) {
BigDecimal totalPrice = item.getTotalPrice();
amount = amount.add(totalPrice);
}
}
}
return amount.subtract(this.getReduce());
}
public BigDecimal getReduce() {
return reduce;
}
public void setReduce(BigDecimal reduce) {
this.reduce = reduce;
}
}

View file

@ -0,0 +1,53 @@
package name.lkk.kkmall.cart.vo;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class SkuInfoVo {
private Long skuId;
/**
* spuId
*/
private Long spuId;
/**
* sku名称
*/
private String skuName;
/**
* sku介绍描述
*/
private String skuDesc;
/**
* 所属分类id
*/
private Long catalogId;
/**
* 品牌id
*/
private Long brandId;
/**
* 默认图片
*/
private String skuDefaultImg;
/**
* 标题
*/
private String skuTitle;
/**
* 副标题
*/
private String skuSubtitle;
/**
* 价格
*/
private BigDecimal price;
/**
* 销量
*/
private Long saleCount;
}

File diff suppressed because it is too large Load diff

View file

@ -1,124 +1,106 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<title>添加购物车</title>
<script type="text/javascript" src="/static/cart/js/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="/static/cart/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="/static/cart/js/swiper.min.js"></script>
<script src="/static/cart/js/swiper.min.js"></script>
<link rel="stylesheet" type="text/css" href="/static/cart/css/swiper.min.css"/>
<link rel="stylesheet" type="text/css" href="/static/cart/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" type="text/css" href="/static/cart/css/success.css"/>
<meta charset="utf-8"/>
<title>商品已成功加入购物车</title>
<script type="text/javascript" src="/static/cart/js/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="/static/cart/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="/static/cart/js/swiper.min.js"></script>
<script src="/static/cart/js/swiper.min.js"></script>
<link rel="stylesheet" type="text/css" href="/static/cart//css/swiper.min.css"/>
<link rel="stylesheet" type="text/css" href="/static/cart//bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" type="text/css" href="/static/cart//css/success.css"/>
</head>
<body>
<!--头部-->
<div class="alert-info">
<div class="hd_wrap_top">
<ul class="hd_wrap_left">
<li class="hd_home"><i class="glyphicon glyphicon-home"></i>
<a href="http://kkmall.com">KK商城首页</a>
</li>
</ul>
<ul class="hd_wrap_right">
<li class="forel" th:if="${session.loginUser} ==null">
<a href="http://auth.kkmall.com/login.html" class="link_login">你好,请登录</a>&nbsp;
<a href="http://auth.kkmall.com/reg.html" class="link_regist">免费注册</a>
</li>
<li class="forel" th:if="${session.loginUser} !=null">
<a class="link_login" style="width: 100px">[[${session.loginUser.username}]]</a>&nbsp;
<a href="http://auth.kkmall.com/oauth2.0/logout" class="link_regist">退出登录</a>
</li>
<li class="spacer"></li>
<li>
<a href="/">我的订单</a>
</li>
</ul>
</div>
<div class="hd_wrap_top">
<ul class="hd_wrap_left">
<li class="hd_home"><i class="glyphicon glyphicon-home"></i>
<a href="http://kkmall.com/">kk商城首页</a>
</li>
</ul>
<ul class="hd_wrap_right">
<li>
<a th:if="${session.loginUser == null}" href="http://auth.kkmall.com/login.html" class="li_2">请登录</a>
<a th:if="${session.loginUser != null}">欢迎, [[${session.loginUser.nickname}]]</a>
</li>
<li>
<a th:if="${session.loginUser == null}" href="http://auth.kkmall.com/reg.html"
style="color: red;">免费注册</a>
</li>
<li>
<a href="/javascript:;">我的订单</a>
</li>
</ul>
</div>
</div>
<div class="nav-tabs-justified">
<div class="nav_wrap">
<div class="nav_wrap">
<div class="nav_top">
<div class="nav_top_one">
<a href="http://kkmall.com/">
<img src="/static/cart/img/logo1.jpg" style="height: 60px;width:180px;"/>
</a>
</div>
<div class="nav_top_two"><input type="text"/>
<button>搜索</button>
</div>
</div>
<div class="nav_top">
<div class="nav_top_one">
<a href="http://kkmall.com"><img src="/static/cart/img/logo1.jpg" style="height: 60px;width:180px;"/></a>
</div>
<div class="nav_top_two"><input type="text"/>
<button>搜索</button>
</div>
</div>
</div>
</div>
<div class="main">
<div class="success-wrap">
<div class="w" id="result">
<div class="m succeed-box">
<div th:if="${item!=null}" class="mc success-cont">
<div class="success-lcol">
<div class="success-top"><b class="succ-icon"></b>
<h3 class="ftx-02">商品已成功加入购物车</h3></div>
<div class="p-item">
<div class="p-img">
<a href="/" target="_blank"><img style="height: 60px;width:60px;" th:src="${item.image}"></a>
</div>
<div class="p-info">
<div class="p-name">
<a th:href="'http://item.kkmall.com/' + ${item.skuId} + '.html'" th:text="${item.title}">TCL 55A950C 55英寸32核人工智能
HDR曲面超薄4K电视金属机身枪色</a>
</div>
<div class="p-extra"><span class="txt" th:text="'数量: ' + ${item.count}"> 数量1</span></div>
</div>
<div class="clr"></div>
</div>
</div>
<div class="success-btns success-btns-new">
<div class="success-ad">
<a href="/#none"></a>
</div>
<div class="clr"></div>
<div class="bg_shop">
<a class="btn-tobback" th:href="'http://item.kkmall.com/' + ${item.skuId} + '.html'">查看商品详情</a>
<a class="btn-addtocart" href="http://cart.kkmall.com/cart.html" id="GotoShoppingCart"><b></b>去购物车结算</a>
</div>
</div>
</div>
<div th:if="${item==null}" class="mc success-cont">
<div class="success-lcol">
<div class="success-top"><b class="succ-icon"></b>
<h3 class="ftx-02">购物车中无商品</h3></div>
<div class="p-item">
<div class="p-img">
<a href="/" target="_blank"></a>
</div>
<div class="p-info">
<div class="p-name">
<div class="success-wrap">
<div class="w" id="result">
<div class="m succeed-box">
<div th:if="${cartItem!=null}" class="mc success-cont">
<div class="success-lcol">
<div class="success-top"><b class="succ-icon"></b>
<h3 class="ftx-02">商品已成功加入购物车</h3></div>
<div class="p-item">
<div class="p-img">
<a href="/javascript:;" target="_blank">
<img style="height: 60px;width:60px;" th:src="${cartItem.image}"></a>
</div>
<div class="p-info">
<div class="p-name">
<a th:href="'http://item.kkmall.com/'+${cartItem.skuId}+'.html'"
th:text="${cartItem.title}">TCL 55A950C 55英寸32核人工智能 HDR曲面超薄4K电视金属机身枪色</a>
</div>
<div class="p-extra"><span class="txt" th:text="'数量:'+${cartItem.count}"> 数量1</span>
</div>
</div>
<div class="clr"></div>
</div>
</div>
<div class="success-btns success-btns-new">
<div class="success-ad">
<a href="/#none"></a>
</div>
<div class="clr"></div>
<div class="bg_shop">
<a class="btn-tobback"
th:href="'http://item.kkmall.com/'+${cartItem.skuId}+'.html'">查看商品详情</a>
<a class="btn-addtocart" href="http://cart.kkmall.com/cart.html"
id="GotoShoppingCart"><b></b>去购物车结算</a>
</div>
</div>
</div>
<div th:if="${cartItem==null}" class="mc success-cont">
<h2>购物车中无此商品</h2>
<a href="http://kkmall.com/">去购物</a>
</div>
<div class="p-extra"><span class="txt" ></span></div>
</div>
<div class="clr"></div>
</div>
</div>
<div class="success-btns success-btns-new">
<div class="success-ad">
<a href="/#none"></a>
</div>
<div class="clr"></div>
<div class="bg_shop">
<a class="btn-addtocart" href="http://kkmall.com" id="GotoShoppingCart"><b></b>去购物</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script type="text/javascript" src="/static/cart/js/success.js"></script>
</html>

View file

@ -14,4 +14,6 @@ public class CartConstant {
* 购物车临时用户COOKIE过期时间
*/
public static final int TEMP_USER_COOKIE_TIME_OUT = 60 * 60 * 24 * 30;
public final static String CART_PREFIX = "kkmall:cart:";
}

View file

@ -7,6 +7,7 @@ import name.lkk.kkmall.product.service.SkuInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Map;
@ -25,11 +26,22 @@ public class SkuInfoController {
@Autowired
private SkuInfoService skuInfoService;
@GetMapping("/{skuId}/price")
public R getPrice(@PathVariable("skuId") Long skuId){
/**
* 根据skuId查询当前商品的价格
*
* @param skuId
* @return
*/
@GetMapping(value = "/{skuId}/price")
public BigDecimal getPrice(@PathVariable("skuId") Long skuId) {
SkuInfoEntity byId = skuInfoService.getById(skuId);
return R.ok().setData(byId.getPrice().toString());
//获取当前商品的信息
SkuInfoEntity skuInfo = skuInfoService.getById(skuId);
//获取商品的价格
BigDecimal price = skuInfo.getPrice();
return price;
}
/**

View file

@ -27,7 +27,9 @@
WHERE info.`spu_id` = #{spuId} GROUP BY ssav.`attr_id`,ssav.`attr_name`,ssav.`attr_value`
</select>
<select id="getSkuSaleAttrValuesAsStringList" resultType="java.lang.String">
SELECT CONCAT(attr_name,":",attr_value) FROM `pms_sku_sale_attr_value` WHERE sku_id = #{skuId};
SELECT CONCAT(attr_name, ':', attr_value)
FROM pms_sku_sale_attr_value
WHERE sku_id = #{skuId}
</select>
</mapper>