购物车的设计与实现

在开发购物车之前,首先要把几个关键类之间的关系理清楚

类图

首先各个类的意义:
1. Product 产品
2. User 用户
3. Order 订单
4. OrderItem 订单项

前3者都好理解,订单项需要解释一下。

比如阁下在某宝下了一次订单,这个订单包括了

苹果                               3个

蜡烛                               2个

玩具                               4个

一条记录就是一个订单项,对应一种商品,以及购买数量。

类图

类关系图

1. 产品和订单项的关系是 一对多
  一种产品,对应多条订单项。
  一条订单项,对应一种产品
2. 订单项和订单的关系 多对一
  一个订单里有多条订单项
  一个订单项,只会出现在一个订单里
3. 订单和用户的关系: 多对一
  一个订单,只能属于一个用户
  一个用户,可以下多个订单

类关系图

因为本文主要讲解如何开发购物车,所以会把重点放在与购物车紧密相关的查询功能方面,不会全面地提供CRUD(增删改查)功能,如果对CRUD还不够熟悉,请参考 Servlet CRUD

在开始之前,需要做一些数据库方面的准备工作.

1. 创建数据库 cart

2. 在cart 数据库中创建表product

3. 为product准备4条数据

(与Product模块类似的,不提供完整的用户CRUD(增 删 改 查) 也是通过SQL准备User数据)

4. 在cart 数据库中创建表user

5.为user准备1条数据

6.创建order表,里面有一个uid字段用于表明该订单属于哪个用户
(注: order是关键字,不能直接用作表名,通常的做法是加一个下划线order_)
7.创建orderitem,表里有id,pid,num,oid等字段。 分别表示主键,商品对应的id,购买数量以及订单id

注:插入中文的时候,如果失败,要记得把表的编码方式修改为UTF-8

创建数据库:

create database cart;

创建product表:

DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(50) DEFAULT NULL,
  `price` float DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入四条数据:

insert into product values(1,'黑色的丝袜',500);
insert into product values(2,'相机',2500);
insert into product values(3,'电动牙刷',180);
insert into product values(4,'蜡烛',0.20);

创建user表:

create table user(
id int,
name varchar(50),
password varchar(50)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入一条数据:

insert into user values(1,'tom','123');

创建order表和orderItem表:

create table order_(
  id int AUTO_INCREMENT,
  uid int,
  primary key(id)
);
 
create table orderitem(
  id int AUTO_INCREMENT,
  pid int,
  num int,
  oid int,
  primary key(id)
);

创建实体类  

创建Product类

package bean;
 
public class Product {
 
    private int id;
    private String name;
    private float price;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
     
}

 创建user类:

package bean;
 
public class User {
    private int id;
    private String name;
    private String password;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

创建OrderItem类:

package bean;
 
public class OrderItem {
 
    private int id;
    private Product product;
    private int num;
    private Order order;
    public Order getOrder() {
        return order;
    }
    public void setOrder(Order order) {
        this.order = order;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public Product getProduct() {
        return product;
    }
    public void setProduct(Product product) {
        this.product = product;
    }
    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
}

 创建Order类:

package bean;

public class Order {

    int id;
    User user;

    public int getId() {
        return id;
    }

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

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

创建DAO类

(记得导入数据库驱动包)

ProductDAO提供对Product的查询:

因为购买的时候,提交到服务器的是pid, 而OrderItem类的product属性是一个Product类型

所以ProductDAO需要根据id获取Product对象

package dao;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
 
import bean.Product;
 
public class ProductDAO {
 
    public static void main(String[] args) {
 
        System.out.println(new ProductDAO().getProduct(1).getName());
 
    }
 
    public Product getProduct(int id) {
        Product result = null;
 
        try {
            Class.forName("com.mysql.jdbc.Driver");
 
            Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cart?characterEncoding=UTF-8",
                    "root", "admin");
 
            String sql = "select * from product where id = ?";
 
            PreparedStatement ps = c.prepareStatement(sql);
            ps.setInt(1, id);
 
            ResultSet rs = ps.executeQuery();
 
            if (rs.next()) {
                result = new Product();
                result.setId(id);
 
                String name = rs.getString(2);
                float price = rs.getFloat(3);
 
                result.setName(name);
                result.setPrice(price);
 
            }
 
            ps.close();
 
            c.close();
 
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }
 
    public List<Product> ListProduct() {
        List<Product> products = new ArrayList<Product>();
 
        try {
            Class.forName("com.mysql.jdbc.Driver");
 
            Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cart?characterEncoding=UTF-8",
                    "root", "admin");
 
            String sql = "select * from product order by id desc";
 
            PreparedStatement ps = c.prepareStatement(sql);
 
            ResultSet rs = ps.executeQuery();
 
            while (rs.next()) {
                Product product = new Product();
                int id = rs.getInt(1);
                String name = rs.getString(2);
                float price = rs.getFloat(3);
 
                product.setId(id);
                product.setName(name);
                product.setPrice(price);
                products.add(product);
 
            }
 
            ps.close();
 
            c.close();
 
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return products;
    }
}

 UserDAO:

根据name和password查询表user,如果有数据就表示账号密码正确
package dao;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
import bean.User;
 
public class UserDAO {
 
    public static void main(String[] args) {
 
        System.out.println(new UserDAO().getUser("tom", "123").getId());
 
    }
 
    public User getUser(String name, String password) {
        User result = null;
 
        try {
            Class.forName("com.mysql.jdbc.Driver");
 
            Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cart?characterEncoding=UTF-8",
                    "root", "admin");
 
            String sql = "select * from user where name = ? and password = ?";
 
            PreparedStatement ps = c.prepareStatement(sql);
 
            ps.setString(1, name);
            ps.setString(2, password);
            ResultSet rs = ps.executeQuery();
 
            if (rs.next()){
                result = new User();
                result.setId(rs.getInt(1));
                result.setPassword(password);
                result.setName(name);
            }
 
            ps.close();
 
            c.close();
 
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }
}

 OrderDAO:

OrderDAO把订单对象保存到数据库中。

这里需要注意的是,Order对象保存到数据库中后,该对象就会有对应的id,这个id,在后续保存OrderItem的时候,是作为order id存在的。

所以在保存的数据库的时候,要获取自增长id

package dao;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
import bean.Order;
 
public class OrderDAO {
 
    public void insert(Order o) {
 
        try {
            Class.forName("com.mysql.jdbc.Driver");
 
            Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cart?characterEncoding=UTF-8",
                    "root", "admin");
 
            String sql = "insert into order_ values(null,?)";
 
            PreparedStatement ps = c.prepareStatement(sql);
 
            ps.setInt(1, o.getUser().getId());
 
            ps.execute();
 
            ResultSet rs = ps.getGeneratedKeys();
            if (rs.next()) {
                int id = rs.getInt(1);
                o.setId(id);
            }
 
            ps.close();
 
            c.close();
 
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
 
}

 OrderItemDAO:

package dao;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
 
import bean.OrderItem;
import bean.Product;
 
public class OrderItemDAO {
 
    public static void main(String[] args) {
 
    }
     
    public void insert(OrderItem oi) {
 
        try {
            Class.forName("com.mysql.jdbc.Driver");
 
            Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cart?characterEncoding=UTF-8",
                    "root", "admin");
 
            String sql = "insert into orderitem values(null,?,?,?)";
 
            PreparedStatement ps = c.prepareStatement(sql);
 
            ps.setInt(1,oi.getProduct().getId());
            ps.setInt(2,oi.getNum());
            ps.setInt(3,oi.getOrder().getId());
             
            ps.execute();
 
            ps.close();
 
            c.close();
 
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         
    }
 
}

创建jsp页面 

(在上面的一些实体类中,有些变量是私有变量,需创建set/get()方法,在jsp页面中使用EL表达式时,可直接使用“对象.属性名”来读其值;使用jstl需要导入两个包)

创建用户登录页面login.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java"
         pageEncoding="UTF-8" import="java.util.*"%>
<html>
<head>
    <title>用户登录</title>
</head>
<body>
    <form action="login" method="post">
        账号: <input type="text" name="name"> <br>
        密码: <input type="password" name="password"> <br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

创建商品展示页面listProduct.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java"
         pageEncoding="UTF-8" import="java.util.*"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>商品展示页</title>
</head>
<body>

    <c:if test="${!empty user}">
        <div align="center">
            当前用户: ${user.name}
        </div>
    </c:if>

    <table align='center' border='1' cellspacing='0'>
        <tr>
            <td>id</td>
            <td>名称</td>
            <td>价格</td>
            <td>购买</td>
        </tr>
        <c:forEach items="${products}" var="product" varStatus="st">
            <tr>
            <td>${product.id}</td>
            <td>${product.name}</td>
            <td>${product.price}</td>
            <td>

            <form action="addOrderItem" method="post">

            数量<input type="text" value="1" name="num">
            <input type="hidden" name="pid" value="${product.id}">
            <input type="submit" value="购买">
            </form>
            </td>

            </tr>
        </c:forEach>
    </table>
</body>
</html>

 显示购物车内容listOrderItem.jsp:

其中添加生成用户订单功能

<%@ page contentType="text/html;charset=UTF-8" language="java"
         pageEncoding="UTF-8" import="java.util.*" isELIgnored="false"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>购物车</title>
</head>
<body>
    <h1 align="center" >${user.name}的购物车</h1>
    <table align='center' border='1' cellspacing='0'>
        <tr>
            <td>商品名称</td>
            <td>单价</td>
            <td>数量</td>
            <td>小计</td>
        </tr>

        <c:forEach items="${ois}" var="oi" varStatus="st">
            <tr>
                <td>${oi.product.name}</td>
                <td>${oi.product.price}</td>
                <td>${oi.num}</td>
                <td>${oi.product.price*oi.num}</td>
            </tr>
        </c:forEach>

        <c:if test="${!empty ois}">
            <tr>
                <td colspan="4" align="right">
                    <a href="createOrder">生成订单</a>
                </td>
            </tr>
        </c:if>
    </table>
</body>
</html>

点击生成订单后,在数据库中的orderitem表观察到插入的数据

创建Servlet

UserLoginServlet:

登陆Servlet, 通过name和password获取user对象
如果对象不为空,就表示账号密码正确,跳转到产品显示界面 /listProduct
如果对象为空,就跳转到登陆界面,重新登陆

package servlet;

import bean.User;
import dao.UserDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "UserLoginServlet")
public class UserLoginServlet extends HttpServlet {
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String name = request.getParameter("name");
        String password = request.getParameter("password");
        User user = new UserDAO().getUser(name,password);
        if (null==user){
            response.sendRedirect("login.jsp");
        }else{
            //创建session会话
            request.getSession().setAttribute("user",user);
            response.sendRedirect("listProduct");
        }
    }
}

ProductListServlet:

ProductListServlet的作用是通过ProductDAO把product从数据库查出来,然后通过listProduct.jsp显示出来

package servlet;

import bean.Product;
import dao.ProductDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet(name = "ProductListServlet")
public class ProductListServlet extends HttpServlet {
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        List<Product> products = new ProductDAO().ListProduct();
        request.setAttribute("products",products);
        request.getRequestDispatcher("listProduct.jsp").forward(request,response);

    }
}

OrderItemAddServlet:

购买行为本身就是创建一个OrderItem对象
在负责购买商品的OrderItemAddServlet 中,进行如下流程
1. 获取购买数量
2. 获取购买商品的id
3. 根据id获取商品对象
4. 创建一个新的OrderItem对象
5. 从session中取出一个List , 这个List里面存放陆续购买的商品。
如果是第一次从session中获取该List,那么它会是空的,需要创建一个ArrayList
6. 把新创建的OrderItem对象放入该List 中
7. 跳转到显示购物车的listOrderItem

(在遇到购买相同物品时,遍历session中所有的OrderItem,如果找到对应的product.id一样的条目,就调整其数量,如果没有找到,就新增加一条)

package servlet;

import bean.OrderItem;
import bean.Product;
import dao.ProductDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@WebServlet(name = "OrderItemAddServlet")
public class OrderItemAddServlet extends HttpServlet {
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        int num = Integer.parseInt(request.getParameter("num"));
        int pid = Integer.parseInt(request.getParameter("pid"));
        Product p = new ProductDAO().getProduct(pid);

        OrderItem oi = new OrderItem();

        oi.setNum(num);
        oi.setProduct(p);

        List<OrderItem> ois = (List<OrderItem>) request.getSession().getAttribute("ois");

        if (null == ois) {
            ois = new ArrayList<OrderItem>();
            request.getSession().setAttribute("ois", ois);
        }

        boolean found = false;
        for (OrderItem orderItem : ois) {
            if (orderItem.getProduct().getId() == oi.getProduct().getId()) {
                orderItem.setNum(orderItem.getNum() + oi.getNum());
                found = true;
                break;
            }
        }

        if (!found)
            ois.add(oi);
        response.sendRedirect("listOrderItem");
        //下面直接重定向到jsp页面也能使用
        //response.sendRedirect("listOrderItem.jsp");
    }
}

OrderItemListServlet:

显示购物车的OrderItemListServlet 其实什么也没做,因为数据已经在session准备好了,直接服务端跳转到listOrderItem.jsp
在listOrderItem.jsp中,从session中遍历出所有的OrderItem。 因为保存在OrderItem 上的是一个Product对象,所以很容易就可以通过EL表达式遍历出商品的名称和价格。

package servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*直接转发到listOrder.jsp页面也能显示信息。因为listOrder.jsp所要的
参数ois是已经保存在浏览器上了。我猜站长这么做的目的是为了方便以后
扩张功能就可以将逻辑代码写到OrderItemListServlet。*/
@WebServlet(name = "OrderItemListServlet")
public class OrderItemListServlet extends HttpServlet {
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher("listOrderItem.jsp").forward(request, response);
    }
}

OrderCreateServlet:

OrderCreateServlet创建订单的Servlet
1. 首选判断用户是否登陆,如果没有登陆跳转到登陆页面
2. 创建一个订单对象,并设置其所属用户
3. 把该订单对象保存到数据库中
4. 遍历session中所有的订单项,设置他们的Order。 然后保存到数据库中
5. 清空session中的订单项
6. 最后打印订单创建成功

package servlet;

import bean.Order;
import bean.OrderItem;
import bean.User;
import dao.OrderDAO;
import dao.OrderItemDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet(name = "OrderCreateServlet")
public class OrderCreateServlet extends HttpServlet {
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        User u = (User) request.getSession().getAttribute("user");
        if (null==u){
            response.sendRedirect("login.jsp");
            return;
        }
        Order o = new Order();
        o.setUser(u);

        new OrderDAO().insert(o);
        List<OrderItem> ois = (List<OrderItem>)request.getSession().getAttribute("ois");
        for (OrderItem oi:ois){
            oi.setOrder(o);
            new OrderItemDAO().insert(oi);
        }
        ois.clear();
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().println("订单创建成功");
    }
}

 配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <servlet>
        <servlet-name>ProductListServlet</servlet-name>
        <servlet-class>servlet.ProductListServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ProductListServlet</servlet-name>
        <url-pattern>/listProduct</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>UserLoginServlet</servlet-name>
        <servlet-class>servlet.UserLoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>UserLoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>OrderItemAddServlet</servlet-name>
        <servlet-class>servlet.OrderItemAddServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>OrderItemAddServlet</servlet-name>
        <url-pattern>/addOrderItem</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>OrderItemListServlet</servlet-name>
        <servlet-class>servlet.OrderItemListServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>OrderItemListServlet</servlet-name>
        <url-pattern>/listOrderItem</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>OrderCreateServlet</servlet-name>
        <servlet-class>servlet.OrderCreateServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>OrderCreateServlet</servlet-name>
        <url-pattern>/createOrder</url-pattern>
    </servlet-mapping>

</web-app>

 购物车项目目录如下:

原文地址:http://how2j.cn/k/cart/cart-tutorials/595.html

猜你喜欢

转载自www.cnblogs.com/churujianghudezai/p/11555374.html