java大作业博客--购物车
Java 大作业————使用MySQL的购物车
一、团队介绍
| 姓名 | 任务 | 
|---|---|
| 李天明、康友煌 | GUI设计及代码编写 | 
| 谢晓淞 | 业务代码编写、MySQL服务器平台部署、git代码库 | 
| 严威 | 类和包的结构关系设计以及流程设计、PPT制作 | 
二、项目git地址
码云地址 (数据库用户目前已经删除)
三、项目主要使用技术
- DAO模式
- MVC模式
- MySQL数据库
四、项目其余特点
- 界面美观
- 可在不同设备登陆同一账号
五、项目功能架构图与主要功能流程图

六、UML类图

七、项目运行截图
- 登录界面

- 登录默认页面(无显示)

- 商城界面

- 商品详情界面

- 购物车界面

- 订单界面

- 订单详情界面

八、项目整体流程
数据库
使用的是MySQL数据库,数据库采用的DAO模式,其中订单,商城,购物车,用户账号密码,商家账号密码后台存储结构都是数据库。他们的表结构如下:
用户表(user)
用户表有三个字段,一个是用户id,一个是用户名,另一个是用户密码的md5值

商家表(merchant)
商家表同用户表

订单表(user_order)
订单表这个信息比较多,实际上订单表中都是以单种商品存在的,什么意思呢,当一个订单中有两件商品时,我会将这两件商品分开以相同的订单id存入数据库,这样设计有一个好处,就是商家也可以通过查询这个表当中的merchant_name字段来查询看谁买了自己商品,然后发货。

商城商品表(product)
这个也没什么特别的,只有一点是值得一提的,那就是details字段,我想让不同的商品体现不同的属性,比如买书会有对应的出版社,出版日期,买电脑有cpu信息这一类,我总不能每种都新建一个类来存储,所以我这边是用map来存储的,而map是一个类,要存入数据库就必须序列化,java要序列化好像还要自己写,比较麻烦,所以我干脆直接用来json格式化字符串来保存。

购物车表(cart)
cart表同上其中item_array同样使用的json格式化字符串来存储不确定数量的商品

DAO模式体现
DAO模式是什么,在我看来,DAO模式是用户操作和后端存储结构操作之间的一条铰链。我们先定义好了这样的一个接口:
package model.dao;
import java.util.ArrayList;
import model.order.Order;
public interface OrderDao {
    public List<Order> getOrders();
    public boolean payOrder(String orderId);
    public boolean cancelOrder(String orderId);
    public boolean deleteOrder(String orderId);
}
对于GUI的编写人员来说,我只需要知道这样的一个接口就能对后端的存储进行读取,写入,修改等操作,我不需要知道这些操作的具体实现。并且如果后面想要换存储结构,又或者说换一种数据库,比如说MySQL要换成Oracle,那么存储结构的编写人员只要根据这个接口对这些操作进行重写就好了,对GUI的代码不用做太多的改变,就能达到目的,这样将存储结构与其他业务代码分开来,减少了代码的耦合度的模式,就是DAO模式。
MVC模式体现
MVC又是什么,好像学习java总是会学到一些奇怪的缩写。我就拿项目中搜索商品举例吧:

MVC分为Model, View, Controler。其中Controler即为监听器,即上图中的searchButtonActionPerformed,当用户输入完商品关键字,并点击搜索Button时,就会触发这个Controler,Controler从searchTextField,即视图层View,获取到了用户输入,然后Controler转而将得到的用户输入交给了malljdbimpl,即模型层Model,并得到了Model对该关键字的搜索结果,最后再将搜索结果交给了视图层,fillTable方法中的tableModel,进行搜索结果的显示,即视图层更新。
如果上面讲的太复杂听不懂,那么我们可以从以下角度理解这段代码的MVC模式:
假设公司中有一个老板叫监听器(Controler),我们就叫他总监吧,他底下有三个小喽啰,一个是干苦力专门找东西的模范员工老莫(Model),一个是老板的传话秘书S小姐(View1,即上面代码中的asearchTextField),还有一个是负责跟顾客交谈的秘书T小姐(View2,即上述代码中fillTable方法中的tableModel)。这天来了个客户:
S小姐(View1) -> 总监(Controler):“老板有一个客户要找xxx商品。”(传递用户输入)
总监(Controler) -> 老莫(Model):“欸老莫啊,你去找找xxx这个商品的相关资料。”(传递用户输入)
老模玩命翻箱倒柜中......(获得搜索结果)
老莫(Model) -> 总监(Controler):“老板找到了,给你。”(传递搜索结果)
总监(Controler) -> T小姐(View2) :“商品资料找到了,你去跟顾客谈生意吧。”(传递搜索结果)
随后T小姐向顾客展示了搜索结果。(视图更新)
以上,即为我对MVC模式的理解。也是MVC在项目中的体现。附上一张MVC图:

九、项目关键代码
搜索商品
public List<Product> searchProduct(String name, int page) {
    List<Product> resultList = new ArrayList<>();
    Connection conn = null;
    PreparedStatement pstat = null;
    ResultSet result ;
    // 每页条数
    int pieces = 10;
    int limitStart = page * pieces - pieces;
    int limitEnd = page * pieces - 1;
    String sqlValue = "%" + name + "%";
    String sql = "select * from product where name like ? or description like ? or brand like ? limit " + limitStart + "," + limitEnd + ";";
    String pageSql = "select count(*) from product where name like ? or description like ? or brand like ?;";
    try {
        conn = Mysql.getConnection();
        pstat = conn.prepareStatement(sql);
        pstat.setString(1, sqlValue);
        pstat.setString(2, sqlValue);
        pstat.setString(3,sqlValue);
        // 设置参数写入
        result = pstat.executeQuery();
        while(result.next()) {
            String productId = result.getString(1);
            String productName = result.getString(2);
            String productDescription = result.getString(3);
            double productPrice = result.getDouble(4);
            String productBrand = result.getString(5);
            String merchant_name = result.getString(6);
            String detailsString = result.getString(7);
            HashMap<String, String> details = jsonToMap(detailsString);
            resultList.add(new Product(productId, productName, productDescription, productPrice, productBrand, details,merchant_name));
        }
        pstat.close();
        pstat = conn.prepareStatement(pageSql);
        pstat.setString(1, sqlValue);
        pstat.setString(2, sqlValue);
        pstat.setString(3,sqlValue);
        result = pstat.executeQuery();
        if (result.next()) {
            this.pageNumber = result.getInt(1);
            if (this.pageNumber % 10 == 0) {
                this.pageNumber /= 10;
            }
            else {
                this.pageNumber = this.pageNumber / 10 + 1;
            }
        }
    } catch (SQLException sqle) {
        sqle.printStackTrace();
    } catch (Exception e){
        e.printStackTrace();
    } finally {
        Mysql.realeaseAll(null,pstat, conn);
    }
    System.out.println(resultList.size());
    this.products = resultList;
    return resultList;
}
生成订单
public boolean generalOrder(CartItemsJDBCImpl cart, String address, long phoneNumber) {
    Order newOrder =  new Order(
        cart.getItems(),
        cart.totalPrice(),
        cart.userNameGet(),
        address,
        System.currentTimeMillis(),
        phoneNumber,
        "unpaid"
        );
    this.orders.add(newOrder);
    Connection conn = null;
    PreparedStatement pstat = null;
    boolean result = false;
    long maxId = 0;
    String sql = "insert into user_order(order_id, user_name, product_id,product_name, product_description, product_price, product_brand, product_details, merchant_name, amount, address, timetamp, phone_number, order_status)  values (?,?,?,?,?,?,?,?,?,?,?,?,?,?);";
    String sqlMaxOrderId = "select max(order_id) from user_order;";
    try {
        conn = Mysql.getConnection();
        pstat = conn.prepareStatement(sqlMaxOrderId);
        ResultSet idResult = pstat.executeQuery();
        if(idResult.next()) {
            maxId = idResult.getLong(1);
        }
        pstat.close();
        newOrder.setOrderId(maxId + 1 + "");
        // 插入数据库
        for(CartItem eItem : newOrder.getItems()) {
            System.out.println(eItem.getProduct());
            pstat = conn.prepareStatement(sql);
            pstat.setLong(1, maxId + 1);
            pstat.setString(2, this.userName);
            pstat.setString(3, eItem.getProduct().getProductId());
            pstat.setString(4, eItem.getProduct().getProductName());
            pstat.setString(5, eItem.getProduct().getProductDescription());
            pstat.setDouble(6, eItem.getProduct().getProductPrice());
            pstat.setString(7, eItem.getProduct().getBrand());
            pstat.setString(8, JSONObject.fromObject(eItem.getProduct().getDetails()).toString());
            pstat.setString(9, eItem.getProduct().getMerchant_name());
            pstat.setInt(10, eItem.getAmount());
            pstat.setString(11, newOrder.getAddress());
            pstat.setLong(12, newOrder.getTimesTamp());
            pstat.setLong(13, phoneNumber);
            pstat.setString(14, newOrder.getOrderStatus());
            if(pstat.executeUpdate() > -1) {
                result = true;
            }
            else {
                 result = false;
            }
            pstat.close();
        }
    } catch (SQLException sqle) {
        sqle.printStackTrace();
    } catch (Exception e){
        e.printStackTrace();
    } finally {
        Mysql.realeaseAll(null,pstat, conn);
    }
    return result;
}
支付订单
public boolean payOrder(String orderId) {
    Connection conn = null;
    PreparedStatement pstat = null;
    int result = -1;
    String sql = "update user_order set order_status = ? where user_name = ? and order_id = ? and order_status = 'unpaid';";
    try {
        conn = Mysql.getConnection();
        pstat = conn.prepareStatement(sql);
        pstat.setString(1, "paid");
        pstat.setString(2, this.userName);
        pstat.setString(3, orderId);
        result = pstat.executeUpdate();
    } catch (SQLException sqle) {
        sqle.printStackTrace();
    } catch (Exception e){
        e.printStackTrace();
    } finally {
        Mysql.realeaseAll(null,pstat, conn);
    }
    if(result > 0) {
        for(int i = 0; i < this.orders.size(); i++) {
            Order e = this.orders.get(i);
            if(e.getOrderId().equals(orderId)) {
                this.orders.get(i).setOrderStatus("paid");
                break;
            }
        }
    }
    return result > 0 ? true : false;
}
从购物车中读取订单信息到本地
public void readData() {
    Connection conn = null;
    PreparedStatement pstat = null;
    ResultSet r = null;
    String sql = "select item_array from cart where user_name = ?;";
    try {
        conn = Mysql.getConnection();
        pstat = conn.prepareStatement(sql);
        pstat.setString(1, this.name);
        r = pstat.executeQuery();
        // 数据不存在该用户的购物车,使用insert增添一个空的购物车
        if(r.next() == false) {
            this.items = new ArrayList<>();
            sql = "insert into cart(user_name, item_array) values (?,NULL);";
            pstat.close();
            pstat = conn.prepareStatement(sql);
            pstat.setString(1, this.name);
            pstat.execute();
        }
        else {
            String text = r.getString(1);
            // 数据库中购物车为NULL,为目前对象新建空购物车
            if(text == null) {
                this.items = new ArrayList<>();
            }
            else {
                JSONArray cartItemJSONArray = JSONArray.fromObject(text);
                this.items = (List<CartItem>) (JSONArray.toList(cartItemJSONArray, CartItem.class));
            }
        }
    } catch (SQLException sqle) {
        sqle.printStackTrace();
    } catch (Exception e){
        e.printStackTrace();
    } finally {
        Mysql.realeaseAll(null,pstat, conn);
    }
}
往购物车添加商品并更新到数据库
public boolean addItem(Product other, int num) {
    for (CartItem e : this.items) {
        // 已存在该商品,则在原本数量的基础上继续添加
        if (e.getProduct().getProductId().equals(other.getProductId())) {
            return this.changeItemAmount(other.getProductId(), num);
        }
    }
    this.items.add(new CartItem(other, num));
    // 连接数据库更新数据
    return this.databaseUpdate();
}
用户登录
public boolean login(String name, String password) {
    password = getMD5(password);
    if(password == "") {
        return false;
    }
    Connection conn = null;
    PreparedStatement pstat = null;
    ResultSet r = null;
    String sql = "select * from user where user = ? and password = ?;";
    try {
        conn = Mysql.getConnection();
        pstat = conn.prepareStatement(sql);
        pstat.setString(1, name);
        pstat.setString(2, password);
        r = pstat.executeQuery();
        this.loginStatus = r.next();
    } catch (SQLException sqle) {
        sqle.printStackTrace();
    } catch (Exception e){
        e.printStackTrace();
    } finally {
        Mysql.realeaseAll(null,pstat, conn);
    }
    if(this.loginStatus == true) {
        this.currentUser = name;
        this.accountInit();
    }
    return this.loginStatus;
}
十、尚待改进或未实现的内容
- GUI的变量命名其实还不太规范
- 实际上商家的业务代码我也已经写完了,但是GUI部分尚未实现,原本的想法是为商家也设计一个客户端
- 安全性不好,因为这个程序是在本地运行的,包括数据库连接部分,所以不法分子可以通过反编译class文件得到数据库的账号密码,从而进行不花钱买东西这种情况,又或者数据库污染。
十一、设计过程中使用到的帮助文档
Java MySQL连接
MySQL教程
Java JSON教程
java大作业博客--购物车的更多相关文章
- Java第二次博客作业
		Java第二次博客作业 时间过的很快啊,在不知不觉中这门课程的学习也就快要过去一半了,现在就来总结一下在这个第二个月的学习当中存在的问题以及得到的心得. 1.前言 第四次题目集和第五次题目集给我的感觉 ... 
- Java课程设计——博客作业教学数据分析系统(201521123082 黄华林)
		Java课程设计--博客作业教学数据分析系统(201521123082 黄华林) 一.团队课程设计博客链接 博客作业教学数据分析系统(From:网络五条狗) 二.个人负责模块或任务说明 1.网络爬虫 ... 
- iOS组件化思路-大神博客研读和思考
		一.大神博客研读 随着应用需求逐步迭代,应用的代码体积将会越来越大,为了更好的管理应用工程,我们开始借助CocoaPods版本管理工具对原有应用工程进行拆分.但是仅仅完成代码拆分还不足以解决业务之间的 ... 
- Java课程设计博客(个人)
		Java课程设计博客(个人) 1. 团队课程设计博客链接 http://www.cnblogs.com/wkfg/p/7063081.html 2. 个人负责模块或任务说明 负责模块/任务:编写doG ... 
- < JAVA - 大作业(2)仿qq即时通讯软件 >
		< JAVA - 大作业(2)仿qq即时通讯软件 > 背景 JAVA上机大作业:设计一个仿qq即时通讯软件 任务简要叙述:设计一款仿QQ的个人用户即时通讯软件,能够实现注册,登陆,与好友聊 ... 
- Java课程设计博客(团队)
		Java课程设计博客(团队) 1. 团队/项目名称 使用JAVA实现简易HTTP服务器 2. 团队成员 组长:林一心 组员:张杭镖 3. 项目git地址 https://github.com/oran ... 
- Java实现个人博客网站
		说明:该项目是实验楼用户"LOU3165780622"发布在实验楼上的项目教程:[Java实现个人博客],未经允许,禁止转载: 该项目利用 SSM 框架和 Mysql 以及一些简单 ... 
- JAVA大作业汇总1
		JAVA大作业 代码 ``` package thegreatwork; import javafx.application.; import javafx.scene.control.; impor ... 
- JAVA大作业汇总2
		JAVA大作业2 代码 package thegreatwork; //Enum一般用来表示一组相同类型的常量,这里用于表示运动方向的枚举型常量,每个方向对象包括方向向量. public enum D ... 
随机推荐
- spring  事务 XML
			事务就是AOP的很典型的应用.(原来需要自己写代码前开启关闭事务,现在通过spring的配置) 所以必要要有<aop:config>,<aop:config>里面要有<a ... 
- 浅谈javascript引擎执行代码的步骤-(2019-2)
			平时面试经常会遇到类似下面的这种题,而且千变万化,让人一个头两个.示例这道题算是稍微有点难度的了,这种题考查的是JavaScript引擎执行代码的步骤. b = 'cba'; function a(a ... 
- gperf heap profiler
			前言 gperf tools有很多功能,其中有一个heap profiler,可按函数级别定位分配内存的累积量 原理 gperf tools需要替换libc的malloc库,替换为tcmalloc:t ... 
- python asyncio 协程调用task步骤
			import asyncio async def compute(x, y): print("Compute %s + %s ..." % (x, y)) await asynci ... 
- lego loam 跑镭神32线激光雷达
			师弟反应镭神32线激光雷达(32C)录制的数据包不能跑lego loam,这里就总结一下. 首先lego loam默认的接受的topic name是velodyne_points,点云的frame_i ... 
- MySQL优化常见Extra分析——慢查询优化
			数据准备: create table user ( id int primary key, name ), sex ), index(name) )engine=innodb; 数据说明:用户表:id ... 
- python 提取整个 HTML 节点
			有的时候,需要把整个 HTML 节点原封不动地取下来,也就是包括节点标签.节点内容,甚至也包括内容中的空格.各种特殊符号等等. 假设已获取到页面源码,并将其保存在变量 src 中.则可有代码如下: f ... 
- Comet OJ-2019国庆欢乐赛
			国庆玩的有点嗨,开学了补题. A轰炸平面镇魂曲 题目描述 虹村万泰是一位二维世界的替身使者,他的替身 "轰炸平面镇魂曲" 能产生一条直线分割整个平面. 一开始,平面上有一个矩形,其 ... 
- 深入理解Vue组件3大核心概念
			摘要: 搞懂Vue组件! 作者:浪里行舟 原文:详解vue组件三大核心概念 Fundebug经授权转载,版权归原作者所有. 前言 本文主要介绍属性.事件和插槽这三个vue基础概念.使用方法及其容易被忽 ... 
- 【原】通过Spring结合Cglib处理非接口代理
			前言: 之前做的一个项目,虽然是查询ES,但内部有大量的逻辑计算,非常耗时,而且经常收到JVM峰值告警邮件.分析了一下基础数据每天凌晨更新一次,但查询和计算其实在第一次之后就可以写入缓存,这样后面直接 ... 
