主頁 > 軟體設計 > Day425&426.購物車服務 -谷粒商城

Day425&426.購物車服務 -谷粒商城

2021-10-22 07:40:43 軟體設計

購物車服務

一、環境搭建

  • springboot初始化

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-w8Etki5f-1634740503555)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20211020215413222.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mx7XHAam-1634740503558)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20211020215509730.png)]

  • 新增本地域名cart.achangmall.com

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-squlof7q-1634740503559)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20211020220220652.png)]

  • 修改對應pom配置,與此次服務間版本對應
    • 引入公共依賴
    • 修改springboot版本
    • 修改springcloud版本

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-T0lijbWA-1634740503562)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20211020220324525.png)]

  • 將提供的靜態資源匯入nginx服務,做到動靜分離

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zSZSoZS2-1634740503564)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20211020221013248.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Et4sjIlg-1634740503565)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20211020221039429.png)]

  • 修改頁面對應的資源地址,修改只選nginx的靜態地址,如:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eQVVKGGa-1634740503567)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20211020221252757.png)]

  • 主啟動類com.achang.achangmall.cart.AchangmallCartApplication
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableFeignClients
@EnableDiscoveryClient
public class AchangmallCartApplication {
    public static void main(String[] args) {
        SpringApplication.run(AchangmallCartApplication.class, args);
    }
}
  • 組態檔achangmall-cart/src/main/resources/application.yaml
spring:
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    nacos:
      discovery:
        server-addr: localhost:8848
  thymeleaf:
    cache: false
  redis:
    host: 192.168.109.101
    port: 6379
  application:
    name: achangmall-cart

server:
  port: 30000
  • 網關配置路由映射achangmall-gateway/src/main/resources/application.yml
        - id: cart_route
          uri: lb://achangmall-cart
          predicates:
            - Host=cart.achangmall.com
  • 啟動服務測驗,訪問:http://cart.achangmall.com/

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6NV0o2aD-1634740503568)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20211020222801089.png)]


二、業務

在這里插入圖片描述

  • com.achang.achangmall.cart.vo.CartVo
/**
 * 購物車1級
 */
public class CartVo {

    /**
     * 購物車子項資訊
     */
    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;
    }

    public Integer getCountNum() {
        int count = 0;
        if (items != null && items.size() > 0) {
            for (CartItemVo item : items) {
                count += item.getCount();
            }
        }
        return count;
    }

    public Integer getCountType() {
        int count = 0;
        if (items != null && items.size() > 0) {
            for (CartItemVo item : items) {
                count += 1;
            }
        }
        return count;
    }

    public BigDecimal getTotalAmount() {
        BigDecimal amount = new BigDecimal("0");
        // 計算購物項總價
        if (!CollectionUtils.isEmpty(items)) {
            for (CartItemVo cartItem : items) {
                if (cartItem.getCheck()) {
                    amount = amount.add(cartItem.getTotalPrice());
                }
            }
        }
        // 計算優惠后的價格
        return amount.subtract(getReduce());
    }

    public BigDecimal getReduce() {
        return reduce;
    }

    public void setReduce(BigDecimal reduce) {
        this.reduce = reduce;
    }
}
  • com.achang.achangmall.cart.vo.CartItemVo
/**
 * 購物車2級--購物項
 */
public class CartItemVo {

    private Long skuId;

    private Boolean check = true;

    private String title;

    private String image;

    /**
     * 商品套餐屬性
     */
    private List<String> skuAttrValues;

    private BigDecimal price;

    private Integer count;

    private BigDecimal totalPrice;

    public Long getSkuId() {
        return skuId;
    }

    public void setSkuId(Long skuId) {
        this.skuId = skuId;
    }

    public Boolean getCheck() {
        return check;
    }

    public void setCheck(Boolean check) {
        this.check = check;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public List<String> getSkuAttrValues() {
        return skuAttrValues;
    }

    public void setSkuAttrValues(List<String> skuAttrValues) {
        this.skuAttrValues = skuAttrValues;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }

    /**
     * 計算當前購物項總價
     * @return
     */
    public BigDecimal getTotalPrice() {
        return this.price.multiply(new BigDecimal("" + this.count));
    }

    public void setTotalPrice(BigDecimal totalPrice) {
        this.totalPrice = totalPrice;
    }
}
  • com.achang.achangmall.cart.vo.SkuInfoVo
@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;
}
  • 引入依賴
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 整合springsession -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
  • com.achang.achangmall.cart.config.AchangmallSessionConfig
@Configuration
@EnableRedisHttpSession
public class AchangmallSessionConfig {
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        //放大作用域
        cookieSerializer.setDomainName("achangmall.com");
        cookieSerializer.setCookieName("ACHANGSESSION");
        return cookieSerializer;
    }

    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        //使用json存盤redis,而不是默認的序列化存盤
        return new GenericJackson2JsonRedisSerializer();
    }
}
  • com.achang.achangmall.cart.config.MyThreadConfig
@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@Configuration
public class MyThreadConfig {
    @Bean
    public ThreadPoolExecutor executor(ThreadPoolConfigProperties pool) {
        return new ThreadPoolExecutor(
                pool.getCoreSize(),
                pool.getMaxSize(),
                pool.getKeepAliveTime(),
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );
    }
}
  • com.achang.achangmall.cart.config.ThreadPoolConfigProperties
@ConfigurationProperties(prefix = "achangmall.thread")
@Data
public class ThreadPoolConfigProperties {
    private Integer coreSize;
    private Integer maxSize;
    private Integer keepAliveTime;
}
  • com.achang.achangmall.cart.exception.RuntimeExceptionHandler
@ControllerAdvice
public class RuntimeExceptionHandler {
    /**
     * 全域統一例外處理
     */
    @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("購物車無此商品");
    }
}
  • com.achang.achangmall.cart.exception.CartExceptionHandler
public class CartExceptionHandler extends RuntimeException {}
  • com.achang.achangmall.cart.feign.ProductFeignService
@FeignClient("achangmall-product")
public interface ProductFeignService {
    /**
     * 根據skuId查詢sku資訊
     */
    @RequestMapping("/product/skuinfo/info/{skuId}")
    R getInfo(@PathVariable("skuId") Long skuId);

    /**
     * 根據skuId查詢pms_sku_sale_attr_value表中的資訊
     */
    @GetMapping(value = "/product/skusaleattrvalue/stringList/{skuId}")
    List<String> getSkuSaleAttrValues(@PathVariable("skuId") Long skuId);

    /**
     * 根據skuId查詢當前商品的最新價格
     */
    @GetMapping(value = "/product/skuinfo/{skuId}/price")
    BigDecimal getPrice(@PathVariable("skuId") Long skuId);
}
  • com.achang.achangmall.cart.intercept.CartIntercept
@Data
public class UserInfoTo {
    private Long userId;
    private String userKey;//一定存在
    /**
     * 是否臨時用戶
     */
    private Boolean tempUser = false;
}
  • 攔截器com.achang.achangmall.cart.intercept.CartIntercept
@Component
public class CartIntercept implements HandlerInterceptor {

    public static ThreadLocal<UserInfoTo> toThreadLocal = new ThreadLocal<>();

    //在目標方法執行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        UserInfoTo userInfoTo = new UserInfoTo();

        HttpSession session = request.getSession();
        MemberResponseVo memberResponseVo = (MemberResponseVo) session.getAttribute(LOGIN_USER);
        if (memberResponseVo != null) {
            //用戶登錄了
            userInfoTo.setUserId(memberResponseVo.getId());
        }
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                //user-key
                String name = cookie.getName();
                if (name.equals(TEMP_USER_COOKIE_NAME)) {
                    userInfoTo.setUserKey(cookie.getValue());
                    //標記為已是臨時用戶
                    userInfoTo.setTempUser(true);
                }
            }
        }
        //如果沒有臨時用戶一定分配一個臨時用戶
        if (StringUtils.isEmpty(userInfoTo.getUserKey())) {
            String uuid = UUID.randomUUID().toString();
            userInfoTo.setUserKey(uuid);
        }

        //目標方法執行之前
        toThreadLocal.set(userInfoTo);
        return true;
    }


    //業務執行之后,分配臨時用戶來瀏覽器保存
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //獲取當前用戶的值
        UserInfoTo userInfoTo = toThreadLocal.get();

        //如果沒有臨時用戶一定保存一個臨時用戶
        if (!userInfoTo.getTempUser()) {
            //創建一個cookie
            Cookie cookie = new Cookie(TEMP_USER_COOKIE_NAME, userInfoTo.getUserKey());
            //擴大作用域
            cookie.setDomain("achangmall.com");
            //設定過期時間
            cookie.setMaxAge(TEMP_USER_COOKIE_TIMEOUT);
            response.addCookie(cookie);
        }
        toThreadLocal.remove();
    }
}
  • com.achang.achangmall.cart.to.UserInfoTo
@Data
public class UserInfoTo {
    private Long userId;
    private String userKey;//一定存在
    /**
     * 是否臨時用戶
     */
    private Boolean tempUser = false;
}
  • com.achang.common.constant.CartConstant
public class CartConstant {
    public final static String TEMP_USER_COOKIE_NAME = "user-key";
    public final static int TEMP_USER_COOKIE_TIMEOUT = 60*60*24*30;
    public final static String CART_PREFIX = "achangmall:cart:";
}
  • com.achang.achangmall.cart.intercept.AchangmallWebConfig配置攔截器,讓其生效
@Configuration
public class AchangmallWebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CartIntercept())//注冊攔截器
            .addPathPatterns("/**");
    }
}
  • achangmall-product/src/main/resources/mapper/product/SkuSaleAttrValueDao.xml
<select id="getSkuSaleAttrValuesAsStringList" resultType="java.lang.String">
    SELECT
    CONCAT( attr_name, ":", attr_value )
    FROM
    pms_sku_sale_attr_value
    WHERE
    sku_id = #{skuId}
</select>
  • com.achang.achangmall.product.service.impl.SkuSaleAttrValueServiceImpl
@Override
public List<String> getSkuSaleAttrValuesAsStringList(Long skuId) {

    SkuSaleAttrValueDao baseMapper = this.baseMapper;
    List<String> stringList = baseMapper.getSkuSaleAttrValuesAsStringList(skuId);

    return stringList;
}
- com.achang.achangmall.product.app.SkuSaleAttrValueController
@GetMapping(value = "/stringList/{skuId}")
public List<String> getSkuSaleAttrValues(@PathVariable("skuId") Long skuId) {
    List<String> stringList = skuSaleAttrValueService.getSkuSaleAttrValuesAsStringList(skuId);
    return stringList;
}
  • com.achang.achangmall.cart.controller.CartController
@Controller
public class CartController {
    @Resource
    private CartService cartService;
    /**
     * 獲取當前用戶的購物車商品項
     * @return
     */
    @GetMapping(value = "/currentUserCartItems")
    @ResponseBody
    public List<CartItemVo> getCurrentCartItems() {

        List<CartItemVo> cartItemVoList = cartService.getUserCartItems();

        return cartItemVoList;
    }

    /**
     * 去購物車頁面的請求
     * 瀏覽器有一個cookie:user-key 標識用戶的身份,一個月過期
     * 如果第一次使用jd的購物車功能,都會給一個臨時的用戶身份:
     * 瀏覽器以后保存,每次訪問都會帶上這個cookie;
     *
     * 登錄:session有
     * 沒登錄:按照cookie里面帶來user-key來做
     * 第一次,如果沒有臨時用戶,自動創建一個臨時用戶
     *
     */
    @GetMapping(value = "/cart.html")
    public String cartListPage(Model model) throws ExecutionException, InterruptedException {
        //快速得到用戶資訊:id,user-key
        // UserInfoTo userInfoTo = CartInterceptor.toThreadLocal.get();
        CartVo cartVo = cartService.getCart();
        model.addAttribute("cart",cartVo);
        return "cartList";
    }

    /**
     * 添加商品到購物車
     * attributes.addFlashAttribute():將資料放在session中,可以在頁面中取出,但是只能取一次
     * attributes.addAttribute():將資料放在url后面
     */
    @GetMapping(value = "/addCartItem")
    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.achangmall.com/addToCartSuccessPage.html";
    }

    /**
     * 跳轉到添加購物車成功頁面
     */
    @GetMapping(value = "/addToCartSuccessPage.html")
    public String addToCartSuccessPage(@RequestParam("skuId") Long skuId,Model model) {
        //重定向到成功頁面,再次查詢購物車資料即可
        CartItemVo cartItemVo = cartService.getCartItem(skuId);
        model.addAttribute("cartItem",cartItemVo);
        return "success";
    }

    /**
     * 商品是否選中
     */
    @GetMapping(value = "/checkItem")
    public String checkItem(@RequestParam(value = "skuId") Long skuId,
                            @RequestParam(value = "checked") Integer checked) {
        cartService.checkItem(skuId,checked);
        return "redirect:http://cart.achangmall.com/cart.html";

    }

    /**
     * 改變商品數量
     */
    @GetMapping(value = "/countItem")
    public String countItem(@RequestParam(value = "skuId") Long skuId,
                            @RequestParam(value = "num") Integer num) {
        cartService.changeItemCount(skuId,num);
        return "redirect:http://cart.achangmall.com/cart.html";
    }

    /**
     * 洗掉商品資訊
     */
    @GetMapping(value = "/deleteItem")
    public String deleteItem(@RequestParam("skuId") Integer skuId) {
        cartService.deleteIdCartInfo(skuId);
        return "redirect:http://cart.achangmall.com/cart.html";
    }
}
  • com.achang.achangmall.cart.service.impl.CartServiceImpl
@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;
    }

    /**
     * 獲取用戶登錄或者未登錄購物車里所有的資料
     */
    @Override
    public CartVo getCart() throws ExecutionException, InterruptedException {

        CartVo cartVo = new CartVo();
        UserInfoTo userInfoTo = CartIntercept.toThreadLocal.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;
    }

    /**
     * 獲取到我們要操作的購物車
     */
    private BoundHashOperations<String, Object, Object> getCartOps() {
        //先得到當前用戶資訊
        UserInfoTo userInfoTo = CartIntercept.toThreadLocal.get();

        String cartKey = "";
        if (userInfoTo.getUserId() != null) {
            //gulimall: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;
    }


    /**
     * 獲取購物車里面的資料
     */
    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);

    }

    /**
     * 修改購物項數量
     */
    @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);
    }

    /**
     * 洗掉購物項
     */
    @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 = CartIntercept.toThreadLocal.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;
    }
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/330272.html

標籤:其他

上一篇:微服務入門(三)反向代理、負載均衡、Nginx、快取、分布式鎖、Redisson、SpringCache

下一篇:DEVOPS架構師 -- 01走進Docker的世界

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more