Lesson 19 京淘项目 微服务--Dubbo框架---用户单点登录注册(SSO)---购物车(CART)---前端页面(WEB)---后台管理(MANAGE)

1 用户模块

1.1 用户登出操作(SSO)

要达成的效果就是:
用户在jt-web主页面点击了退出之后,跳转回jt-web主页面,并且不再显示用户的名称。
隐含的过程是:
浏览器:要删除用户上次登录时的cookie信息(即作废ticket);
服务器:要删除用户上次登录存入的登录的redis缓存信息(因为redis中的记录是根据ticket来记录的,ticket的value就是redis中的key。ticket作废了,redis中这条数据也就作废了)

1.1.1 当前情况分析

点击了“退出”后,浏览器地址栏中的地址变成了:
在这里插入图片描述
可见,这是一个同域请求。
所以需要在自家的jt-web的controller中写一个方法,来接收

1.1.2 编辑jt-web中的UserController

去处理登出请求。
有两种方式:

 /**
     * 方式1:用最原始的手敲一行行代码的方式 (没用用Cookie工具API)
     * 用户在点击“退出”时,要重定向到jt-web的首页,并删除这个用户的cookie和redis中这个用户的数据
     * 步骤:通过cookie获取ticket信息。根据cookie中的cookie的name,获取到这个name对应的value(就是ticket的信息)。
     * 这个ticket就是redis中的key
     * url:http://www.jt.com/user/logout.html
     * 返回值:重定向到jt-web首页
     * 同时要做的:删除用户cookie,并在redis中删除这个用户的数据
     * 思路:要先获取到他的cookie中的key和value(value就是ticket)
     */
    @RequestMapping("/logout")
    public String logout(HttpServletRequest request,HttpServletResponse response){

        //1.request.getCookies()获取到的目前还存活的所有的cookies。
        Cookie[] cookies = request.getCookies();

        //2.校验Cookie[] 中是否有数据(是否为null)
        //cookies不是空的,并且 cookies中确实存的是cookie的信息
        if(cookies !=null && cookies.length>0){
            //3 从cookies中获取到当前这个用户的cookie
            for (Cookie cookie: cookies ) {
                if("JT_TICKET".equals(cookie.getName())){  //在之前用户注册时,服务器把cookie给用户时,就规定了,这个cookie的名字是JT_TICKET

                    //4 删除redis中这个用户的登录的数据
                    String ticket = cookie.getValue();
                    //打个桩===看看ticket中是什么样的数据
                    //System.out.println(ticket); //8b80e3adaaeb44b896e2ffbc50540026
                    //根据ticket的值,就是redis中的key,去删除redis中的数据
                    jedisCluster.del(ticket);

                    //5 删除cookie
                    cookie.setMaxAge(0);
                    //由于通过request对象获取的cookie中只有name和value,而cookie的其他属性值(path和domain需要自己赋值)
                    cookie.setPath("/");  //cookie要设置成与用户原来的cookie中的这个属性值一致
                    cookie.setDomain("jt.com"); //cookie要设置成与用户原来的cook
                    response.addCookie(cookie);

                    //当cookies都被遍历完了,就break跳出
                    break;
                }
            }
        }
        return "redirect:/";  //重定向到jt-web的首页
    }
/**
     * 方式2:通过工具API  见1.1.2.1
     * 用户在点击“退出”时,要重定向到jt-web的首页,并删除这个用户的cookie和redis中这个用户的数据
     * 步骤:通过cookie获取ticket信息。根据cookie中的cookie的name,获取到这个name对应的value(就是ticket的信息)。
     * 这个ticket就是redis中的key
     * url:http://www.jt.com/user/logout.html
     * 返回值:重定向到jt-web首页
     * 同时要做的:删除用户cookie,并在redis中删除这个用户的数据
     * 思路:要先获取到他的cookie中的key(就是ticket)和value
     */
    @RequestMapping("/logout")
    public String logout(HttpServletRequest request,HttpServletResponse response){
        //1.通过工具API获取cookie的值,也就是ticket
        String ticket = CookieUtil.getCookieValueByName("JT_TICKET",request);
        //2.判断ticket中是否有值
        if(!StringUtils.isEmpty(ticket)){
            //3.根据ticket,删除redis
            jedisCluster.del(ticket);
            //4.删除cookie
            CookieUtil.deleteCookie("JT_TICKET","/","jt.com",response);
        }
        //5.跳转到jt-web首页
        return "redirect:/";
    }

既然要用工具API,就我就得先写一个工具API

1.1.2.1 自编一个关于操作cookie的工具util----CookieUtil

写在jt-common的util中
注意,这个util中包含:
1.根据cookie的名称 返回cookie对象
2.根据cookie的名称 返回value的值
3.新增cookie的方法
4.删除cookie的方法

public class CookieUtil {

    /**
     * 该工具API的主要作用:
     * 1.根据cookie的名称 返回cookie对象
     * 2.根据cookie的名称 返回value的值
     * 3.新增cookie的方法
     * 4.删除cookie的方法
     */

    //1.根据cookie的name 获取这个cookie对象  (在调用这个方法时,我得事先知道cookie的name,比如JT_TICKET)
    public static Cookie getCookieByName(String cookieName,HttpServletRequest request){
        //一个网页中可能含有很多个cookie,它们都可以通过request对象获取到
        Cookie[] cookies = request.getCookies();
        //判断一个数组是否有值的标准写法:先判断它是不是null,并且 ,这个数组的长度要>0
        if(cookies !=null && cookies.length>0){
            for(Cookie   cookie  :  cookies){
                //从这一堆cookie中挑选出跟这个用户的cookie的name匹配的那个cookie,上交这个cookie
                //如果方法参数中的name与cookie的真实的name相同
                if(cookieName.equalsIgnoreCase(cookie.getName())){
                    //就把这个cookie上交给调用getCookieByName()这个方法的对象
                    return cookie;
                }//否则,啥也不做
            }
        }
        //如果cookie数组是空的,就返回null
        return null;
    }

    //2.根据cookie的name 获取这个cookie的value
    public static String getCookieValueByName(String cookieName,HttpServletRequest request){
       //调用上面那个方法 获取cookie对象
        Cookie cookie = getCookieByName(cookieName,request);

        //cookie为空吗? 如果是null,就返回null。如果不为null,就返回cookie的value
        return (cookie==null)?null:cookie.getValue();
    }


    //3.addCookie()的作用就是 new出一个新的空的cookie
    public static void addCookie(String cookieName, String cookieValue, String path, String domain, int maxAge, HttpServletResponse response){
        //一个cookie身上最常用的5个属性:name,value,path,domain,maxAge
        Cookie cookie = new Cookie(cookieName,cookieValue);
        cookie.setPath(path);
        cookie.setDomain(domain);
        cookie.setMaxAge(maxAge);
        //通过response对象,将cookie返回给浏览器
        response.addCookie(cookie);
    }

    //4.deleteCookie()的作用:删除Cookie
    public static void deleteCookie(String cookieName,String path,String domain,HttpServletResponse response){
        //删除的思路就是:再新建一个cookie。并且把maxAge设置为0,value设置为空串,其余3项的值与原cookie保持一致。否则某些浏览器可能不能成功删除。
        Cookie cookie = new Cookie(cookieName, "");
        cookie.setPath(path);
        cookie.setDomain(domain);
        cookie.setMaxAge(0);  //!!!!!
        //cookie的maxAge如果为-1,意思是关闭浏览器后这个cookie就失效了
        //通过response对象,将cookie返回给浏览器
        response.addCookie(cookie);
    }

}

2 商品详情页的展现(MANAGE)

目的:用户在jt-web的页面上点击一个商品,能展现出这个商品的详情信息
是jt-web服务器向jt-manage服务器请求数据信息,又是RPC远程调用。所以要将jt-manage配置上dubbo框架。
在这里插入图片描述
跳转到的页面url
在这里插入图片描述
而商品的详情信息要去jt-manage服务器中请求获取。
所以要将jt-manage改造为Dubbo项目

2.1 将jt-manage改造为Dubbo项目

2.1.1 在jt-manage中新增DubboItemServiceImpl实现类

在jt-manage中新增DubboItemServiceImpl实现类,用来实现展现商品详情数据的业务逻辑。
在这里插入图片描述

2.1.2 修改jt-manage的yml文件

只需要在最下面添加上dubbo框架的配置即可
在这里插入图片描述

2.2 实现商品详情的展现

2.2.1 页面请求url分析

说明:当用户点击某个商品时,需要跳转到商品的详情页面中.根据itemId展现商品信息.并且在item.jsp中展现数据.

在这里插入图片描述

2.2.2 前台页面是怎么取值的?

商品Item的pojo身上有title和sellpoint这两个属性
在这里插入图片描述
展现的就是这的数据
在这里插入图片描述
别的item的信息以此类推

2.2.3 编辑ItemController

由请求的url可知,这个controller要写在jt-web中。
所以在jt-web中的controller文件夹中,新增一个ItemController类,里面写一个方法,用来根据itemId展现这个item的具体信息

@Controller  //由于要返回页面 所以这里要写@Controller
public class ItemController {

    @Reference(check = false,timeout = 3000) //A发送请求后,等B服务器3秒钟,如果B还不接收请求,A再回去
    private DubboItemService dubboItemService;

    /** 在jt-web主页 点击一个商品后,展现这个商品的介绍页面
     * 根据itemId查询商品信息:1、商品信息  2、商品详情信息
     * url地址:http://www.jt.com/items/562379.html
     * 参数:是从url中传过来的,restful风格
     * 返回值:页面 item.jsp
     * 前端js是怎么取值的:${item.title}   ${itemDesc.itemDesc},它就可以从域中取到值了
     */
    @RequestMapping("/items/{itemId}")
    public String findItemById(@PathVariable Long itemId, Model model){
        //查询到商品信息item
        Item item = dubboItemService.findItemById(itemId);
        //查询到商品详情信息itemDesc
        ItemDesc itemDesc = dubboItemService.findItemDescById(itemId);
        //把商品信息item放到作用域中,来让前端获取 (其实是放到item.jsp中的指定位置)
        model.addAttribute("item",item);
        //把商品详情信息itemDesc放到域中,来让前端获取(其实是放到item.jsp中的指定位置)
        model.addAttribute("itemDesc",itemDesc);
        //返回有了数据的item.jsp  
        return "item"; 
    }

}

2.2.4 编辑ItemService

在jt-common的service中新建一个DubboItemService接口,用来生成上面controller中的两个方法

package com.jt.service;

import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;

//商品
public interface DubboItemService {
    Item findItemById(Long itemId);

    ItemDesc findItemDescById(Long itemId);
}

2.2.5 编辑DubboItemServiceImpl

在jt-manage中的web文件夹下,新建一个service文件夹,用来存放DubboItemServiceImpl.java

@Service  //dubbo框架的@Service注解
public class DubboItemServiceImpl implements DubboItemService {

    @Autowired
    private ItemMapper itemMapper;  //商品信息

    @Autowired
    private ItemDescMapper itemDescMapper;  //商品详情信息

    /**
     * 在jt-web主页点击一个商品后,根据itemId,查询这个商品的item信息和itemDesc信息
     * @param itemId
     * @return item信息  itemDesc信息
     */
    @Override
    public Item findItemById(Long itemId) {
        //根据itemId查询item信息
        return itemMapper.selectById(itemId);
    }

    @Override
    public ItemDesc findItemDescById(Long itemId) {
        //根据itemId查询itemDesc信息
        //由于都是同一个商品,所以它的itemDesc的id和itemId是一样的
        return itemDescMapper.selectById(itemId);
    }
}

2.2.6 展现效果

在这里插入图片描述

3 购物车模块业务的实现(CART)

在这里插入图片描述

3.1 创建jt-cart项目

3.1.1 新建项目

在这里插入图片描述

3.1.2 添加基础/依赖/插件

<?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>jt</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    
    <!--添加依赖项-->
    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

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

</project>

3.1.3 编辑jt-cart的pojo

在jt-common的pojo文件夹中,新建一个Cart.java

@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; //购买数量

}

3.1.4 jt-cart项目的文件结构

在这里插入图片描述

3.1.5 编辑jt-cart的yml文件

tomcat服务器端口号:8094
dubbo的服务名称:provider-cart
dubbo的服务端口号:20881

server:
  port: 8094
  servlet:
    context-path: /
spring:
  datasource:
    #引入druid数据源
    #type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

  #提供了MVC的支持
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp

#mybatis-plush配置
mybatis-plus:
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mybatis/mappers/*.xml
  configuration:
    map-underscore-to-camel-case: true

logging:
  level: 
    com.jt.mapper: debug

#关于Dubbo配置
dubbo:
  scan:
    basePackages: com.jt    #指定dubbo的包路径
  application:              #应用名称
    name: provider-cart     #一个接口对应一个服务名称
  registry:                 #zk集群 主机中的信息与从机中的信息一致的 从zk中获取数据的时候链接的从机 主机的作用就是监控集群
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
  protocol:  #指定协议
    name: dubbo  #使用dubbo协议(tcp-ip)  web-controller直接调用sso-Service
    port: 20881  #每一个服务都有自己特定的端口 不能重复.

3.1.6 修改IDEA在启动启动类时的名称

在这里插入图片描述

3.2 购物车页面的展现

3.2.1 页面分析

1.分析客户端请求的url
在这里插入图片描述
2.业务说明
用户只能看自己的购物车信息,所以用户得先登录,才能进行购物车的操作。
当用户登录了后,就能获取到userId,当他点击“加入购物车”按钮后,就应该跳转到他的购物车页面。
根据userId查询这个用户的购物车数据信息,然后在cart.jsp中展现这个用户的购物车中的信息。
由于购物车中可以放这个用户想买的很多很多item,不止一条信息。
所以根据userId查到的是一个cartList集合
在这里插入图片描述

3.2.2 编辑CartController

由于 “想要 跳转到 购物车” 这个请求是 在jt-web页面中发过来的。所以CartController.java要写在jt-web的controller中
在这里插入图片描述
在jt-web的controller中增加“CartController”

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

    @Reference(check = false,timeout = 3000)
    private DubboCartService cartService;

    /**
     * 1.购物车列表数据展现
     * url地址: http://www.jt.com/cart/show.html
     * 参数:    暂时没有
     * 返回值:  页面逻辑名称  cart.jsp
     * 页面取值: ${cartList}
     * 应该将数据添加到域对象中 Request域  model工具API操作request对象
     *
     */
    @RequestMapping("/show")
    public String show(Model model){
        //1.暂时将userId写死    7L
        Long userId = 7L;
        List<Cart> cartList = cartService.findCartListByUserId(userId);
        model.addAttribute("cartList",cartList);
        return "cart";
    }
}

3.2.3 编辑DubboCartService接口

通过controller中我自定义的方法中的提示,IDEA会帮我在DubboCartService接口中新建findCartListByUserId()方法
在这里插入图片描述

3.2.4 编辑DubboCartServiceImpl

由于购物车页面到底展现啥,是jt-cart的活,所以要在jt-cart的service文件夹下新建DubboCartServiceImpl.java

@Service
public class DubboCartServiceImpl implements DubboCartService{

    @Autowired
    private CartMapper cartMapper;

    /**
     * 根据jt-web的controller中传过来的用户的userId,查询他的购物车的信息
     */
    @Override
    public List<Cart> findCartListByUserId(Long userId) {
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId);
        List<Cart> cartList = cartMapper.selectList(queryWrapper);
        return cartList;
    }
}

3.2.5 页面效果展现

在这里插入图片描述

3.3 实现购物车中修改商品数量的操作,并且总计的费用同时变化

在这里插入图片描述
业务要求:
点击“-”或者“+”,商品的数量要随之变化。
并且总价要随之动态变化。

3.3.1 页面分析

在这里插入图片描述

3.3.2 页面JS分析

在这里插入图片描述

3.3.3 编辑CartController

在jt-web的controller中添加“修改购物车中商品数量”的方法updateCartNum()

 /**
     * 在购物车中,点击“+”“-”修改购物车中这个商品的数量
     * url:http://www.jt.com/cart/update/num/562379/10   (当我把商品数量想改成  10 时,就显示这个)
     * 参数: itemId/num  (比如:562379/10)
     * 返回值类型: void
     */
    @RequestMapping("/update/num/{itemId}/{num}")
    @ResponseBody   //这个注解的作用是,将返回值对象转化为json串
                    //为的是满足前端调用的要求
                    //而前端是靠发ajax请求,所以这个注解也可以看做是ajax请求的结束
    public void updateCartNum(Cart cart){ //restful风格中,如果{ }中的名字 与 对象的属性名称一致,则可以自动赋值
        //1.获取itemId
        Long userId = 7L;  //暂时写死
        cart.setUserId(userId); //将7号用户的userId 放进cart对象中,就表明我要修改的是7号的这人的购物车信息、
         /**
         * cart身上共有7个属性,传过来的这个cart身上哪些属性有值?哪些属性为null?
         * cart.getUserId 为 7L   在上边那句代码中传过来的
         * cart.getItemId 为 562379  是因为用户在点击“+”“-”时,肯定操作的是1个item,这个itemId就得到了
         * cart.getNum  有值,改之前 是 几就是几
         * 其余的都为null
         */
        dubboCartService.updateCartNum(cart);
    }

3.3.4 编辑DubboCartService接口

jt-common中的DubboCartService接口中又多了一个方法
在这里插入图片描述

3.3.5 编辑DubboCartServiceImpl实现类

在jt-cart的service中的DubboCartServiceImpl实现类中,实现上面接口中多出来的接口方法:
注意:点击“+”“-”修改数量这个操作,需求是只修改cart的num属性的值,别的属性要是有值的话,不要去变。
而如果直接传controller中的cart对象进来,因为人家身上有4个属性都有值,修改的就太多了,并且itemId和userId,它俩的值在修改前和修改后,值是一样的,那岂不是做了无用功。
uodated时间的修改我已经写了一个MyMetaObjectHandler.java方法,可以实现自动修改。
所以我只需要修改num这个属性的值即可。
所以我就要new出一个cartTemp对象,让它只有num这个属性有值。

 /**
     * 根据cart对象身上的信息,去修改他购物车中,这个商品的数量
     * 注意:要新new一个cartTemp对象,让其身上只有num属性有值。
     */
    @Override
    public void updateCartNum(Cart cart) {
        //构建一个购物车,把传过来的购物车的信息放到这个新车上

        //传过来的cart对象身上的哪些属性有值,哪些为空???
//        System.out.println("cartId==="+cart.getId());  //null
//        System.out.println("userId==="+cart.getUserId());  //7
//        System.out.println("itemId==="+cart.getItemId());  //562379
//        System.out.println("itemTitle=="+cart.getItemTitle());//null
//        System.out.println("itemImage==="+cart.getItemImage());//null
//        System.out.println("itemPrice=="+cart.getItemPrice());//null
//        System.out.println("itemNum=="+cart.getNum()); //9
        Cart cartTemp = new Cart();
        cartTemp.setNum(cart.getNum()); //cartTemp身上 只有num这一个属性有值
        UpdateWrapper<Cart> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id",cart.getUserId());
        updateWrapper.eq("item_id",cart.getItemId());
        /**
         * 为什么要new一个cartTemp传进来,而不用原来的cart?
         * 1.当我用原来的cart传进来时,update的sql语句如下:
         * UPDATE tb_cart SET item_id=?,num=?,user_id=?,updated=?  WHERE (user_id=? AND item_id=?)
         * 这是因为cart身上有4个属性有值,所以修改时 要这4个属性的值都要修改。
         * 2.当我再new一个cartTemp出来,只让它身上的num属性有值时,update的sql语句如下:
         * UPDATE tb_cart SET num=?,updated=?  WHERE (user_id=? AND item_id=?)
         * (由于我之前写了一个时间自动填充的方法:jt-common中MyMetaObjectHandler.java,所以这个updated不算)
         * 可见,这种情况下,我只修改了购物车中的num。
         * 而实际上,我需要的效果就是:在购物车页面,点击“+”“-”只修改num即可,与第2种情况是吻合的。
         * 我只想修改num,不需要修改itemId和userId。
         * 并且第一种情况下,itemId和userId的值在修改前和修改后都是一样,没修改一丁点,岂不是很多余的操作。
         * 所以这里要传的就是(身上只有num这一个属性有值的)cartTemp对象
         */
        cartMapper.update(cartTemp,updateWrapper);

    }

3.3.6 效果验证

我将下面商品的数量由8 增加到 10,总价也跟着变了
在这里插入图片描述
在这里插入图片描述

3.4 购物车中商品的删除

目的:在购物车页面,点击 商品后面的删除,能将这个商品的信息,从购物车中删除。
并且重定向到购物车列表页面。
在这里插入图片描述

3.4.1 页面请求的url分析

根据userId(用户登录了就有)和itemId(购物车页面有),这两个属性作为where条件,删除购物车中此条item数据
在这里插入图片描述

3.4.2 编辑CartController

由上图可知,这个请求是jt-web中的请求,所以还是要往jt-web中的controller中添加方法

/**
     * 在购物车页面,点击“删除”后,删除此条商品的信息,并重定向到购物车页面
     * url:http://www.jt.com/cart/delete/562379.html
     * 参数:  562379   (就是我这次选的商品的itemId)
     * 返回值: 跳转到购物车列表页面
     */
    @RequestMapping("/delete/{itemId}")
    public String deleteCart(Cart cart){

        Long userId = 7L;
        cart.setUserId(userId); //规定了这是7号人物的 他那台购物车
        dubboCartService.deleteCart(cart); //这个cart只有userId和itemId这两个属性有值
        return "redirect:/cart/show.html"; //参考上面的展现页面的方法

    }

3.4.3 编辑DubboCartService

通过CartController中的提示,就可以在jt-common中的DubboCartService接口中新增出deleteCart()接口方法
在这里插入图片描述

3.4.4 编辑DubboCartServiceImpl

在jt-cart中,DubboCartServiceImpl去实现上面的接口方法
cart对象身上只有userId和itemId有值,就根据这两个条件去删除购物车中的这条信息

    /**
     * 在购物车页面中,点击“删除”,删除此条商品信息
     * @param cart
     */
    @Override
    public void deleteCart(Cart cart) {  //这个cart只有userId和itemId这两个属性有值
//        //方法1:麻烦写法:
//        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("item_id",cart.getItemId());
//        queryWrapper.eq("user_id",cart.getUserId());
//        cartMapper.delete(queryWrapper);

        //方法2:简单写法  根据对象中不为null的元素,充当where条件
        cartMapper.delete(new QueryWrapper<>(cart));
    }

3.5 往购物车中添加商品

目的:
用户在商品详情页点击“加入购物车”后,有2种情况:
1.这个商品之前已经在购物车里有了,那么这次用户想要再增加几个,就在购物车中这个商品的数量上新增就可以,并且重定向到购物车列表页面.
2.这个商品在购物车里没有,就将这个商品的信息,按照购物车信息展现的形式,添加到购物车中。(其实后台的操作是,将用户提交的数据以购物车商品的pojo的形式存到tb_cart表中)并且重定向到购物车列表页面.
在这里插入图片描述
要是实现这个功能,首先要实现商品详情页面的展现。这个功能在上面“2 商品详情页的展现”中已经实现了。
开发者工具中显示:
在这里插入图片描述
在这里插入图片描述
还有一个需要注意的点:
每个商品一般都有多张图片:
在这里插入图片描述
点击“加入购物车”后,购物车页面只会显示一个简图:
在这里插入图片描述
那就是介绍页的第一个图

<form id="cartForm" method="post">
	<input class="text" id="buy-num" name="num" value="1" onkeyup="setAmount.modify('#buy-num');"/>
	<input type="hidden" class="text"  name="itemTitle" value="${item.title }"/>
    <input type="hidden" class="text" name="itemImage" value="${item.images[0]}"/>
	<input type="hidden" class="text" name="itemPrice" value="${item.price}"/>
</form>

3.5.1 编辑CartController

由上面的请求的url可知,这个CartController应该是在jt-web服务器中
所以在jt-web的controller中新增方法

    /**
     * 在商品详情页面,点击“加入购物车”,将用户提交的数据(这个商品,和商品的数量)插入到tb_cart表中,实现购物车页面呈现该商品的信息
     * 注意事项:
     *   如果用户提交的这个商品,购物车中已经有了,就把购物车中的这个商品的数量更新。
     * url:http://www.jt.com/cart/add/562379.html
     * 参数:form表单提交的数据   和 itemId
     * 返回值:重定向到更新后的购物车页面
     */
    @RequestMapping("/add/{itemId}")
    public String addCart(Cart cart){
        //暂时先将将登陆的用户固定死  7号用户
        Long userId = 7L;
        //addCart方法的参数是cart,是为了简化代码
        //用户在点击“加入购物车”后,通过form表单提交了很多数据,从中提取一些就能封装成一个Cart对象
        //将用户的userId插入到这个cart对象中
        cart.setUserId(userId);
        //将这个封装了新数据的cart对象通过addCart()方法,加入到购物车页面中。(至于是新增一条数据,还是在原有数据上增加num,就要在serviceImpl中进行判断处理了)
        dubboCartService.addCart(cart);
        //重定向到购物车页面
        return "redirect:/cart/show.html";
    }

3.5.2 编辑DubboCartService

在jt-common的DubboCartService接口中,新建接口方法
在这里插入图片描述

3.5.3 编辑DubboCartServiceImpl

在jt-cart的DubboCartServiceImpl中添加方法addCart()

   /**
     * 在商品详情页面,点击“加入购物车”,将用户提交的数据(这个商品,和商品的数量)插入到tb_cart表中,实现购物车页面呈现该商品的信息
     * 思路:
     *      查询数据库,根据user_id和item_id这两个条件 去查tb_cart表,看表里是不是已经有这条数据了。
     *      如果有,则只需要 将购物页面该商品的数量 增加。 如果没有,则把这条信息写入到tb_cart表中,即在购物车页面新增这条信息。
     */
    @Override
    public void addCart(Cart cart) {
        //第2步:构造查询的条件,要要满足,同时匹配上userId和itemId
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",cart.getUserId());
        queryWrapper.eq("item_id",cart.getItemId());
        //第1步:让cartMapper对象去查表,根据userId和itemId,查查看有没有满足条件的这个Cart对象(取名为cartDB)
        Cart cartDB = cartMapper.selectOne(queryWrapper);
        //第3步:进行判断,查询出的结果是否有值
        if(cartDB == null){
            //情况1:tb_cart表中没有这条数据,需要新增,到购物车页面
            //cart对象的7个属性都能有值:id没有传值,但它是主键,入库后就有了;userId,只要用户登录了,就有了;itemId,用户点击“加入购物车”时就有了;
            //itemTitle,itemImage,itemPrice,num  这4个都是用户在点击“加入购物车”时,通过表单提交的
            //所以可以放心地把cart对象传进去,入库
            cartMapper.insert(cart);
        }else {
            //情况2:购物车页面已有这条数据了,只需增加num 。
            //最后商品的总数量 = 我这次要买的 + 之前我已经加入到购物车的(即我之前已经写入tb_cart表中的)
            int num = cart.getNum() + cartDB.getNum();

            //这种情况下,我只需将总的num更新进数据库就行了
            //方式1.用MP写的话,代码很多====不推荐
//            Cart cartTemp = new Cart();
//            cartTemp.setNum(num);
//            UpdateWrapper<Cart> updateWrapper = new UpdateWrapper<>();
//            updateWrapper.eq("user_id",cart.getUserId());
//            updateWrapper.eq("item_id",cart.getItemId());
//            cartMapper.update(cartTemp,updateWrapper);
//            //方式2.手写sql
            //1.将新的商品的总数传入cartDB对象   数据库中购物车的数据都是这个cartDB身上的
            cartDB.setNum(num).setUpdated(new Date());
            //2.updateCartNum()方法是自定义的,
            //由于sql语句为update tb_cart set num=#{num},updated=now() where user_id=#{userId} and item_id=#{itemId}
            //可知需要num,updated,userId,itemId这几个属性的值,而cartDB身上,这几个属性正好都有值,所以直接传cartDB对象即可
            cartMapper.updateCartNum(cartDB);

        }

    }
3.5.3.1 如果是用方法2,还需编辑CartMapper

在jt-cart的CartMapper中添加方法,并填写sql语句

package com.jt.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jt.pojo.Cart;
import org.apache.ibatis.annotations.Update;

public interface CartMapper extends BaseMapper<Cart> {

    @Update("update tb_cart set num=#{num},updated=now() where user_id=#{userId} and item_id=#{itemId}")
    void updateCartNum(Cart cartDB);
}

3.5.4 效果验证

之前购物车中没有这个商品,我想先加入1台
在这里插入图片描述
点击“加入购物车”后,购物车页面多了这个商品的信息:
在这里插入图片描述
当我在商品详情页面 再选择5台 点击“加入购物车”后,
在这里插入图片描述
购物车中由于之前已经有这个商品了,所以只把这个商品的num加了5
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值