Mall business---shopping cart

foreword

Just a simple thought reminder, the specific business logic implementation is to write the interface, there is nothing to say.

1. Requirements description

  • 1. Users can add items to the shopping cart in the login state [user shopping cart/online shopping cart]
  • 2. Users can add items to the shopping cart without logging in [tourist shopping cart/offline shopping cart/temporary shopping cart]
  • 3. Users can use the shopping cart to settle and place an order together
  • 4. Add items to the shopping cart
  • 5. Users can query their own shopping cart
  • 6. The user can modify the quantity of purchased items in the shopping cart.
  • 7. Users can delete items in the shopping cart.
  • 8. Select or not select the product
  • 9. Display product discount information in the shopping cart
  • 10. Prompt the price change of the shopping cart

2. Process analysis

2.1 Add new product: determine whether to log in

Yes: add the product to the background Redis, and use the unique identifier of the user as the key.
No: add the product to the background redis, and use the randomly generated user-key as the key.

2.2 Query the shopping cart list: determine whether to log in

  • No: directly query the data in redis according to the user-key and display it
  • Yes: If you have logged in, you need to check whether there is data in redis according to the user-key.
    • Yes: It needs to be submitted to the background to add to redis, merge the data, and then query.
    • No: directly go to the background to query redis, and then return.

2.3 Determine whether to log in

Here, an interceptor is used for preprocessing. If the user is not logged in, a value is randomly assigned.

    /***
     * 目标方法执行之前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @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;
    }

3. Temporary shopping cart

    /**
     * 获取到我们要操作的购物车
     * @return
     */
    private BoundHashOperations<String, Object, Object> getCartOps() {
    
    
        //先得到当前用户信息
        UserInfoTo userInfoTo = CartInterceptor.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;
    }

4. Log in to the shopping cart

    /**
     * 获取用户登录或者未登录购物车里所有的数据
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    @Override
    public CartVo getCart() throws ExecutionException, InterruptedException {
    
    

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

5. Add items to the shopping cart

Here the data is directly stored in redis, which involves remote service calls.

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

6. Tips

6.1 Question 1

If the call to the remote service fails, the page will also report an error. You need to manually write the sql statement. Before the product is added to the shopping cart, determine whether the product already exists in the shopping cart.

6.3 Question 2

When using interceptors, due to different versions. The writing is different.

        WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
            @Override
            public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
                R error = R.error(BizCodeEnume.TO_MANY_REQUEST.getCode(), BizCodeEnume.TO_MANY_REQUEST.getMsg());
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json");
                response.getWriter().write(JSON.toJSONString(error));

            }
        });

If you want to continue using this method, you need to add new dependencies to the pom file

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>

6.4 Question 3

About how to store the information of the product in redis

Redis has 5 different data structures, which one is more appropriate to choose here? Map<String, List>

  • First of all, different users should have independent shopping carts, so the shopping cart should be stored with the user as the key, and the Value is all the shopping cart information of the user. So it seems that the basic k-vstructure is fine.
  • However, when we add, delete, and modify items in the shopping cart, we basically need to judge based on the item id. In order to facilitate post-processing, our shopping cart should also be structured. The key is the item id, and the value is the item k-v. shopping cart information

To sum up, our shopping cart structure is a two-layer Map:Map<String,Map<String,String>>

  • The first layer of Map, Key is the user id
  • The second layer of Map, Key is the product id in the shopping cart, and the value is the shopping item data

7. The effect achieved

7.1 Not logged in

7.1.1 Adding items to the shopping cart

insert image description here
insert image description here

7.1.2 View shopping cart

insert image description here

7.1.3 View data stored in redis

insert image description here

7.2 Login status

7.1 View shopping cart

insert image description here
insert image description here

7.2 View reids data

insert image description here

Guess you like

Origin blog.csdn.net/weixin_43304253/article/details/130175863