分佈式電商項目(十)--購物車&用戶權限

購物車操做

業務分析

說明:當用戶點擊購物車按鈕時,應該跳轉到購物車列表頁面.
在這裏插入圖片描述
頁面名稱: cart.jsp
頁面數據: ${cartList}html

建立購物Cart POJO

package com.jt.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;

@TableName("tb_cart")
@Data
@Accessors(chain = true)
public class Cart extends BasePojo{
   @TableId(type = IdType.AUTO)     //主鍵自增
   private Long id; //購物車Id號
   private Long userId; //用戶Id號
   private Long itemId; //商品id號
   private String itemTitle;    //商品標題
   private String itemImage;    //商品圖片信息
   private Long itemPrice;
   private Integer num;
}

建立JT-CART項目

建立項目

在這裏插入圖片描述

添加繼承依賴插件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <artifactId>jt-cart</artifactId>

    <parent>
        <artifactId>jt2007</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <!--3.依賴工具API-->
    <dependencies>
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--4.添加maven插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

購物車項目結構

在這裏插入圖片描述

購物車業務實現

購物車列表展示

編輯CartController

package com.jt.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.service.DubboCartService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/cart")
public class CartController {

    @Reference(check = false)
    private DubboCartService cartService;
    /**
     *  業務描述: 展示購物車列表頁面,同時查詢購物車數據
     *  url: http://www.jt.com/cart/show.html
     *  參數: userId=7L
     *  返回值:  頁面邏輯名稱  cart.jsp
     *  頁面取值:  ${cartList}
     */
    @RequestMapping("/show")
    public String show(Model model){
        Long userId = 7L;   //暫時寫死
        List<Cart> cartList = cartService.findCartListByUserId(userId);
        model.addAttribute("cartList",cartList);
        return "cart";
    }

}

編輯CartService

package com.jt.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.CartMapper;
import com.jt.pojo.Cart;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

@Service(timeout = 3000)
public class DubboCartServiceImpl implements DubboCartService{

    @Autowired
    private CartMapper cartMapper;

    @Override
    public List<Cart> findCartListByUserId(Long userId) {
    QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("user_id", userId);
        return cartMapper.selectList(queryWrapper);
    }
}

頁面效果展示

在這裏插入圖片描述

購物車數量的修改

頁面URL分析

1.頁面URL分析
在這裏插入圖片描述
2.商品的參數 在url地址中 RESTFul風格.
3.頁面JS分析
在這裏插入圖片描述java

編輯CartController

/**
     * 業務描述:
     *  完成購物車數量的修改操做
     *  url地址:  http://www.jt.com/cart/update/num/1474392004/4
     *  參數:     restFul風格
     *  返回值:   void
     */
     @RequestMapping("/update/num/{itemId}/{num}")
     @ResponseBody  //讓ajax程序結束
     public void updateNum(Cart cart){//springmvc 針對restFul提供的功能 名稱和屬性一致

         Long userId = 7L;
         cart.setUserId(userId);
         cartService.updateCartNum(cart);
     }

編輯CartService

/**
     * Sql: update tb_cart set num=#{num},updated=#{updated}
     *      where user_id=#{userId} and item_id = #{itemId}
     * @param cart
     */
    @Override
    public void updateCartNum(Cart cart) {
        Cart cartTemp = new Cart();
        cartTemp.setNum(cart.getNum());
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", cart.getUserId())
                    .eq("item_id", cart.getItemId());
        cartMapper.update(cartTemp,queryWrapper);

    }

購物車刪除

頁面分析

業務邏輯: 當刪除購物車時,應該刪除數據庫記錄,以後將頁面重定向到購物車列表頁面.
在這裏插入圖片描述web

編輯CartController

/**
     * 實現購物車刪除操做
     * 1.url地址: http://www.jt.com/cart/delete/1474392004.html
     * 2.參數:    1474392004 itemId
     * 3.返回值:  String   重定向到列表頁面
     */
     @RequestMapping("/delete/{itemId}")
     public String deleteCart(Cart cart){
         Long userId = 7L;
         cart.setUserId(userId);
         cartService.deleteCart(cart);
         return "redirect:/cart/show.html";
     }

編輯CartService

@Override
    public void deleteCart(Cart cart) { //userId/itemId

        cartMapper.delete(new QueryWrapper<>(cart));
        //根據對象中不爲null的屬性當作where條件.
    }

購物車新增

業務說明

業務說明: 當購物車點擊新增時,須要重定向到購物車列表頁面. 完成購物車"新增""
注意事項: 若是用戶重複添加購物車.則只作購物車數量的更新,若是購物車沒有記錄,則新增數據.
在這裏插入圖片描述
2).參數接收
在這裏插入圖片描述ajax

編輯CartController

/**
* 業務描述:
* 實現購物車的新增
* 1.url:http://www.jt.com/cart/add/562379.html
* 2.參數: num: 1
* itemTitle: 三星 W999 黑色 電信3G手機 雙卡雙待雙通
* itemImage: https://img14.360buyimg.com/n0/jfs/t1/125477/20/11441/43547/5f4e2293E02391add/cf8bee33b3ed4394.jpg
* itemPrice: 4299000
* 3.返回值: String 重定向到購物車頁面
*/
@RequestMapping("/add/{itemId}")
public String addCart(Cart cart){
    Long userId = UserThreadLocal.get().getId();
    cart.setUserId(userId);
    dubboCartService.addCart(cart);
    return "redirect:/cart/show.html";
}

編輯CartService

/**
     * 若是購物車已存在,則更新數量,不然新增.
     * 如何判斷購物車數據是否存在   userId itemId
     *
     * @param cart
     */
    @Override
    public void addCart(Cart cart) {
        //1.查詢購物車信息 userId,itemId
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", cart.getUserId());
        queryWrapper.eq("item_id",cart.getItemId());
        Cart cartDB = cartMapper.selectOne(queryWrapper);
        if(cartDB == null){
            //第一次新增購物車
            cartMapper.insert(cart);
        }else{
            //用戶已經加購,更新數量
            int num = cartDB.getNum() + cart.getNum();
            Cart cartTemp = new Cart();
            cartTemp.setNum(num).setId(cartDB.getId());
            cartMapper.updateById(cartTemp);
        }
    }

權限控制

需求: 若是用戶不登陸,則不容許訪問購物車列表頁面,若是沒有登陸則應該重定向到用戶登陸頁面.redis

SpringMVC調用原理圖

Image.png

攔截器工做原理

在這裏插入圖片描述

編輯攔截器配置

package com.jt.config;

import com.jt.interceptor.UserInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfigurer implements WebMvcConfigurer{
    
    //開啓匹配後綴型配置
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        
        configurer.setUseSuffixPatternMatch(true);
    }

    //配置攔截器策略
    @Autowired
    private UserInterceptor userInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(userInterceptor)
                .addPathPatterns("/cart/**","/order/**");
    }
}

編輯攔截器

說明:經過攔截器動態獲取userIdspring

package com.jt.interceptor;

import com.jt.pojo.User;
import com.jt.util.ObjectMapperUtil;
import com.jt.util.UserThreadLocal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import redis.clients.jedis.JedisCluster;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class UserInterceptor implements HandlerInterceptor {

    @Autowired
    private JedisCluster jedisCluster;

    /**
    * 參數介紹:
    * @param request 用戶請求對象
    * @param response 服務器響應對象
    * @param handler 當前處理器自己
    * @return true:請求放行 false:請求攔截 通常配合重定向使用
    * @throws Exception
    *
    * 若是用戶不登錄則重定向到登錄頁面
    *
    * 判斷用戶是否登陸了?
    * 依據: 1.根據cookie判斷
    * 2.判斷redis
    */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ticket = null;
        //1.判斷cookie中是否有記錄
        Cookie[] cookies = request.getCookies();
        if (cookies !=null && cookies.length>0){
            for (Cookie cookie:cookies) {
                if ("JT_TICKET".equals(cookie.getName())){
                    ticket = cookie.getValue();
                    break;
                }
            }
        }
        //2.判斷cookie的數據是否有效
        if (!StringUtils.isEmpty(ticket)){
            //3.判斷redis
            if (jedisCluster.exists(ticket)){
                String userJSON = jedisCluster.get(ticket);
                User user = ObjectMapperUtil.toObject(userJSON, User.class);
                //4.利用request對象進行數據傳遞 request是最經常使用的方式
                request.setAttribute("JT_USER", user);
                //5.利用本地線程變量傳參(兩種方式均可以,第二種更便捷,可是微服務中須要謹慎,只在同一線程內有效)
                UserThreadLocal.set(user);
                return true; //表示用戶已登錄 放行
            }
        }

        //重定向到用戶登陸頁面
        response.sendRedirect("/user/login.html");
        return false;//表示攔截
    }

    /**
    * 爲了知足業務須要將數據刪除
    */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        request.removeAttribute("JT_USER");
        UserThreadLocal.remove();
    }
}

ThreadLocal介紹

ThreadLocal做用

名稱: 本地線程變量
做用: 能夠在同一個線程內,實現數據的共享.
![Image \[2\].png](/img/bVcHRC0)數據庫

編輯ThreadLocal工具API

package com.jt.util;

import com.jt.pojo.User;

public class UserThreadLocal{
    //在同一線程內有效
    private static ThreadLocal<User> userThreadLocal = new ThreadLocal<>();
    //存值
    public static void set(User user){
        userThreadLocal.set(user);
    }
    //取值
    public static User get(){
        return userThreadLocal.get();
    }
    //刪除
    public static void remove(){
        userThreadLocal.remove();
    }
}

重構User攔截器

![Image \[3\].png](/img/bVcHRDp)apache

動態獲取UserId

![Image \[4\].png](/img/bVcHRDu)服務器

京淘訂單模塊

訂單表設計

![Image \[5\].png](/img/bVcHRDv)cookie

建立訂單項目

建立項目

![Image \[6\].png](/img/bVcHRD0)

添加繼承依賴

<!--繼承父級項目-->
<parent>
<artifactId>jt2007</artifactId>
<groupId>com.jt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<!--依賴工具API-->
<dependencies>
<dependency>
<groupId>com.jt</groupId>
<artifactId>jt-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--添加maven插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

添加POJO

![Image \[7\].png](/img/bVcHREf)
刪除orderItem的主鍵標識
![Image \[8\].png](/img/bVcHREx)

構建jt-order項目

訂單項目代碼結構以下
![Image \[9\].png](/img/bVcHREC)

訂單確認頁面跳轉

url分析

![Image \[10\].png](/img/bVcHREG)

頁面效果展示

![Image \[11\].png](/img/bVcHREV)

關於訂單提交

頁面URL說明

![Image \[12\].png](/img/bVcHRFJ)

請求參數

![Image \[13\].png](/img/bVcHRFL)

訂單成功跳轉

頁面url分析

![Image \[14\].png](/img/bVcHRF6)

頁面效果展示

![Image \[15\].png](/img/bVcHRGd)

編輯OrderController

package com.jt.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.pojo.Order;
import com.jt.service.DubboCartService;
import com.jt.service.DubboOrderService;
import com.jt.util.UserThreadLocal;
import com.jt.vo.SysResult;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
@RequestMapping("/order")
public class OrderController {

    @Reference
    private DubboCartService dubboCartService;
    @Reference
    private DubboOrderService dubboOrderService;

    /**
    * 個人訂單頁面跳轉
    * url:http://www.jt.com/order/myOrder.html
    * 參數:無
    * 返回值: 個人訂單頁面
    * 頁面數據:
    */
    @RequestMapping("/myOrder")
    public String myOrder(){
        return "my-orders";
    }

    /**
    * 完成訂單查詢
    * url:http://www.jt.com/order/success.html?id=order.getUserId()1605862542149
    * 參數: orderId
    * 返回值: 訂單成功頁面
    * 頁面取值:${order.orderId}
    */
    @RequestMapping("/success")
    public String success(String id,Model model){

        Order order = dubboOrderService.findOrderId(id);
        model.addAttribute("order", order);
        return "success";
    }

    /**
    * 訂單提交入庫操做
    * url:http://www.jt.com/order/submit
    * 參數: 整個表單對象 order
    * 返回值:SysResult對象(orderId)
    */
    @RequestMapping("/submit")
    @ResponseBody
    public SysResult saveOrder(Order order){
        Long userId =UserThreadLocal.get().getId();
        order.setUserId(userId);
        String orderId = dubboOrderService.saveOrder(order);
        if ((StringUtils.isEmpty(orderId))){
            return SysResult.fail();
        }else {
            return SysResult.success(orderId);
        }
    }

    /**
    * 跳轉訂單確認頁面
    * url:http://www.jt.com/order/create.html
    * 參數:暫時沒有
    * 返回值: order-cart.jsp
    */
    @RequestMapping("/create")
    public String create(Model model){

        Long userId = UserThreadLocal.get().getId();
        List<Cart> carts = dubboCartService.findCartListByUserId(userId);
        model.addAttribute("carts", carts);
        return "order-cart";
    }

}

編輯OrderService

package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.pojo.Order;
import com.jt.pojo.OrderItem;
import com.jt.pojo.OrderShipping;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.OrderItemMapper;
import com.jt.mapper.OrderMapper;
import com.jt.mapper.OrderShippingMapper;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


@Service(timeout = 3000)
public class OrderServiceImpl implements DubboOrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderShippingMapper orderShippingMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;

    /**
    * 完成三張表的入庫
    * @param order
    * @return
    */
    @Override
    @Transactional //控制事務
    public String saveOrder(Order order) {
        //訂單號:登陸用戶id+當前時間戳
        String orderId = order.getUserId().toString() + System.currentTimeMillis();

        order.setOrderId(orderId).setStatus(1);
        orderMapper.insert(order);

        OrderShipping orderShipping = order.getOrderShipping();
        orderShipping.setOrderId(orderId);
        orderShippingMapper.insert(orderShipping);

        List<OrderItem> orderItems = order.getOrderItems();
        for (OrderItem orderItem:orderItems){
            orderItem.setOrderId(orderId);
            orderItemMapper.insert(orderItem);
        }
        return orderId;
    }

    //須要經過order對象 返回三部分數據
    @Override
    public Order findOrderId(String id) {
        Order order = orderMapper.selectById(id);
        OrderShipping orderShipping = orderShippingMapper.selectById(id);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("order_id", id);
        List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper);
        order.setOrderShipping(orderShipping).setOrderItems(orderItems);
        return order;
    }
}

項目結構圖

![Image \[16\].png](/img/bVcHRGp)

相關文章
相關標籤/搜索