Java十天上手做一个自己的web商城笔记-购物车(12)

 该系列博客主要记录笔者的开发过程,参考B站系列视频:【SpringBoot项目实战完整版】SpringBoot+MyBatis+MySQL电脑商城项目实战_哔哩哔哩_bilibili

所用的一些版本信息:

IDEA开发、JDK1.8版本以上、maven3.61版本以上,springboot,DataGrip管理数据库

购物车页面展示如下:

0 前置准备

0.1 创建购物车表

CREATE TABLE t_cart (
	cid INT AUTO_INCREMENT COMMENT '购物车数据id',
	uid INT NOT NULL COMMENT '用户id',
	pid INT NOT NULL COMMENT '商品id',
	price BIGINT COMMENT '加入时商品单价',
	num INT COMMENT '商品数量',
	created_user VARCHAR(20) COMMENT '创建人',
	created_time DATETIME COMMENT '创建时间',
	modified_user VARCHAR(20) COMMENT '修改人',
	modified_time DATETIME COMMENT '修改时间',
	PRIMARY KEY (cid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

0.2 创建实体类

创建 store\src\main\java\com\cy\store\entity\Cart.java 文件。

public class Cart {
    private Integer cid;
    private Integer uid;
    private Integer pid;
    private Long price;
    private Integer num;

    public Integer getCid() {
        return cid;
    }

    public void setCid(Integer cid) {
        this.cid = cid;
    }

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public Integer getPid() {
        return pid;
    }

    public void setPid(Integer pid) {
        this.pid = pid;
    }

    public Long getPrice() {
        return price;
    }

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

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Cart cart = (Cart) o;
        return Objects.equals(cid, cart.cid) && Objects.equals(uid, cart.uid) && Objects.equals(pid, cart.pid) && Objects.equals(price, cart.price) && Objects.equals(num, cart.num);
    }

    @Override
    public int hashCode() {
        return Objects.hash(cid, uid, pid, price, num);
    }
}

0.3 功能规划

主要有以下两大功能:

1.在商品详情页添加商品

2.展示购物车列表

1 持久层

1.1 规划SQL语句

1.插入语句 insert

2.当前商品已存在,更新num数量,update

3.插入更新执行前,查询数据库该用户是否有这个商品,select

4.查询该用户购物车所有的商品,以及商品对应的详情

1.2 接口和抽象方法

在语句4查询后的给前端显示的购物车信息使用的是VO对象:

    Value Object,值对象。当进行SELECT查询时,结果为多表时,POJO实体类无法接收,构建VO对象去存储查询出来的结果集对应的映射。

创建:store\src\main\java\com\cy\store\vo

package com.cy.store.vo;

import java.io.Serializable;
import java.util.Objects;

/**购物车的VO类*/
public class CartVO implements Serializable {
    private Integer cid;
    private Integer uid;
    private Integer pid;
    private Long price;
    private Integer num;
    private String title;
    private String image;
    private Long realPrice;

    //...... getter ,setter, equals, hashCode 
}

创建 store\src\main\java\com\cy\store\mapper\CartMapper.java 文件

package com.cy.store.mapper;

import com.cy.store.entity.Cart;

import java.util.Date;

public interface CartMapper {
    /**
     * 插入数据
     * @param cart
     * @return
     */
    Integer insert(Cart cart);

    /**
     * 根据cid修改剩余数量num
     * @param cid
     * @param num
     * @param modified_user
     * @param modified_time
     * @return
     */
    Integer updateByCid(Integer cid, Integer num, String modified_user, Date modified_time);

    /**
     * 根据用户和商品id查询购物车
     * @param uid
     * @param pid
     * @return
     */
    Cart findByUidAndPid(Integer uid, Integer pid);

        /**
     * 展示购物车数据查询
     * @param uid
     * @return
     */
    List<CartVO> findByUid(Integer uid);
}

1.3 SQL映射

创建 store\src\main\resources\mapper\CartMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace需要映射到java中的接口,指定路径-->
<mapper namespace="com.cy.store.mapper.CartMapper">
    <resultMap id="CartEntityMap" type="com.cy.store.entity.Cart">
        <id column="cid" property="cid"/>
        <result column="created_user" property="createdUser"/>
        <result column="created_time" property="createdTime"/>
        <result column="modified_user" property="modifiedUser"/>
        <result column="modified_time" property="modifiedTime"/>
    </resultMap>

    <insert id="insert" useGeneratedKeys="true" keyProperty="cid">
        INSERT INTO t_cart (uid, pid, price, num, created_user, created_time, modified_user, modified_time)
        VALUES (#{uid}, #{pid}, #{price}, #{num}, #{createdUser}, #{createdTime}, #{modifiedUser}, #{modifiedTime})
    </insert>

    <update id="updateNumByCid">
        UPDATE
            t_cart
        SET
            num=#{num},
            modified_user=#{modifiedUser},
            modified_time=#{modifiedTime}
        WHERE
            cid=#{cid}
    </update>

    <select id="findByUidAndPid" resultMap="CartEntityMap">
        SELECT
            *
        FROM
            t_cart
        WHERE
            uid=#{uid} AND pid=#{pid}
    </select>

    <select id="findByUid" resultMap="com.cy.store.vo.CartVO">
        SELECT
            cid,
            uid,
            pid,
            t_cart.price,
            t_cart.num,
            t_product.title,
            t_product.price AS realPrice,
            t_product.image
        FROM
            t_cart
                LEFT JOIN t_product ON t_cart.pid = t_product.id
        WHERE
            uid = #{uid}
        ORDER BY
            t_cart.created_time DESC
    </select>
</mapper>

1.4 单元测试

2 业务层

2.1 规划异常

1.插入时异常

2.更新数据异常

3.查询无异常

2.2 接口与抽象方法

新建:store\src\main\java\com\cy\store\service\ICartService.java

package com.cy.store.service;

import com.cy.store.vo.CartVO;

import java.util.List;

/** 购物车的业务层 */
public interface ICartService {
    /**
     * 将商品添加到购物车中
     * @param uid 用户id
     * @param pid 商品id
     * @param num
     * @param username
     */
    void addToCar(Integer uid, Integer pid, Integer num, String username);

    /**
     * 查询购物车显示数据
     * @param uid
     * @return
     */
    List<CartVO> getVOByUid(Integer uid);
}

2.3 实现抽象方法

新建 store\src\main\java\com\cy\store\service\impl\CartServiceImpl.java

package com.cy.store.service.impl;

import com.cy.store.entity.Cart;
import com.cy.store.entity.Product;
import com.cy.store.mapper.CartMapper;
import com.cy.store.mapper.ProductMapper;
import com.cy.store.service.ICartService;
import com.cy.store.service.IProductService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.ProductNotFoundException;
import com.cy.store.service.ex.UpdateException;
import com.cy.store.vo.CartVO;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/** 处理商品数据的业务层实现类 */
@Service
public class CartServiceImpl implements ICartService {
    @Resource
    private CartMapper cartMapper;

    @Resource
    private ProductMapper productMapper;

    @Override
    public void addToCar(Integer uid, Integer pid, Integer num, String username) {
        // 查询当前添加的购物车是否在表中共已存在
        Cart result = cartMapper.findByUidAndPid(uid, pid);
        Date date = new Date();
        if(result == null){
            //商品没有添加过,insert
            Cart cart = new Cart();
            //补全数据
            cart.setUid(uid);
            cart.setPid(pid);
            cart.setNum(num);
            //价格 来自商品数据
            Product product = productMapper.findById(pid);
            cart.setPrice(product.getPrice());

            cart.setCreatedUser(username);
            cart.setCreatedTime(date);
            cart.setModifiedUser(username);
            cart.setModifiedTime(date);
            Integer rows = cartMapper.insert(cart);
            if(rows!=1){
                throw new InsertException("插入时产生未知异常");
            }
        }else{
            //当前商品在购物车中已经存在,update
            Integer reNum = result.getNum()+num;
            Integer rows = cartMapper.updateNumByCid(result.getCid(), reNum, username, new Date());
            if(rows!=1){
                throw new UpdateException("更新时产生未知异常");
            }
        }
    }

    @Override
    public List<CartVO> getVOByUid(Integer uid) {
        return cartMapper.findVOByUid(uid);
    }
}

3 控制层

3.1 处理异常

无新异常梳理

3.2 设计请求

添加购物车

URL:/carts/add_to_cart
请求方式:GET
请求参数:pid, num, session
返回值:JsonResult<Void>

查询购物车显示数据

URL:/carts/
请求方式:GET
请求参数:session
返回值:JsonResult<List<CartVO>>

3.2 处理请求

新建: store\src\main\java\com\cy\store\controller\CartController.java

package com.cy.store.controller;

import com.cy.store.entity.Address;
import com.cy.store.service.ICartService;
import com.cy.store.util.JsonResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.List;


//@Controller
@RestController //该注解等于@Controller + 方法上的@ResponseBody
@RequestMapping("carts")
public class CartController extends BaseController{
    @Resource
    private ICartService cartService;

    @RequestMapping({"add_to_cart"})
    public JsonResult<List<Address>> addToCart(Integer pid, Integer num, HttpSession session){
        cartService.addToCar(getuidFromSession(session), pid, num, getusernameFromSession(session));
        return new JsonResult<>(OK);
    }
}

4 前端页面

在 store\src\main\resources\static\web\product.html 添加请求

			$("#btn-add-to-cart").click(function() {
				$.ajax({
					url: "/carts/add_to_cart",
					type: "POST",
					data: {
						"pid": id,
						"amount": $("#num").val()
					},
					dataType: "JSON",
					success: function(json) {
						if (json.state == 200) {
							alert("增加成功!");
						} else {
							alert("增加失败!" + json.message);
						}
					},
					error: function(xhr) {
						alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
						location.href = "login.html";
					}
				});
			});

在store\src\main\resources\static\web\cart.html中

<!--页脚结束-->
		<script type="text/javascript">
			$(document).ready(function() {
				showCartList();
			});

			function showCartList() {
				$("#cart-list").empty();
				$.ajax({
					url: "/carts",
					type: "GET",
					dataType: "JSON",
					success: function(json) {
						let list = json.data;
						for (let i = 0; i < list.length; i++) {
							let tr = '<tr>'
										+ '<td>'
										+ 	'<input name="cids" value="#{cid}" type="checkbox" class="ckitem" />'
										+ '</td>'
										+ '<td><img src="..#{image}collect.png" class="img-responsive" /></td>'
										+ '<td>#{title}#{msg}</td>'
										+ '<td>¥<span id="price-#{cid}">#{realPrice}</span></td>'
										+ '<td>'
										+ 	'<input type="button" value="-" class="num-btn" onclick="reduceNum(1)" />'
										+ 	'<input id="num-#{cid}" type="text" size="2" readonly="readonly" class="num-text" value="#{num}">'
										+ 	'<input class="num-btn" type="button" value="+" onclick="addNum(#{cid})" />'
										+ '</td>'
										+ '<td>¥<span id="total-price-#{cid}">#{totalPrice}</span></td>'
										+ '<td>'
										+ 	'<input type="button" onclick="delCartItem(this)" class="cart-del btn btn-default btn-xs" value="删除" />'
										+ '</td>'
									 + '</tr>';
							tr = tr.replace(/#{cid}/g, list[i].cid);
							tr = tr.replace(/#{title}/g, list[i].title);
							tr = tr.replace(/#{image}/g, list[i].image);
							tr = tr.replace(/#{realPrice}/g, list[i].realPrice);
							tr = tr.replace(/#{num}/g, list[i].num);
							tr = tr.replace(/#{totalPrice}/g, list[i].realPrice * list[i].num);

							if (list[i].realPrice < list[i].price) {
								tr = tr.replace(/#{msg}/g, "比加入时降价" + (list[i].price - list[i].realPrice) + "元");
							} else {
								tr = tr.replace(/#{msg}/g, "");
							}
							$("#cart-list").append(tr);
						}
					}
				});
			}

			function addNum(cid) {
				$.ajax({
					url: "/carts/" + cid + "/num/add",
					type: "POST",
					dataType: "JSON",
					success: function(json) {
						if (json.state == 200) {
							// showCartList();
							$("#num-" + cid).val(json.data);
							let price = $("#price-" + cid).html();
							let totalPrice = price * json.data;
							$("#total-price-" + cid).html(totalPrice);
						} else {
							alert("增加商品数量失败!" + json.message);
						}
					},
					error: function(xhr) {
						alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
						location.href = "login.html";
					}
				});
			}

			/*
			$(function() {
				//返回链接
				$(".link-account").click(function() {
					location.href = "orderConfirm.html";
				});
			});
			*/
		</script>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值