day10-功能实现09

家居网购项目实现09

以下皆为部分代码,详见 https://github.com/liyuelian/furniture_mall.git

21.功能20-修改购物车

21.1需求分析/图解

image-20221226211829037
  1. 进入购物车页面,可以修改购买数量
  2. 更新该商品的金额
  3. 更新购物车商品数量和总金额

21.2思路分析

21.3代码实现

21.3.1entity层

Cart.java

增加方法updateCount()

/**
 * 根据家居id和count,修改指定cartItem的数量和总价
 *
 * @param id    家居id
 * @param count 指定id的家居的数量
 */
public void updateCount(int id, int count) {
    //获取指定的cartItem
    CartItem item = items.get(id);
    if (null != item) {//如果cartItem不为空
        //更新数量
        item.setCount(count);
        //某家居总价 = 单价 * 数量(为了安全使用get方法获取数量count)
        item.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getCount())));
    }
}

21.3.2web层

CartServlet.java

增加方法updateCount()

/**
 * 更新购物车的某个家居数量
 *
 * @param req
 * @param resp
 * @throws ServletException
 * @throws IOException
 */
protected void updateCount(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    int id = DataUtils.parseInt(req.getParameter("id"), 0);
    int count = DataUtils.parseInt(req.getParameter("count"), 1);
    //获取session中的购物车
    Cart cart = (Cart) req.getSession().getAttribute("cart");
    if (null != cart) {
        cart.updateCount(id, count);
    }
    //回到请求更新家居购物车的页面
    resp.sendRedirect(req.getHeader("Referer"));
}

21.3.3前端

cart.jsp

添加绑定事件,当点击修改对应的家居数量时,向服务器发送更新家居信息的请求

<script type="text/javascript">
    $(function () {
        /*--------------------------
            Cart Plus Minus Button
        ----------------------------*/
        var CartPlusMinus = $(".cart-plus-minus");
        CartPlusMinus.prepend('<div class="dec qtybutton">-</div>');
        CartPlusMinus.append('<div class="inc qtybutton">+</div>');
        $(".qtybutton").on("click", function () {
            var $button = $(this);
            var oldValue = $button.parent().find("input").val();
            if ($button.text() === "+") {
                var newVal = parseFloat(oldValue) + 1;
            } else {
                // Don't allow decrementing below zero
                if (oldValue > 1) {
                    var newVal = parseFloat(oldValue) - 1;
                } else {
                    newVal = 1;
                }
            }
            $button.parent().find("input").val(newVal);
            var furnId = $button.parent().find("input").attr("furnId");
            //发出修改购物车的请求
            location.href =
                "cartServlet?action=updateCount&count=" + newVal + "&id=" + furnId;
        });
    })
</script>

21.4完成测试

image-20221227180751201

修改家居数量:

image-20221227180837612

22.功能21-删除/清空购物车

22.1需求分析/图解

image-20221227185033474
  1. 进入购物车,可以删除某商品
  2. 可以清空购物车
  3. 要求该出适当的确认信息

22.2思路分析

见21.2思路分析图

22.3代码实现

22.3.1entity层

Cart.java添加删除购物车家居项的方法delItem()

/**
 * 根据家居id删除对应的cartItem
 *
 * @param id 家居id
 */
public void delItem(int id) {
    items.remove(id);
}

增加清空方法clear()

/**
 * 清空items
 */
public void clear() {
    items.clear();
}

22.3.2web层

CartServlet.java添加方法delItem()

/**
 * 根据id删除购物车的某个家居信息
 *
 * @param req
 * @param resp
 * @throws ServletException
 * @throws IOException
 */
protected void delItem(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    int id = DataUtils.parseInt(req.getParameter("id"), 0);
    //获取session中的购物车
    Cart cart = (Cart) req.getSession().getAttribute("cart");
    if (null != cart) {
        cart.delItem(id);
    }
    //回到请求删除家居项的购物车页面
    resp.sendRedirect(req.getHeader("Referer"));
}

增加clear()方法

/**
 * 清空购物车
 *
 * @param req
 * @param resp
 * @throws ServletException
 * @throws IOException
 */
protected void clear(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取session的购物车
    Cart cart = (Cart) req.getSession().getAttribute("cart");
    if (null != cart) {
        cart.clear();
    }
    //回到请求清空家居项的购物车页面
    resp.sendRedirect(req.getHeader("Referer"));
}

22.3.3前端

cart.jsp

//清空购物车绑定确认事件
$("a.clearCart").click(function () {
    return window.confirm("你确认要清空购物车吗?")
})

//给删除购物车绑定事件
$("a.delItem").click(function () {
    //获取要删除的家居名
    var furnName = $(this).parent().parent().find("td:eq(1)").text();
    //使用确认弹窗
    //点击确认,返回true,点击取消,返回false
    return window.confirm("你确认要删除" + furnName + "吗?")
})
image-20221227192117207 image-20221227194032831

22.4完成测试

删除购物车项:

image-20221227192245013 image-20221227192257075

清空购物车:

image-20221227194405872 image-20221227194415362

23.功能22-生成订单

23.1需求分析/图解

image-20221227195655878 image-20221227204858133 image-20221227201044836 image-20221227201115765
  1. 进入购物车,点击购物车结账
  2. 生成订单和订单项
  3. 如果会员没有登录,则先进入登录页面,完成登录后再结账

23.2思路分析

23.3代码实现

23.3.1设计order和order_item表

创建订单表和订单项表

###
-- 设计 订单表order
-- 字段参考前端给的界面
-- mysql每个字段应尽量使用not null约束
-- 字段类型的设计应当和关联的表的字段保持一致
-- 外键是否要给? 
-- 因为外键对效率有影响,应当从程序的业务保证数据的一致性,而不是db层保证
CREATE TABLE `order`(
`id` VARCHAR(64) PRIMARY KEY, #订单号,主键
`create_time` DATETIME NOT NULL, #订单生成时间
`price` DECIMAL(11,2) NOT NULL, #订单的总金额,类型应该和furn表的price类型对应
`status` TINYINT NOT NULL, #订单状态 0-未发货 1-已发货 2-已结账
`member_id` INT NOT NULL  #从属的会员id -不需要外键约束
)CHARSET utf8 ENGINE INNODB;

###
-- 设计 订单项表order_item
CREATE TABLE `order_item`(
`id` INT PRIMARY KEY AUTO_INCREMENT, #订单项id,自增长
`name` VARCHAR(64) NOT NULL, #家居名
`price` DECIMAL(11,2) NOT NULL, #家居单价
`count` INT NOT NULL, #某项的家居数量
`total_price` DECIMAL(11,2) NOT NULL, #订单项 的总价
`order_id` VARCHAR(64) NOT NULL #从属的订单号
)CHARSET utf8 ENGINE INNODB;

23.3.2entity层

Order.java

package com.li.furns.entity;

import java.math.BigDecimal;
import java.util.Date;

/**
 * Order表示一个订单
 *
 * @author 李
 * @version 1.0
 */
public class Order {
    //属性
    private String id;
    private Date createTime;
    private BigDecimal price;
    private Integer status;
    private Integer memberId;

    public Order() {
    }

    public Order(String id, Date createTime, BigDecimal price, Integer status, Integer memberId) {
        this.id = id;
        this.createTime = createTime;
        this.price = price;
        this.status = status;
        this.memberId = memberId;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public BigDecimal getPrice() {
        return price;
    }

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

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public Integer getMemberId() {
        return memberId;
    }

    public void setMemberId(Integer memberId) {
        this.memberId = memberId;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id='" + id + '\'' +
                ", createTime=" + createTime +
                ", price=" + price +
                ", status=" + status +
                ", memberId=" + memberId +
                '}';
    }
}

OrderItem.java

package com.li.furns.entity;

import java.math.BigDecimal;

/**
 * @author 李
 * @version 1.0
 */
public class OrderItem {

    private Integer id;
    private String name;
    private BigDecimal price;
    private Integer count;
    private BigDecimal totalPrice;
    private String orderId;

    public OrderItem() {
    }

    public OrderItem(Integer id, String name, BigDecimal price, Integer count, BigDecimal totalPrice, String orderId) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.count = count;
        this.totalPrice = totalPrice;
        this.orderId = orderId;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

    public BigDecimal getTotalPrice() {
        return totalPrice;
    }

    public void setTotalPrice(BigDecimal totalPrice) {
        this.totalPrice = totalPrice;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    @Override
    public String toString() {
        return "OrderItem{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", count=" + count +
                ", totalPrice=" + totalPrice +
                ", orderId='" + orderId + '\'' +
                '}';
    }
}

23.3.3dao层

OrderDAO接口

package com.li.furns.dao;

import com.li.furns.entity.Order;

/**
 * @author 李
 * @version 1.0
 */
public interface OrderDAO {
    /**
     * 将传入的order对象保存到数据表order表
     *
     * @param order order对象
     * @return 返回操作影响的行数
     */
    public int saveOrder(Order order);
}

OrderDAOImpl实现类

package com.li.furns.dao.impl;

import com.li.furns.dao.BasicDAO;
import com.li.furns.dao.OrderDAO;
import com.li.furns.entity.Order;

/**
 * @author 李
 * @version 1.0
 */
public class OrderDAOImpl extends BasicDAO<Order> implements OrderDAO {
    @Override
    public int saveOrder(Order order) {
        String sql =
                "INSERT INTO `order`(`id`,`create_time`,`price`,`status`,`member_id`) " +
                        "VALUES(?,?,?,?,?)";
        return update(sql, order.getId(), order.getCreateTime(),
                order.getPrice(), order.getStatus(), order.getMemberId());

    }
}

test包-OrderDAOImplTest测试

package com.li.furns.test;

import com.li.furns.dao.OrderDAO;
import com.li.furns.dao.impl.OrderDAOImpl;
import com.li.furns.entity.Order;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.Date;

/**
 * @author 李
 * @version 1.0
 */
public class OrderDAOImplTest {
    private OrderDAO orderDAO = new OrderDAOImpl();

    @Test
    public void saveOrder() {
        Order order = new Order("sn000002", new Date(),
                new BigDecimal(300), 0, 1);
        System.out.println(orderDAO.saveOrder(order));
    }
}
image-20221228183909748

OrderItemDAO接口

package com.li.furns.dao;

import com.li.furns.entity.OrderItem;

/**
 * OrderItemDAO表示一个订单项
 *
 * @author 李
 * @version 1.0
 */
public interface OrderItemDAO {
    /**
     * 将传入的orderItem对象保存到order_item表中
     *
     * @param orderItem
     * @return
     */
    public int saveOrderItem(OrderItem orderItem);

}

OrderItemDAOImpl

package com.li.furns.dao.impl;

import com.li.furns.dao.BasicDAO;
import com.li.furns.dao.OrderItemDAO;
import com.li.furns.entity.OrderItem;

/**
 * @author 李
 * @version 1.0
 */
public class OrderItemDAOImpl extends BasicDAO<OrderItem> implements OrderItemDAO {
    @Override
    public int saveOrderItem(OrderItem orderItem) {
        String sql =
                "INSERT INTO `order_item`(`id`,`name`,`price`,`count`,`total_price`,`order_id`) " +
                        "VALUES(?,?,?,?,?,?);";
        return update(sql, orderItem.getId(), orderItem.getName(), orderItem.getPrice(),
                orderItem.getCount(), orderItem.getTotalPrice(), orderItem.getOrderId());
    }
}

test包-OrderItemDAOImplTest

package com.li.furns.test;

import com.li.furns.dao.OrderItemDAO;
import com.li.furns.dao.impl.OrderItemDAOImpl;
import com.li.furns.entity.OrderItem;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;

/**
 * @author 李
 * @version 1.0
 */
public class OrderItemDAOImplTest {
    private OrderItemDAO orderItemDAO = new OrderItemDAOImpl();

    @Test
    public void saveOrderItem() {
        OrderItem orderItem = new OrderItem(null, "北欧小沙发", new BigDecimal(200),
                3, new BigDecimal(600), "sn000001");
        System.out.println(orderItemDAO.saveOrderItem(orderItem));
    }
}
image-20221228190713106

23.3.4service层

OrderService接口

package com.li.furns.service;

import com.li.furns.entity.Cart;

/**
 * @author 李
 * @version 1.0
 */
public interface OrderService {
    /**
     * 1.生成订单
     * 2.订单是根据购物车来生成的,cart对象在session,通过web层,传入saveOrder
     * 3.订单和会员id关联
     *
     * @param cart     购物车
     * @param memberId 会员id
     * @return 返回生成的订单号
     */
    public String saveOrder(Cart cart, int memberId);
}

OrderServiceImpl实现类

package com.li.furns.service.impl;

import com.li.furns.dao.FurnDAO;
import com.li.furns.dao.OrderDAO;
import com.li.furns.dao.OrderItemDAO;
import com.li.furns.dao.impl.FurnDAOImpl;
import com.li.furns.dao.impl.OrderDAOImpl;
import com.li.furns.dao.impl.OrderItemDAOImpl;
import com.li.furns.entity.*;
import com.li.furns.service.OrderService;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author 李
 * @version 1.0
 */
public class OrderServiceImpl implements OrderService {
    private OrderDAO orderDAO = new OrderDAOImpl();
    private OrderItemDAO orderItemDAO = new OrderItemDAOImpl();
    private FurnDAO furnDAO = new FurnDAOImpl();

    @Override
    public String saveOrder(Cart cart, int memberId) {
        //这里的业务相对而言比较综合
        //任务:将cart购物车的数据以order和orderItem的形式保存到数据库中

        /**
         * 因为生成订单会操作多张表,设计到多表事务问题,使用ThreadLocal+MySQL事务机制+过滤器Filter
         * 因为事务处理考虑的点比较多,这里先不处理,后面专门处理
         */

        //1.构建一个对应的order对象
        //先生成一个UUID,表示当前的订单号。要保证订单号是唯一的
        String orderId = System.currentTimeMillis() + "" + memberId;
        Order order = new Order(orderId, new Date(), cart.getCartTotalPrice(), 0, memberId);
        //将order对象保存到数据库order表中
        orderDAO.saveOrder(order);
        //2.通过cart对象,遍历出CartItem家居项,构建orderItem对象
        HashMap<Integer, CartItem> items = cart.getItems();
        //遍历hm
        /**
         * 遍历方法一:entrySet
         * 通过entrySet的方法遍历items,取出cartItem
         * for(Map.Entry<Integer, CartItem> entry : items.entrySet()) {
         *       CartItem item = entry.getValue();
         *       ...
         *  }
         */
        //遍历方法二:keySet
        Set<Integer> keys = items.keySet();
        for (Integer id : keys) {
            //获取家居项
            CartItem item = items.get(id);
            //构建orderItem对象
            OrderItem orderItem = new OrderItem(null, item.getName(), item.getPrice(),
                    item.getCount(), item.getTotalPrice(), orderId);
            //将orderItem对象保存到数据库表order_item中
            orderItemDAO.saveOrderItem(orderItem);
            //更新furn表的对应记录的sales销量,stock存量
            //(1)获取到furn对象
            Furn furn = furnDAO.queryFurnById(id);
            //(2)更新furn对象的sales销量,stock存量
            furn.setSales(furn.getSales() + item.getCount());
            furn.setStock(furn.getStock() - item.getCount());
            //(3)更新到数据表中
            furnDAO.updateFurn(furn);
        }
        //清空购物车
        cart.clear();
        //返回生成的订单号
        return orderId;
    }
}

test包-OrderServiceImplTest测试

package com.li.furns.test;

import com.li.furns.entity.Cart;
import com.li.furns.entity.CartItem;
import com.li.furns.service.OrderService;
import com.li.furns.service.impl.OrderServiceImpl;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;

/**
 * @author 李
 * @version 1.0
 */
public class OrderServiceImplTest {
    private OrderService orderService = new OrderServiceImpl();

    @Test
    public void saveOrder() {
        //构建cart对象
        Cart cart = new Cart();
        cart.addItem(new CartItem(1, "北欧风格小桌子", new BigDecimal(180), 10, new BigDecimal(1800)));
        cart.addItem(new CartItem(26, "简约风格小椅子", new BigDecimal(100), 5, new BigDecimal(500)));
        String orderId = orderService.saveOrder(cart, 2);
        System.out.println(orderId);
    }
}
image-20221228201239274

furn表对应的家居项:

-测试前

image-20221228200854786

-测试后

image-20221228200942578

order表:

image-20221228201410295

order_item表:

image-20221228201455336

23.3.5web层

配置OrderServlet

<servlet>
    <servlet-name>OrderServlet</servlet-name>
    <servlet-class>com.li.furns.web.OrderServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>OrderServlet</servlet-name>
    <url-pattern>/orderServlet</url-pattern>
</servlet-mapping>

OrderServlet:

package com.li.furns.web;

import com.li.furns.entity.Cart;
import com.li.furns.entity.Member;
import com.li.furns.service.OrderService;
import com.li.furns.service.impl.OrderServiceImpl;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

/**
 * @author 李
 * @version 1.0
 */
public class OrderServlet extends BasicServlet {
    private OrderService orderService = new OrderServiceImpl();

    /**
     * 生成订单
     *
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    protected void saveOrder(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取购物车cart
        Cart cart = (Cart) req.getSession().getAttribute("cart");
        if (null == cart || cart.isEmpty()) {//购物车不存在session或者购物车没有任何东西
            // 转发到首页
            req.getRequestDispatcher("/index.jsp").forward(req, resp);
            return;//结束业务
        }
        //获取当前登录的memberId
        Member member = (Member) req.getSession().getAttribute("member");
        if (null == member) {//如果没有登录
            //转发到登录页面
            req.getRequestDispatcher("/views/member/login.jsp").forward(req, resp);
            return;//结束业务
        }

        //生成订单
        String orderId = orderService.saveOrder(cart, member.getId());
        req.getSession().setAttribute("orderId", orderId);

        //使用重定向到checkout.jsp页面
        resp.sendRedirect(req.getContextPath() + "/views/order/checkout.jsp");

    }
}

修改前端接口:略

23.4完成测试

未登录状态下添加家居到购物车,点击生成账单,请求转发登录页面

image-20221228221535569 image-20221228221609192

点击登录后重新返回购物车页面,点击生成订单,生成订单成功

image-20221228221748394

数据库插入成功

order表

image-20221228221841883

order_item表

image-20221228221939433

furn表

image-20221228222027320
posted @ 2022-12-27 21:00  一刀一个小西瓜  阅读(98)  评论(0编辑  收藏  举报