JAVA 课设 满汉楼餐厅点餐系统

一、代码详解

1.总体结构展示


2.总体代码

2.1 libs文件

链接:https://pan.baidu.com/s/1nH-I7gIlsqyMpXDDCFRuOA 
提取码:3404

2.2 配置的德鲁连接池

#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mhl?rewriteBatchedStatements=true
username=root
password=wzh123123
#initial connection Size
initialSize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=50
#max wait time (5000 mil seconds)
maxWait=5000

2.3 utils 工具包

2.3.1 JDBCUtilsByDruid 类
package com.mhl.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * 基于druid数据库连接池的工具类
 */
public class JDBCUtilsByDruid {

    private static DataSource ds;

    //在静态代码块完成 ds初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //编写getConnection方法
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    //关闭连接, 再次强调: 在数据库连接池技术中,close 不是真的断掉连接
    //而是把使用的Connection对象放回连接池
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {

        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
2.3.2 Utility 类
package com.mhl.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * 基于druid数据库连接池的工具类
 */
public class JDBCUtilsByDruid {

    private static DataSource ds;

    //在静态代码块完成 ds初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //编写getConnection方法
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    //关闭连接, 再次强调: 在数据库连接池技术中,close 不是真的断掉连接
    //而是把使用的Connection对象放回连接池
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {

        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

2.4 dao包

2.4.1 BasicDAO 类
package com.mhl.dao;


import com.mhl.utils.JDBCUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * 开发BasicDAO , 是其他DAO的父类
 */
public class BasicDAO<T> { //泛型指定具体类型

    private QueryRunner qr =  new QueryRunner();

    //开发通用的dml方法, 针对任意的表
    public int update(String sql, Object... parameters) {

        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            int update = qr.update(connection, sql, parameters);
            return  update;
        } catch (SQLException e) {
           throw  new RuntimeException(e); //将编译异常->运行异常 ,抛出
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }

    }

    //返回多个对象(即查询的结果是多行), 针对任意表

    /**
     *
     * @param sql sql 语句,可以有 ?
     * @param clazz 传入一个类的Class对象 比如 Actor.class
     * @param parameters 传入 ? 的具体的值,可以是多个
     * @return 根据Actor.class 返回对应的 ArrayList 集合
     */
    public List<T> queryMulti(String sql, Class<T> clazz, Object... parameters) {

        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return qr.query(connection, sql, new BeanListHandler<T>(clazz), parameters);

        } catch (SQLException e) {
            throw  new RuntimeException(e); //将编译异常->运行异常 ,抛出
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }

    }

    //查询单行结果 的通用方法
    public T querySingle(String sql, Class<T> clazz, Object... parameters) {

        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return  qr.query(connection, sql, new BeanHandler<T>(clazz), parameters);

        } catch (SQLException e) {
            throw  new RuntimeException(e); //将编译异常->运行异常 ,抛出
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }

    //查询单行单列的方法,即返回单值的方法

    public Object queryScalar(String sql, Object... parameters) {

        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return  qr.query(connection, sql, new ScalarHandler(), parameters);

        } catch (SQLException e) {
            throw  new RuntimeException(e); //将编译异常->运行异常 ,抛出
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }

}
2.4.2 BillDAO 类
package com.mhl.dao;

import com.mhl.domain.Bill;

public class BillDAO extends BasicDAO<Bill> {
}
2.4.3 DiningTableDAO 类
package com.mhl.dao;

import com.mhl.domain.DiningTable;

public class DiningTableDAO extends BasicDAO<DiningTable> {
    //如果有特别的操作,可以写在 DiningTableDAO
}
2.4.4 EmployeeDAO 类
package com.mhl.dao;

import com.mhl.domain.Employee;

public class EmployeeDAO extends BasicDAO<Employee> {
    //这里还可以写特有的操作.
}
2.4.5 MenuDAO 类
package com.mhl.dao;

import com.mhl.domain.Menu;

public class MenuDAO extends BasicDAO<Menu> {
}
2.4.6 MultiTableDAO 类
package com.mhl.dao;

import com.mhl.domain.MultiTableBean;

public class MultiTableDAO extends BasicDAO<MultiTableBean> {
}

2.5 domain包

2.5.1 Bill 类
package com.mhl.domain;

import java.util.Date;

/**
 * Bill 是javabean 和 bill对应
 * id int primary key auto_increment, #自增主键
 * 	billId varchar(50) not null default '',#账单号可以按照自己规则生成 UUID
 * 	menuId int not null default 0,#菜品的编号, 也可以使用外键
 * 	nums int not null default 0,#份数
 * 	money double not null default 0, #金额
 * 	diningTableId int not null default 0, #餐桌
 * 	billDate datetime not null ,#订单日期
 * 	state varchar(50) not null default '' # 状态 '未结账' , '已经结账', '挂单'
 */
public class Bill {
    private Integer id;
    private String billId;
    private Integer menuId;
    private Integer nums;
    private Double money;
    private Integer diningTableId;
    private String billDate;
    private String state;

    public Bill() {
    }

    public Bill(Integer id, String billId, Integer menuId, Integer nums, Double money, Integer diningTableId, String billDate, String state) {
        this.id = id;
        this.billId = billId;
        this.menuId = menuId;
        this.nums = nums;
        this.money = money;
        this.diningTableId = diningTableId;
        this.billDate = billDate;
        this.state = state;
    }

    public Integer getId() {
        return id;
    }

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

    public String getBillId() {
        return billId;
    }

    public void setBillId(String billId) {
        this.billId = billId;
    }

    public Integer getMenuId() {
        return menuId;
    }

    public void setMenuId(Integer menuId) {
        this.menuId = menuId;
    }

    public Integer getNums() {
        return nums;
    }

    public void setNums(Integer nums) {
        this.nums = nums;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    public Integer getDiningTableId() {
        return diningTableId;
    }

    public void setDiningTableId(Integer diningTableId) {
        this.diningTableId = diningTableId;
    }

    public String getBillDate() {
        return billDate;
    }

    public void setBillDate(String billDate) {
        this.billDate = billDate;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    @Override
    public String toString() {
        return  id +
                "\t\t" + menuId +
                "\t\t\t" + nums +
                "\t\t\t" + money +
                "\t" + diningTableId +
                "\t\t" + billDate +
                "\t\t" + state ;
    }
}
2.5.2 DiningTable 类
package com.mhl.domain;

/**
 * 这是一个javabean 和 diningTable 表对应
 * 	id int primary key auto_increment, #自增, 表示餐桌编号
 * 	state varchar(20) not null default '',#餐桌的状态
 * 	orderName varchar(50) not null default '',#预订人的名字
 * 	orderTel varchar(20) not null default ''
 */
public class DiningTable {
    private Integer id;//Integer 防止空指针的问题
    private String state;
    private String orderNmae;
    private String orderTel;

    //无参构造器
    public DiningTable() {
    }

    public DiningTable(Integer id, String state, String orderNmae, String orderTel) {
        this.id = id;
        this.state = state;
        this.orderNmae = orderNmae;
        this.orderTel = orderTel;
    }

    public Integer getId() {
        return id;
    }

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

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getOrderNmae() {
        return orderNmae;
    }

    public void setOrderNmae(String orderNmae) {
        this.orderNmae = orderNmae;
    }

    public String getOrderTel() {
        return orderTel;
    }

    public void setOrderTel(String orderTel) {
        this.orderTel = orderTel;
    }

    //重写toString方法
    public String toString() {
        return id + "\t\t\t" + state;
    }
}
2.5.3 Employee 类
package com.mhl.domain;
/**
 * 这是一个javabean 和 employee对应
 * id int primary key auto_increment, #自增
 * 	empId varchar(50) not null default '',#员工号
 * 	pwd char(32) not null default '',#密码md5
 * 	name varchar(50) not null default '',#姓名
 * 	job varchar(50) not null default '' #岗位
 */
public class Employee {
    private Integer id;
    private String empId;
    private String pwd;
    private String name;
    private String job;

    public Employee() { //无参构造器,底层apache-dbutils反射需要
    }

    public Employee(Integer id, String empId, String pwd, String name, String job) {
        this.id = id;
        this.empId = empId;
        this.pwd = pwd;
        this.name = name;
        this.job = job;
    }

    public Integer getId() {
        return id;
    }

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

    public String getEmpId() {
        return empId;
    }

    public void setEmpId(String empId) {
        this.empId = empId;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public String getName() {
        return name;
    }

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

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }
}
2.5.4 Menu 类
package com.mhl.domain;

/**
 * 该类(javabean)和 menu 表对应
 * id int primary key auto_increment, #自增主键,作为菜谱编号(唯一)
 * name varchar(50) not null default '',#菜品名称
 * type varchar(50) not null default '', #菜品种类
 * price double not null default 0 #价格
 */
public class Menu {
    private Integer id;
    private String name;
    private String type;
    private Double price;

    public Menu() {//无参构造器
    }

    public Menu(Integer id, String name, String type, Double price) {
        this.id = id;
        this.name = name;
        this.type = type;
        this.price = price;
    }

    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 String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Double getPrice() {
        return price;
    }

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

    @Override
    public String toString() {
        return id + "\t\t\t" + name + "\t\t" + type + "\t\t" + price;
    }
}
2.5.5 MultiTableBean 类
package com.mhl.domain;

import java.util.Date;

/**
 * 解决多表查询
 * 这是一个javabean 可以和多张表进行对应
 */
public class MultiTableBean {
    private Integer id;
    private String billId;
    private Integer menuId;
    private Integer nums;
    private Double money;
    private Integer diningTableId;
    private String billDate;
    private String state;
    //增加一个来自menu表的列 name
    //这里的属性名不一定要和表的列名保持一致.
    //但是需要sql做相应的修改, 规范需要保持一致.
    private String name;
    //增加来自menu表的列 price
    private Double price;
    //默认值 null

//    public MultiTableBean() {
//        System.out.println("反射调用....");
//    }

//    public MultiTableBean(Integer id, String billId, Integer menuId, Integer nums, Double money, Integer diningTableId, String billDate, String state, String name, Double price) {
//        this.id = id;
//        this.billId = billId;
//        this.menuId = menuId;
//        this.nums = nums;
//        this.money = money;
//        this.diningTableId = diningTableId;
//        this.billDate = billDate;
//        this.state = state;
//        this.name = name;
//        this.price = price;
//    }

    //给price生成setter 和 getter

    public Double getPrice() {
        return price;
    }

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


    //给name生成setter 和 getter


    public String getName() {
        return name;
    }

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

    public Integer getId() {
        return id;
    }

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

    public String getBillId() {
        return billId;
    }

    public void setBillId(String billId) {
        this.billId = billId;
    }

    public Integer getMenuId() {
        return menuId;
    }

    public void setMenuId(Integer menuId) {
        this.menuId = menuId;
    }

    public Integer getNums() {
        return nums;
    }

    public void setNums(Integer nums) {
        this.nums = nums;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    public Integer getDiningTableId() {
        return diningTableId;
    }

    public void setDiningTableId(Integer diningTableId) {
        this.diningTableId = diningTableId;
    }

    public String getBillDate() {
        return billDate;
    }

    public void setBillDate(String billDate) {
        this.billDate = billDate;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    @Override
    public String toString() {
        return  id +
                "\t\t" + menuId +
                "\t\t\t" + nums +
                "\t\t\t" + money +
                "\t" + diningTableId +
                "\t\t" + billDate +
                "\t\t" + state +
                "\t\t" + name +
                "\t\t" + price;
    }
}

2.6 service包

2.6.1 BillService 类
package com.mhl.service;

import com.mhl.dao.BillDAO;
import com.mhl.dao.MultiTableDAO;
import com.mhl.domain.Bill;
import com.mhl.domain.MultiTableBean;

import java.util.List;
import java.util.UUID;

/**
 * 处理和账单相关的业务逻辑
 */
public class BillService {
    //定义BillDAO属性
    private BillDAO billDAO = new BillDAO();
    //定义MenuService 属性
    private MenuService menuService = new MenuService();
    //定义DiningTableService属性
    private DiningTableService diningTableService = new DiningTableService();

    private MultiTableDAO multiTableDAO = new MultiTableDAO();

    //思考
    //编写点餐的方法
    //1. 生成账单
    //2. 需要更新对应餐桌的状态
    //3. 如果成功返回true, 否则返回false
    public boolean orderMenu(int menuId, int nums, int diningTableId) {
        //生成一个账单号,UUID,随机ID
        String billID = UUID.randomUUID().toString();

        //将账单生成到bill表, 要求直接计算账单金额
        int update = billDAO.update("insert into bill values(null,?,?,?,?,?,now(),'未结账')",
                billID, menuId, nums, menuService.getMenuById(menuId).getPrice() * nums, diningTableId);

        if (update <= 0) {
            return false;
        }

        //需要更新对应餐桌的状态
        return diningTableService.updateDiningTableState(diningTableId, "就餐中");

    }

    //返回所有的账单, 提供给View调用
    public List<Bill> list() {
        return billDAO.queryMulti("select * from bill", Bill.class);
    }

    //返回所有的账单并带有菜品名,价格, 提供给View调用
    public List<MultiTableBean> list2() {
        return multiTableDAO.queryMulti("SELECT bill.*, NAME " +
                "FROM bill, menu " +
                "WHERE bill.menuId = menu.id", MultiTableBean.class);
    }


    //查看某个餐桌是否有未结账的账单
    public boolean hasPayBillByDiningTableId(int diningTableId) {
    //LIMIT 0, 1 限制了查询结果的数量,从第0行开始(实际上就是从第一行开始,因为行数索引从0开始),返回1行。
    //也就是说,即使有多个符合前面条件的记录,这个查询也只给你看第一条这样的记录。
        Bill bill =
                billDAO.querySingle("SELECT * FROM bill WHERE diningTableId=? AND state = '未结账' LIMIT 0, 1", Bill.class, diningTableId);
        return bill != null;
    }

    //完成结账[如果餐桌存在,并且该餐桌有未结账的账单]
    //如果成功,返回true, 失败返回 false
    //payMode结账方式
    public boolean payBill(int diningTableId, String payMode) {

        //1. 修改bill表
        int update = billDAO.update("update bill set state=? where diningTableId=? and state='未结账'", payMode, diningTableId);

        if(update <= 0) { //如果更新没有成功,则表示失败...
            return false;
        }
        //2. 修改diningTable表
        //注意:不要直接在这里操作,而应该调用DiningTableService 方法,完成更新,体现各司其职

        if(!diningTableService.updateDiningTableToFree(diningTableId, "空")) {
            return false;
        }
        return true;

    }

}
2.6.2 DiningTable 类
package com.mhl.service;

import com.mhl.dao.DiningTableDAO;
import com.mhl.domain.DiningTable;

import java.util.List;

public class DiningTableService { //业务层

    //定义一个DiningTableDAO对象
    private DiningTableDAO diningTableDAO = new DiningTableDAO();

    //返回所有餐桌的信息
    public List<DiningTable> list() {

        return diningTableDAO.queryMulti("select id, state from diningTable", DiningTable.class);
    }//返回一个集合

    //根据id , 查询对应的餐桌DiningTable 对象
    //如果返回null , 表示id编号对应的餐桌不存在
    public DiningTable getDiningTableById(int id) {

        //技巧:把sql语句放在查询分析器去测试一下.
        return diningTableDAO.querySingle("select * from diningTable where id = ?", DiningTable.class, id);
    }

    //如果餐桌可以预定,调用方法,对其状态进行更新(包括预定人的名字和电话)
    public boolean orderDiningTable(int id, String orderName, String orderTel) {

        int update =
                diningTableDAO.update("update diningTable set state='已经预定', orderName=?, orderTel=? where id=?", orderName, orderTel, id);

        return  update > 0;//update > 0 表示更新成功
    }

    //需要提供一个更新 餐桌状态的方法
    public boolean updateDiningTableState(int id, String state) {

        int update = diningTableDAO.update("update diningTable set state=? where id=?", state, id);
        return update > 0;
    }

    //提供方法,将指定的餐桌设置为空闲状态
    public boolean updateDiningTableToFree(int id, String state) {

        int update = diningTableDAO.update("update diningTable set state=?,orderName='',orderTel='' where id=?", state, id);
        return update > 0;
    }

}
2.6.3 EmployeeService 类
package com.mhl.service;

import com.mhl.dao.EmployeeDAO;
import com.mhl.domain.Employee;

/**
 * 该类完成对employee表的各种操作(通过调用EmployeeDAO对象完成)
 */
public class EmployeeService {

    //定义一个 EmployeeDAO 属性
    private EmployeeDAO employeeDAO = new EmployeeDAO();

    //方法,根据empId 和 pwd 返回一个Employee对象
    //如果查询不到,就返回null
    //QuerySingle是一个可以从IDbConnection类型的任意对象调用的扩展方法,
    // 它可以执行查询并映射第一个结果,如果序列中没有元素则会引发异常。
    public Employee getEmployeeByIdAndPwd(String empId, String pwd) {

        return employeeDAO.querySingle("select * from employee where empId=? and pwd=md5(?)", Employee.class, empId, pwd);

    }
}
2.6.4 MenuService 类
package com.mhl.service;

import com.mhl.dao.MenuDAO;
import com.mhl.domain.Menu;

import java.util.List;

/**
 * 完成对menu表的各种操作(通过调用MenuDAO)
 */
public class MenuService {

    //定义MenuDAO 属性
    private MenuDAO menuDAO = new MenuDAO();

    //返回所有的菜品, 返回给界面使用
    public List<Menu> list() {
        return menuDAO.queryMulti("select * from menu", Menu.class);
    }

    //需要方法,根据id, 返回Menu对象
    public Menu getMenuById(int id) {
        return menuDAO.querySingle("select * from menu where id = ?", Menu.class, id);
    }
}

2.7 view 包

MHLView
package com.mhl.view;

import com.mhl.domain.DiningTable;
import com.mhl.domain.Employee;
import com.mhl.domain.Menu;
import com.mhl.domain.MultiTableBean;
import com.mhl.service.BillService;
import com.mhl.service.DiningTableService;
import com.mhl.service.EmployeeService;
import com.mhl.service.MenuService;
import com.mhl.utils.Utility;

import java.util.List;
import java.util.UUID;

/**
 * 这是主界面
 */
public class MHLView {

    //控制是否退出菜单
    private boolean loop = true;
    private String key = "";
    //接收用户的选择
    //定义EmployeeService 属性
    private EmployeeService employeeService = new EmployeeService();
    //定义DiningTableService的属性
    private DiningTableService diningTableService = new DiningTableService();
    //定义MenuService属性
    private MenuService menuService = new MenuService();
    //定义BillService属性
    private BillService billService = new BillService();

    public static void main(String[] args) {
        new MHLView().mainMenu();
    }

    //完成结账
    public void payBill() {
        System.out.println("==============结账服务============");
        System.out.print("请选择要结账的餐桌编号(-1退出): ");
        int diningTableId = Utility.readInt();
        if (diningTableId == -1) {
            System.out.println("=============取消结账============");
            return;
        }
        //验证餐桌是否存在
        DiningTable diningTable = diningTableService.getDiningTableById(diningTableId);
        if (diningTable == null) {
            System.out.println("=============结账的餐桌不存在============");
            return;
        }
        //验证餐桌是否有需要结账的账单
        if (!billService.hasPayBillByDiningTableId(diningTableId)) {
            System.out.println("=============该餐位没有未结账账单============");
            return;
        }
        System.out.print("结账方式(现金/支付宝/微信)回车表示退出: ");
        String payMode = Utility.readString(20, "");//说明如果回车,就是返回 ""
        if ("".equals(payMode)) {
            System.out.println("=============取消结账============");
            return;
        }
        char key = Utility.readConfirmSelection();
        if (key == 'Y') { //结账

            //调用我们写的方法
            if (billService.payBill(diningTableId, payMode)) {
                System.out.println("=============完成结账============");
            } else {
                System.out.println("=============结账失败============");
            }

        } else {
            System.out.println("=============取消结账============");
        }
    }

    //显示账单信息
    public void listBill() {
//        List<Bill> bills = billService.list();
//        System.out.println("\n编号\t\t菜品号\t\t菜品量\t\t金额\t\t桌号\t\t日期\t\t\t\t\t\t\t状态");
//        for (Bill bill : bills) {
//            System.out.println(bill);
//        }
//        System.out.println("==============显示完毕============");

        List<MultiTableBean> multiTableBeans = billService.list2();
        System.out.println("\n编号\t\t菜品号\t\t菜品量\t\t金额\t\t桌号\t\t日期\t\t\t\t\t\t状态\t\t\t菜品名\t\t价格");
        for (MultiTableBean bill : multiTableBeans) {
            System.out.println(bill);
        }
        System.out.println("==============显示完毕============");
    }

    //完成点餐
    public void orderMenu() {
        System.out.println("==============点餐服务============");
        System.out.print("请输入点餐的桌号(-1退出): ");
        int orderDiningTableId = Utility.readInt();
        if (orderDiningTableId == -1) {
            System.out.println("==============取消点餐============");
            return;
        }
        System.out.print("请输入点餐的菜品号(-1退出): ");
        int orderMenuId = Utility.readInt();
        if (orderMenuId == -1) {
            System.out.println("==============取消点餐============");
            return;
        }
        System.out.print("请输入点餐的菜品量(-1退出): ");
        int orderNums = Utility.readInt();
        if (orderNums == -1) {
            System.out.println("==============取消点餐============");
            return;
        }

        //验证餐桌号是否存在.
        DiningTable diningTable = diningTableService.getDiningTableById(orderDiningTableId);
        if (diningTable == null) {
            System.out.println("==============餐桌号不存在============");
            return;
        }
        //验证菜品编号
        Menu menu = menuService.getMenuById(orderMenuId);
        if (menu == null) {
            System.out.println("==============菜品号不存在============");
            return;
        }

        //点餐
        if (billService.orderMenu(orderMenuId, orderNums, orderDiningTableId)) {
            System.out.println("==============点餐成功============");
        } else {
            System.out.println("==============点餐失败============");
        }

    }

    //显示所有菜品
    public void listMenu() {
        List<Menu> list = menuService.list();
        System.out.println("\n菜品编号\t\t菜品名\t\t类别\t\t价格");
        for (Menu menu : list) {
            System.out.println(menu);
        }
        System.out.println("==============显示完毕============");
    }

    //完成订座
    public void orderDiningTable() {
        System.out.println("==============预定餐桌============");
        System.out.print("请选择要预定的餐桌编号(-1退出): ");
        int orderId = Utility.readInt();
        if (orderId == -1) {
            System.out.println("==============取消预订餐桌============");
            return;
        }
        //该方法得到的是 Y 或者 N
        char key = Utility.readConfirmSelection();
        if (key == 'Y') {//要预定

            //根据orderId 返回 对应DiningTable对象, 如果为null, 说明该对象不存在
            DiningTable diningTable = diningTableService.getDiningTableById(orderId);
            if (diningTable == null) {//
                System.out.println("==============预订餐桌不存在============");
                return;
            }
            //判断该餐桌的状态是否 "空"
            if (!("空".equals(diningTable.getState()))) {//说明当前这个餐桌不是 "空" 状态
                System.out.println("==============该餐桌已经预定或者就餐中============");
                return;
            }

            //接收预定信息
            System.out.print("预定人的名字: ");
            String orderName = Utility.readString(50);
            System.out.print("预定人的电话: ");
            String orderTel = Utility.readString(50);

            //更新餐桌状态
            if (diningTableService.orderDiningTable(orderId, orderName, orderTel)) {
                System.out.println("==============预订餐桌成功============");
            } else {
                System.out.println("==============预订餐桌失败============");
            }

        } else {
            System.out.println("==============取消预订餐桌============");
        }

    }

    //显示所有餐桌状态
    public void listDiningTable() {
        List<DiningTable> list = diningTableService.list();
        System.out.println("\n餐桌编号\t\t餐桌状态");
        for (DiningTable diningTable : list) {
            System.out.println(diningTable);
        }
        System.out.println("==============显示完毕============");
    }

    //显示主菜单
    public void mainMenu() {

        while (loop) {

            System.out.println("\n===============满汉楼================");
            System.out.println("\t\t 1 登录满汉楼");
            System.out.println("\t\t 2 退出满汉楼");
            System.out.print("请输入你的选择: ");
            key = Utility.readString(1);
            switch (key) {
                case "1":
                    System.out.print("输入员工号: ");
                    String empId = Utility.readString(50);
                    System.out.print("输入密  码: ");
                    String pwd = Utility.readString(50);
                    Employee employee = employeeService.getEmployeeByIdAndPwd(empId, pwd);
                    if (employee != null) { //说明存在该用户
                        System.out.println("===============登录成功[" + employee.getName() + "]================\n");
                        //显示二级菜单, 这里二级菜单是循环操作,所以做成while
                        while (loop) {
                            System.out.println("\n===============满汉楼(二级菜单)================");
                            System.out.println("\t\t 1 显示餐桌状态");
                            System.out.println("\t\t 2 预定餐桌");
                            System.out.println("\t\t 3 显示所有菜品");
                            System.out.println("\t\t 4 点餐服务");
                            System.out.println("\t\t 5 查看账单");
                            System.out.println("\t\t 6 结账");
                            System.out.println("\t\t 9 退出满汉楼");
                            System.out.print("请输入你的选择: ");
                            key = Utility.readString(1);
                            switch (key) {
                                case "1":
                                    listDiningTable();//显示餐桌状态
                                    break;
                                case "2":
                                    orderDiningTable();//完成订座
                                    break;
                                case "3":
                                    listMenu();//显示所有菜品
                                    break;
                                case "4":
                                    orderMenu();//完成点餐
                                    break;
                                case "5":
                                    listBill();//显示所有账单
                                    break;
                                case "6":
                                    payBill();//完成结账
                                    break;
                                case "9":
                                    loop = false;
                                    break;
                                default:
                                    System.out.println("你的输入有误,请重新输入");
                                    break;
                            }
                        }
                    } else {
                        System.out.println("===============登录失败================");
                    }
                    break;
                case "2":
                    loop = false;//
                    break;
                default:
                    System.out.println("你输入有误,请重新输入.");
            }
        }
        System.out.println("你退出了满汉楼系统~");
    }

}


二、设计任务书

姓 名

本课题为完成餐厅管理点餐设计,主要功能包括:

一、登录功能

  1. 员工登录(数据库存储)
  2. 退出登录
  • 点餐功能

1.显示餐桌状态    2.预定餐桌      3.显示所有菜品

4.点餐服务        5.查看账单      6.结账

7.退出程序

完成情况:独立完成

开发工具:IDEA DataGrip

开发语言:Java MySQL

第1周(2024-06-17~2024-06-21):

系统需求分析,模块分层设计,模块分类,分为dao层,domain层,service层,utils层和view层。

第2周(2024-06-24~2024-06-28):

进行编码、测试。撰写报告、系统验收。

原 主始 要资 参料 考与 文  献

餐厅管理点餐系统的设计与实现

摘  要

餐厅管理点餐账单管理系统是为餐厅行业设计的信息化管理平台,旨在通过集成点餐、预定餐桌,查看账单,账单处理等功能,全面提升餐厅运营效率与顾客满意度。

功能实现:

一、登录功能(一级菜单)

1.员工登录满汉楼程序

2.退出登录

二、点餐功能(二级菜单)

1.显示餐桌状态    2.预定餐桌      3.显示所有菜品

4.点餐服务           5.查看账单      6.结账

7.退出程序

业务总体逻辑为:

员工登录—>预定餐桌—>显示菜单—>点菜—>

查看账单—>结账—>员工退出登录

当然有不少细节和逻辑判断,比如说预定餐桌,如果该桌是已预订或者正在用餐,那么这一桌是不可选的。比如说点餐,菜品必须要在菜单内,也不能给不存在的餐桌号点餐,在用餐的餐桌不能被其他用户预定,状态设置为“用餐中”。结账,需要在点餐时生成账单,初始化为“未支付”;结账后更新状态,并且把该餐桌的状态设置为“空”。

第1章 需求分析

1.1业务需求

餐饮管理顾客点餐系统为餐厅点餐服务,使用用户为职工。职工通过该系统对预定,点餐,账单进行管理,方便职工为用餐者提供更好的服务。职工可以查询各个用餐者的用餐信息。

功能需求:

一、登录功能(一级菜单)

1.员工登录满汉楼程序

2.退出登录

二、点餐功能(二级菜单)

1.显示餐桌状态    2.预定餐桌      3.显示所有菜品

4.点餐服务        5.查看账单      6.结账

7.退出程序

1.2员工需求

1.2.1服务员需求:

菜单管理:能够轻松访问和更新菜单,包括菜品的名称、描述、价格。

点餐功能:快速且直观的点餐界面,能够添加、修改或取消订单。

桌位管理:跟踪桌位的状态,如预订、占用、空闲等,并能快速分配桌位。

支付处理:支持多种支付方式,包括现金、支付宝等。

1.2.2收银员需求:

结账速度:快速处理支付,减少顾客等待时间。

结账管理:对账单信息进行核实,查看账单信息。

1.3管理员需求

     员工管理:对员工信息进行录入,设置登录权限。

     系统管理:系统升级与维护。

1.4开发环境

后端开发工具:

IDEA

开发语言:

Java

数据库技术开发工具:

DataGrip

开发语言:

MySQL

第2章 系统设计

2.1总体方案设计

包括软件系统的架构设计,技术方案,模块结构等。

2.2 框架的设计

2.2.1 核心类库libs

如图2.1所示。

图2.1核心类库libs

核心库libs包括:

commons-dbutils-1.3.jar,

druid-1.1.10.jar,

mysql-connector-java-8.0.29.jar。

(1)commons-dbutils-1.3.jar:是Apache Commons项目中的一个Java库,主要用于简化JDBC编程的工作。这个库提供了一组帮助类,可以减少在使用传统JDBC进行数据库操作时的样板代码,提高开发效率并减少潜在的错误。

(2)druid-1.1.10.jar:是Druid数据库连接池的Java库文件。Druid是阿里巴巴开源的一个全面的数据库连接池实现,它不仅仅是一个连接池,还包含监控、过滤、SQL解析等功能。

  1. mysql-connector-java-8.0.29.jar:是MySQL官方提供的Java数据库连接驱动程序,用于在Java应用程序中建立与MySQL数据库的连接并进行通信。

2.2.2 代码分层设计

如图2.2所示。

图2.2

2.2.3 各个的介绍

(1)view层:存放MHLView类,为界面层,是可视化界面,调用service层的类。

(2)service层:

EmployService:

该类完成对employee表的各种操作,对职工信息进行操作(通过调用EmployeeDAO对象完成)。

DiningTableService:

该类完成对diningtable表的各种操作,对餐桌信息进行操作(通过调用DijningTableDAO对象完成)。

MenuService:

该类完成对menu表的各种操作,对菜单信息进行操作(通过调用MenuDAO对象完成)。

BillService:

该类完成对bill表的各种操作,对菜单信息进行操作(通过调用BillDAO对象完成)。

如图2.3所示:

图2.3

  1. dao层:每个Dao对应一个表

BasicDAO:开发BasicDAO,是其他DAO的父类。

如图2.4所示:

图2.4

  1. domain层:

分别与各个表进行对应 如图2.5所示:

图2.5

2.2.4 类关系图

图2.6类关系图

2.3 数据库设计

2.3.1 概念设计

在该系统中,涉及的实体包括员工、餐桌表、菜单表等,它们之间的关系

如图2.7所示。

图2.7 ER图

2.3.2 逻辑设计

1)菜单表 (Menu)

1.id (主键, 自增): 菜品唯一标识

2.name (字符串): 菜品名称

3.type(字符串): 菜品类别(如川菜、粤菜等)

4.price (浮点数): 单价

2)订单表 (Bill)

1.id (主键, 自增): 订单唯一标识

2.billId字符串): 关联顾客表,表示下单顾客

3.menuId(菜品编号):表示顾客点的哪份菜

4.nums(整型):菜品分数

5.billDate (日期时间): 下单日期时间

6.money (浮点数): 订单总金额

7.state (字符串): 订单状态(如待支付、已支付、已取消等)

8.diningTable(整型):餐桌

3)餐桌表 (diningTable)

1.id (主键, 自增): 餐桌编号,餐桌详情唯一标识

2.state (字符串): 餐桌状态

3.orderName(整型): 预定人姓名

4.OrderTel (整): 预定人电话

4)员工表 (Employee)

1.id (主键, 自增): 员工唯一标识

2.empId(整型):员工号

3.pwd(字符串):员工登录密码

4.name (字符串): 员工姓名

5.Job (字符串): 员工职位(如厨师、服务员、经理等)

2.3.3 物理设计

(1)员工表 employee

表3.1 employee表

字段名称

类型

是否主键

备注

Id

Int

员工ID

EmpId

varchar(50)

员工号

Name

varchar(50)

MD5密码

Pwd

char(32)

员工姓名

Job

varchar(50)

员工岗位

(2)餐桌表 diningTable

表3.2 diningTable表

字段名称

类型

是否主键

备注

Id

Int

餐桌编号

State

varchar(20)

餐桌的状态

OrderName

varchar(50)

预定人姓名

OrderTel

char(32)

预定人电话

(3)菜单表 menu

表3. 3 menu表

字段名称

类型

是否主键

备注

Id

Int

菜谱编号

Name

varchar(50)

菜品名称

Type

char(32)

菜品种类

Price

varchar(50)

菜品价格

(4)账单表 bill

表3.4 bill表

字段名称

类型

是否主键

备注

Id

Int

账单ID

BillId

varchar(50)

账单号

MenuId

Int

菜品名称

Nums

Int

分数

Money

Double

金额

diningTableId

int  

餐桌

billDate

datetime   

订单日期

state

varchar(50)

订单状态

第3章 系统实现

3.1前期准备util工具类

JDBCUtilsByDruid:

基于druid数据库连接池的工具类,Druid数据库连接池的Java库文件。Druid是阿里巴巴开源的一个全面的数据库连接池实现,它不仅仅是一个连接池,还包含监控、过滤、SQL解析等功能。

Utility:

工具类,处理各种情况的用户输入,并且能够按照程序员的需求,得到用户的控制台输入。

3.2 MHLVIew-菜单的显示

这是一个简化的控制台应用程序,模拟了一个名为“满汉楼”的餐饮管理系统的主要操作流程。它通过命令行界面与用户交互,允许员工登录系统、执行各种餐厅管理任务,并最终退出系统。下面是对代码逻辑的逐段解释:

3.2.1主循环 

(while (loop) { ... })

整个程序运行在一个大的循环内,由变量loop控制循环是否继续。初始情况下,loop为true,使得程序开始执行并展示主菜单。

3.2.2主菜单

提供两个选项:

(1)登录满汉楼

(2)退出满汉楼

用户输入选项后,程序通过switch语句处理不同的选择。

3.2.3登录逻辑

 (case "1":...)

请求用户输入员工号和密码。

调用employeeService.getEmployeeByIdAndPwd()方法验证员工身份。

如果验证成功(即返回非null的`Employee`对象):

打印登录成功的消息,并显示二级菜单。

在二级菜单的循环中,用户可以执行更多操作,如显示餐桌状态、预定餐桌、查看菜品、点餐、查看账单、结账等。

如果用户选择退出(输入"9"),则关闭二级菜单的循环。

如果登录失败,打印错误消息。

3.2.4二级菜单

列出多项与餐厅运营相关的功能选项,如显示餐桌状态、预定餐桌等。

用户根据提示选择操作,程序根据用户的选择调用相应的方法,如listDiningTable()、orderDiningTable()等。

用户可随时选择退出二级菜单乃至整个程序。

3.2.5退出逻辑

 (case "2":和其他默认情况)

用户选择退出("2")时,将`loop`设为`false`,结束主循环。

对于无效输入,提示用户重新输入。

3.2.6最终输出

当主循环结束时,即用户选择退出满汉楼系统后,打印退出信息。

整个代码示例展示了基本的控制台应用程序架构,包括用户认证、多级菜单导航和简单的业务逻辑处理。通过这个程序,员工可以完成一系列餐厅日常管理操作。

执行效果如3.1所示:

图3.1

3.3 用户登录

系统在使用前需要进行登录,输入账号和密码进行登录,登录成功后才能进行后续的操作。登录流程图如图3.2所示。

图3.2登录流程图

3.3.1创建 Employee 员工表

在数据库中创建employee员工表

3.3.2修改德鲁伊配置文件-src 目录下
#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mhl?rewriteBatchedStatements=true
username=root
password=123456
#initial connection Size
initialSize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=50
#max wait time (5000 mil seconds)
maxWait=5000
3.3.3创建 Employee 类

定义了一个名为Employee的Java类,用于表示员工实体。这个类包含了员工的基本属性以及相应的getter和setter方法。

类声明

定义了一个公开(public)的类Employee。

成员变量

定义了五个私有(private)成员变量,分别代表员工的ID(整型)、员工编号(字符串)、密码(字符串)、姓名(字符串)和职位(字符串)。使用Integer而不是int类型,是为了方便支持数据库中的空值情况。

构造方法

提供了两个构造方法:

无参构造器:这是为了某些框架如Apache DbUtils等反射机制使用的,这些框架在创建对象时可能需要无参数的构造函数。

有参构造器:接收五个参数,用于初始化员工对象的所有字段,提高代码的灵活性和便利性。

Getter和Setter方法

为每个成员变量提供了getter(获取器)和setter(设置器)方法,遵循Java Bean规范。这些方法允许外部代码以受控的方式访问和修改对象的属性。通过getter和setter方法,实现了对内部数据的安全访问控制,而构造方法则提供了实例化对象的不同方式,适应不同的使用场景。

3.3.4创建 EmployeeDAO 子类

这个DAO类将专门用于处理与Employee实体相关的数据库操作。

public class EmployeeDAO:定义了一个公开的类EmployeeDAO。

extends BasicDAO<Employee>:表明EmployeeDAO类继承自BasicDAO泛型类,并指定其操作的实体类型为Employee。BasicDAO提供了一套通用的数据库操作方法(如增删改查)。

EmployeeDAO类作为一个数据访问对象,通过继承泛型的BasicDAO类,专注于实现对Employee实体的数据访问逻辑,同时保留了扩展自定义操作的空间。

3.3.5创建 EmployeeService 类

该类完成对employee表的各种操作(通过调用EmployeeDAO对象完成)

声明了一个私有的EmployeeDAO类型的成员变量employeeDAO,并实例化了该DAO对象。这表明EmployeeService类将依赖EmployeeDAO来进行数据库操作,采用了依赖注入的设计思想,

方法签名:声明了一个公共方法getEmployeeByIdAndPwd,接受员工ID(emp和密码(pwd)两个字符串参数,返回一个Employee对象或null。

SQL查询:方法内部调用了employeeDAO的querySingle方法执行SQL查询。这条SQL旨在从employee表中根据员工ID和经过MD5加密的密码查找匹配的记录。使用占位符,来防止SQL注入攻击,并安全地传递查询参数。

参数说明:

"select * from employee where empId=? and pwd=md5(?)":SQL查询语句,注意pwd=md5(?)表示在数据库中存储的是密码的MD5哈希值。

Employee.class:指定了查询结果应被映射到的Java类,这里是Employee类。

empId 和 pwd:作为查询参数传递给SQL,完成动态值的替换。

返回值:如果找到了匹配的记录,则通过ORM(对象关系映射)技术自动将查询结果转换为Employee对象并返回;如果没有找到匹配记录,根据querySingle的常见行为,可能会直接返回null。

3.3.6在显示层 VIew 调用 EmployeeService 类

循环显示一级菜单:代码开始处于一个while循环中,该循环由变量loop控制,只要loop为true,就会持续显示满汉楼的一级菜单。菜单提供两个选项:“登录满汉楼”和“退出满汉楼”。

用户输入选择:

通过Utility.readString()方法读取用户针对一级菜单的选择,并存储在变量key中。这里readString()意味着只读取一个字符长度的输入,这取决于Utility.readString的具体实现。

处理登录选项:如果用户选择了“登录满汉楼”(即key为"1"),程序会要求用户依次输入工号(empId)和密码(pwd)。

模拟登录过程:

之后,通过调用employeeService.getEmployeeByIdAndPwd(empId, pwd)方法来验证用户输入的工号和密码是否与数据库中的某个员工记录匹配。这里假设employeeService是一个服务类,封装了对数据库的操作,getEmployeeByIdAndPwd方法会根据工号和经过处理的密码查询数据库。

判断登录结果:

如果employee对象不为null,说明数据库中存在匹配的员工记录,即用户输入的工号和密码正确。成功“登录满汉楼”,登录成功后的进一步操作跳转到员工操作界面(二级菜单)。

执行结果如3.3所示:

图3.3

3.4显示餐桌的状态

3.4.1创建 DiningTable 餐桌

在数据库中创建diningTable餐桌表

3.4.2创建 DiningTable 类

成员变量private Integer id;:餐桌的唯一标识符,使用Integer类型而非基本类型int,可以避免空指针异常,因为在数据库操作或某些逻辑中,餐桌ID可能为null。private String state;:餐桌的状态,例如“空闲”、“已预订”或“就餐中”等。

private String orderName;:预订餐桌的顾客姓名。

private String orderTel;:预订餐桌的顾客联系电话。

构造方法无参构造器:public DiningTable() {},这是为了满足某些框架(如ORM框架)的要求,它们可能需要无参数的构造函数来实例化对象。

有参构造器:public DiningTable(Integer id, String state, String orderNmae, String orderTel) {...},用于根据给定的参数初始化餐桌对象的所有属性。

Getter和Setter方法为每个成员变量提供了标准的getter和setter方法,使得外部代码可以访问和修改这些属性,同时保持了封装性。例如,getId()和setId(Integer id)分别用于获取和设置餐桌的ID。

重写toString方法public String toString() {return id + "\t\t\t" + state;}:

覆盖了从Object类继承的toString方法,用于以字符串形式表示餐桌对象。这里只包含了餐桌ID和状态,用制表符分隔,实际应用中可能还需要包含其他属性,以提供更完整的餐桌信息展示。

3.4.3创建 DiningTableDAO 类

定义了一个名为DiningTableDAO的Java类,它继承自一个泛型类BasicDAO,并指定了操作的实体类型为DiningTable。

继承BasicDAO<DiningTable>

泛型的使用:BasicDAO<DiningTable>表示BasicDAO是一个泛型类,它可以应用于任何实体类型。这里特化为DiningTable,DiningTableDAO专门用于处理与DiningTable实体对象相关的数据库操作。继承的目的:通过继承,DiningTableDAO能够复用BasicDAO中定义的通用数据库访问方法,如保存、更新、删除和查询等,这些方法通常对应到数据库的CRUD操作。这样做减少了代码重复,提高了代码的可维护性和扩展性。

3.4.4创建 DiningTableService 类

类定义及成员变量

private DiningTableDAO diningTableDAO = new DiningTableDAO();:

声明并实例化了一个DiningTableDAO对象,用于执行数据库操作。方法解析list()方法:此方法用于查询并返回所有餐桌的信息。通过调用diningTableDAO.queryMulti执行SQL(查询餐桌表中的id和state列),并将结果映射为DiningTable对象列表返回。

getDiningTableById(int id)方法:

根据餐桌ID查询单个餐桌的信息。使用diningTableDAO.querySingle执行SQL(根据ID查询餐桌表),返回匹配的DiningTable对象,若无匹配则返回null。

orderDiningTable(int id, String orderName, String orderTel)方法:

预定餐桌操作。更新指定餐桌的状态为“已经预定”,并记录预定人的名字和电话。通过diningTableDAO.update执行更新SQL,根据返回的受影响行数判断操作是否成功。

updateDiningTableState(int id, String state)方法:

更新餐桌状态。接受餐桌ID和新的状态作为参数,更新餐桌的状态信息。同样根据更新操作影响的行数判断是否成功。

updateDiningTableToFree(int id, String state)方法:

将餐桌设置为空闲状态,并清空预定人的名字和电话。除了更新状态外,还清空了与预定相关的联系信息,确保餐桌回归到初始可用状态。

3.4.5在显示层 VIew 调用DiningTableService 类中的方法

方法定义public void listDiningTable(){}

这是一个公开(public)的方法,没有返回值(void类型),方法名为listDiningTable,意在列出所有餐桌的状态。

获取餐桌列表:

List<DiningTable> list = diningTableService.list();

这里调用了diningTableService对象的list方法,该方法属于DiningTableService类,用于从数据库中查询并返回所有餐桌的信息。查询结果是一个List<DiningTable>集合,其中每个元素都是一个DiningTable对象,代表一张餐桌及其状态。

打印餐桌状态:

System.out.println("\n餐桌编号\t\t餐桌状态");

for(DiningTable diningTable : list){ System.out.println(diningTable);}

首先,打印表头信息:“餐桌编号”和“餐桌状态”,使用制表符\t进行对齐。然后,通过增强for循环(foreach)遍历list中的每一个DiningTable对象。对于每个餐桌,直接调用其toString方法(隐式地),将餐桌编号和状态打印出来。

执行结果如图3.4所示:

图3.4

3.5预订餐桌

在 DiningTableService 类中新增功能

功能流程显示预定餐桌提示:首先打印提示信息,告诉用户即将进入预定餐桌环节。用户选择餐桌编号:请求用户输入想要预定的餐桌编号,提供了一个退出选项(输入-1)。确认预定:调用Utility.readConfirmSelection()方法让用户确认是否继续预定(输入'Y'或'N')。如果用户确认(输入'Y'):

检查餐桌是否存在:

通过调用diningTableService.getDiningTableById(orderId)根据用户选择的餐桌编号获取对应的DiningTable对象。如果餐桌不存在(返回null),则打印提示信息并结束预定流程。

检查餐桌状态:

确认餐桌是否为空闲状态。如果不是空闲(即已被预定或正在使用),则提示用户并结束预定流程。

收集预定信息:

如果餐桌可以预定,程序接着请求用户输入预定人的姓名和电话。

执行预定操作:

最后,调用diningTableService.orderDiningTable(orderId, orderName, orderTel)方法更新数据库中选定餐桌的状态为已预定,并记录预定人的信息。

取消预定:

如果用户在确认时选择不预定(输入'N'),则直接打印取消预定的提示信息。

结束预定流程:

无论预定成功还是取消,都以打印一条结束信息作为流程的收尾。

执行结果如图3.5所示:

图3.5

3.6 显示所有菜品

3.6.1创建 Menu菜品表

在数据库中创建menu菜品表

3.6.2创建 Menu

定义了一个名为Menu的Java类,用于表示餐厅菜单中的菜品信息。

类定义public class Menu {}

声明了一个公开(public)的类Menu,用于封装菜品数据。

成员变量

private Integer id;:菜品的唯一标识符。

private String name;:菜品的名称。

private String type;:菜品的类型或类别,如素菜、荤菜、汤品等。

private Double price;:菜品的价格。

构造方法无参构造器public Menu() {}:默认构造方法,主要用于框架如ORM映射时实例化对象。

带参数的构造器public Menu(Integer id, String name, String type, Double price) {...}:用于初始化菜品的所有属性,便于在创建对象时直接设定值。

Getter和Setter方法为每个成员变量提供了getter和setter方法,以便外部类访问和修改这些属性,同时保持了封装性。

getId()用于获取菜品ID,setPrice(Double price)用于设置菜品价格。重写toString方法@Overridepublic String toString() {return id + "\t\t\t" + name + "\t\t" + type + "\t\t" + price;}重写了从Object类继承的toString方法,返回一个格式化的字符串,用于表示Menu对象的详细信息。这里使用制表符\t来分隔各个属性,使得打印或展示时更加易读。

3.6.3创建菜品 MenuDAO

定义了一个名为MenuDAO的Java类,它继承自一个泛型类BasicDAO,并指定了操作的实体类型为Menu。

继承BasicDAO<Menu>

泛型的使用:BasicDAO<Menu>表示BasicDAO是一个泛型类,它可以应用于任何实体类型。这里特化为Menu,MenuDAO专门用于处理与Menu实体对象相关的数据库操作。继承的目的:通过继承,MenuDAO能够复用BasicDAO中定义的通用数据库访问方法,如保存、更新、删除和查询等,这些方法通常对应到数据库的CRUD操作。这样做减少了代码重复,提高了代码的可维护性和扩展性。

3.6.4创建菜品 MenuService

类定义及成员变量private MenuDAO menuDAO = new MenuDAO();:声明并实例化了一个MenuDAO对象。MenuDAO类负责直接与数据库交互,执行SQL查询、插入、更新和删除等操作。MenuService通过持有这个对象,能够间接操作数据库中的菜单数据。

方法解析

list()方法:

功能:用于获取并返回数据库中所有菜品的列表。实现:调用menuDAO.queryMulti方法,传入SQL查询语句(查询menu表中的所有列)和目标实体类类型Menu.class。此方法执行查询并映射结果集到Menu对象列表,然后返回这个列表给调用者。这通常是用于填充界面菜单列表的数据。

getMenuById(int id)方法:

功能:根据菜品ID查询并返回对应的Menu对象。实现:通过调用menuDAO.querySingle方法,传入根据ID查询单个菜品的SQL语句、Menu.class以及菜品ID作为参数。此方法执行SQL查询并期望返回唯一结果,如果找到匹配的菜品,则返回一个Menu对象;如果未找到,则根据querySingle的实现可能返回null。这个方法适用于需要展示或修改特定菜品信息的场景。

3.6.5在显示层 VIew 调用 菜品 Serive 方法

    通过执行 List<Menu> list = menuService.list();来调用MenuService方法

执行结果如图3.6所示:

图3.6

3.7 点餐服务

3.7.1创建账单 Bill 账单

在数据库中创建menu菜品表

3.7.2创建 Bill

类定义与属性

Bill类代表一个账单对象,包含了账单的各项基本信息。

成员变量包括账单ID (id)、账单编号 (billId)、菜品ID (menuId)、数量 (nums)、金额 (money)、餐桌ID (diningTableId)、账单日期 (billDate) 以及账单状态 (state)。

使用Integer和Double类型来存储ID、数量和金额,这样可以支持null值,适合数据库映射。

构造方法

提供了无参构造器 public Bill() { },这是为了满足某些框架(如ORM框架)的需要,它们在实例化对象时可能需要无参数的构造函数。

带参数的构造器 public Bill(...),用于一次性初始化账单对象的所有属性,提高代码的简洁性和效率。

Getter和Setter方法

为每个成员变量提供了getter和setter方法,遵循JavaBean规范,使得外部类可以访问和修改这些属性,同时保持了对象的封装性。

重写toString方法

@Override public String toString() 方法被重写,用于以字符串形式展示账单信息,便于调试和打印。这里将账单的各个属性以固定格式拼接成字符串,方便查看。

3.7.3创建 BillBAO

定义了一个名为BillDAO的Java类,它继承自一个泛型类BasicDAO,并指定了操作的实体类型为Bill。

继承BasicDAO<Bill>

泛型的使用:BasicDAO<Bill>表示BasicDAO是一个泛型类,它可以应用于任何实体类型。这里特化为Bill,BillDAO专门用于处理与Bill实体对象相关的数据库操作。继承的目的:通过继承,BillDAO能够复用BasicDAO中定义的通用数据库访问方法,如保存、更新、删除和查询等。

3.7.4创建 BillService 类

属性定义

BillDAO billDAO: 用于执行与账单数据表相关的数据库操作。

MenuService menuService: 提供菜单项相关的服务,例如获取菜品价格。

DiningTableService diningTableService: 管理餐桌状态的服务,如更新餐桌状态。

MultiTableDAO multiTableDAO: 用于执行涉及多表查询的操作。

orderMenu

功能:点餐逻辑,包括生成账单、更新餐桌状态。

步骤:

生成唯一的账单ID(使用UUID)。

插入新账单到数据库,同时计算总金额(通过调用menuService获取菜品单价乘以数量)。更新餐桌状态为“就餐中”(通过diningTableService)。

返回值:操作成功返回true,否则false。

List()

功能:查询所有账单并返回账单列表。

实现:直接调用billDAO查询账单表所有记录。

list2()

功能:查询所有账单,并附带菜品名和价格信息。

实现:通过多表联查(账单表和菜单表)获取更详尽的信息,返回一个包含额外信息的MultiTableBean列表。

hasPayBillByDiningTableId

功能:检查指定餐桌是否有未结账的账单。

实现:查询账单表中对应餐桌ID且状态为“未结账”的记录是否存在,存在则返回true。

payBill

功能:完成账单结账,包括更新账单状态和餐桌状态。

步骤:

更新账单状态为给定的结账方式(如“现金”,“支付宝”等)。

调用diningTableService更新餐桌状态为“空”(表示可用)。

返回值:整个结账过程成功返回true,否则false。

执行结果如图3.7所示:

图3.7

3.8 查看账单

注释掉了原始的账单信息打印方式,该方式直接调用billService.list()获取账单列表,并以简单的表格形式打印账单的基本信息(编号、菜品号、菜品量、金额、桌号、日期、状态)。这种方式不包含菜品名称。

调用billService.list2()方法来获取账单信息,这个方法返回的列表包含了账单与菜品关联的信息,即List<MultiTableBean>。MultiTableBean类可能设计用来封装来自多个表(如账单表和菜品表)的数据,以便于联合展示。

打印表头信息,与之前不同的是,在原有的基础上增加了“菜品名”这一列,以便展示每条账单所对应的菜品名称。

使用增强型for循环遍历multiTableBeans列表。对于列表中的每一个MultiTableBean对象(代表一条账单记录),调用其toString()方法(隐式调用)打印账单的详细信息,现在包括了菜品名。

最后,打印一条分割线“===========显示完毕===========”来标记账单列表输出的结束,使得输出更加清晰易读。

执行结果如图3.8所示:

图3.8

3.9 结账

开始结账服务提示:首先,输出提示信息,告知用户即将开始结账服务。

用户选择餐桌编号:请求用户输入欲结账的餐桌编号,允许用户输入-1来退出结账流程。

验证餐桌存在性:根据用户输入的餐桌编号,

调用diningTableService.getDiningTableById(diningTableId)检查餐桌是否存在。

如果餐桌不存在,则提示并结束结账流程。

检查餐桌是否有未结账账单:即使餐桌存在,还需确认该餐桌是否有未结账的账单,通过调用billService.hasPayBillByDiningTableId(diningTableId)方法进行检查。如果没有未结账账单,也会提示并结束流程。

询问结账方式:

如果餐桌有未结账账单,程序会要求用户输入结账方式(现金、支付宝、微信),允许用户直接回车退出结账流程。

确认结账:

用户输入结账方式后,程序再次确认用户是否确定结账,通过调用Utility.readConfirmSelection()读取用户确认选择('Y' 表示确认,其他键表示取消)。

执行结账操作:

如果用户确认结账,调用billService.payBill(diningTableId, payMode)方法尝试完成结账操作。此方法根据餐桌ID和结账方式更新账单状态。如果结账成功,即方法返回true,则输出结账成功的提示;如果结账失败或用户在任一环节取消操作,会相应地输出取消结账的消息。

执行结果如图3.9所示:

图3.9

4章 总结

心得体会与遇到的挑战:

在满汉楼项目的Java开发过程中,我深刻体会到了理论知识与实践结合的重要性。起初,面对复杂的业务需求和数据关系,我感到有些手足无措。特别是数据库逻辑设计阶段,如何有效映射实体关系到数据库表结构,同时确保数据的一致性和高效访问,对我而言是一大挑战。通过不断查阅资料、询问同学及老师的悉心指导,我逐渐掌握了ER图转换为关系模型的技巧,理解了规范化的重要性,并学会了如何使用数据库连接池。

另外,我也学会了在编写项目时要对系统进行分层,提高代码的阅读性,使其在以后的更改中更加便捷。对于各个部分应该各司其职,例如:在BillService账单操作中需要更改餐桌的状态,这时就可以在BillService中直接调用DiningService,在DiningService中进行编辑。在这一过程极大地提升了我的问题解决能力和技术实践水平。

课题完成情况:

我认为本课题已经较好完成。我成功实现了餐厅管理点餐系统的核心功能,包括:

登录功能(一级菜单)

1.员工登录满汉楼程序

2.退出登录

  • 点餐功能(二级菜单)

1.显示餐桌状态    2.预定餐桌      3.显示所有菜品

4.点餐服务        5.查看账单      6.结账

7.退出程序

同时系统能够流畅地处理日常的餐饮服务流程,提高了餐厅的运营效率。尽管在项目开发后期遇到了一些多表查询,java与数据库中数据类型不匹配上的难题,但我通过建立新的类MultiTableBean来关联所有表,改变数据类型,有效缓解了这些问题。不过,仍有一些扩展功能,如查看员工的详细信息,顾客线上点餐等功能,更加美观的可视化界面,因时间限制未能深入实施,这是后续可以继续完善的地方。

未来展望与自我要求:

展望未来,我期望能进一步深化在Java、微服务架构以及大数据处理方面的技能,以便在后续项目中能更加游刃有余。我计划通过自学,掌握Spring Boot、Vue以及分布式系统设计原理,以提升系统的可扩展性和健壮性。同时,我也意识交流与沟通的重要性,未来将更加注重提升自己的协作能力,成为一名能独立解决问题技术领导者。

致谢:

在此,我要衷心感谢在项目中给予我无私帮助的每一位同学。你们的智慧火花和不懈努力,是我能够克服重重难关的重要动力。特别感谢我的老师,您的专业指导和耐心解答,让我在遇到技术瓶颈时总能找到方向,您的鼓励和支持是我坚持下去的重要力量。没有大家的共同努力,就不会有项目的成功实施。谢谢大家,这段经历将是我学习生涯中宝贵的财富。

参考文献

评分

课堂表现(20%)

答辩部分(40%)

技术报告(40%)

总评

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/780889.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SAP_MM模块-特殊业务场景下的系统实现方案

一、业务背景 目前公司有一种电商业务&#xff0c;卖的是备品配件&#xff0c;是公司先跟供应商采购&#xff0c;然后再销售给客户&#xff0c;系统账就是按照正常业务来流转&#xff0c;公司进行采购订单入库&#xff0c;然后销售订单出库。 不过这种备品配件&#xff0c;实…

Android使用http加载自建服务器静态网页

最终效果如下图&#xff0c;成功加载了电脑端的静态网页内容&#xff0c;这是一个xml文件。 电脑端搭建http服务器 使用“Apache Http Server”&#xff0c;下载地址是&#xff1a;https://httpd.apache.org/download.cgi。具体操作步骤&#xff0c;参考&#xff1a;Apache …

卫星IoT产品发展前景

卫星IoT产品发展前景 一、概述 卫星IoT产品是指利用卫星通信技术实现物联网设备互联互通的解决方案。随着卫星互联网技术的快速发展&#xff0c;卫星IoT产品正逐渐成为解决偏远地区、海洋、航空等场景下物联网连接问题的重要手段。 二、性能特点 广泛覆盖&#xff1a; 卫星…

ssrf结合redis未授权getshell

目录 漏洞介绍 SSRF Redis未授权 利用原理 环境搭建 利用过程 rockylinux cron计划任务反弹shell 写公钥免密登录 ubuntu 写公钥免密登录 漏洞介绍 SSRF SSRF&#xff08;server side request forgrey&#xff09;服务端请求伪造&#xff0c;因后端未过滤用户输入&…

SpringBoot实现多数据源切换

1. 概述 仓库地址&#xff1a;https://gitee.com/aopmin/multi-datasource-demo 随着项目规模的扩大和业务需求的复杂化&#xff0c;单一数据源已经不能满足实际开发中的需求。在许多情况下&#xff0c;我们需要同时操作多个数据库&#xff0c;或者需要将不同类型的数据存储在不…

陶建辉当选 GDOS 全球数据库及开源峰会荣誉顾问

近日&#xff0c;第二十三届 GOPS 全球运维大会暨 XOps 技术创新峰会在北京正式召开。本次会议重点议题方向包括开源数据库落地思考、金融数据库自主可控、云原生时代下数据库、数据库智能运维、数据库安全与隐私、开源数据库与治理。大会深入探讨这些方向&#xff0c;促进了数…

Matplotlib 学习

知识点 1.plot()&#xff1a;用于绘制线图和 散点图scatter() 函数&#xff1a;plot() 函数可以接受许多可选参数&#xff0c;用于控制图形的外观&#xff0c;例如&#xff1a;颜色: colorblue 控制线条的颜色。线型: linestyle-- 控制线条的样式&#xff0c;例如虚线。标记…

前端vue后端java使用easyexcel框架下载表格xls数据工具类

一 使用alibaba开源的 easyexcel框架&#xff0c;后台只需一个工具类即可实现下载 后端下载实现 依赖 pom.xml <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependen…

昇思25天学习打卡营第12天|FCN图像语义分割

文章目录 昇思MindSpore应用实践基于MindSpore的FCN图像语义分割1、FCN 图像分割简介2、构建 FCN 模型3、数据预处理4、模型训练自定义评价指标 Metrics 5、模型推理结果 Reference 昇思MindSpore应用实践 本系列文章主要用于记录昇思25天学习打卡营的学习心得。 基于MindSpo…

机械键盘有哪些分类

机械键盘是一种比传统的薄膜键盘更耐用、更快捷、更具有手感的键盘。它的键帽和按键是独立的&#xff0c;能够提供更好的反应速度和操作感。机械键盘在现代化生活中得到了广泛的应用。根据其特性和使用场景&#xff0c;机械键盘可以分为以下几类&#xff1a; 1.轴体分类 机械…

永磁同步电机控制算法--最大转矩电流比控制(虚拟信号注入法)

目前&#xff0c;国内外相关学者对 MTPA 控制方法进行了一系列的理论研究与仿真分析。通过研究取得的成果综合来看&#xff0c;该控制方法主要有&#xff1a;直接公式计算法、曲线拟合法、查表法、搜索法、高频信号注入法以及参数辨识法等。 之前的文章中已经介绍了直接公式计…

柯桥小语种学校成人生活口语学习|西班牙语中H为什么不发音…

01 H en el alfabeto espaol 西语字母表中的h 字母H是唯一一个在标准西班牙语中不再代表任何音素的字母。尽管在它单独出现时被叫做HACHE&#xff0c;但在大多数单词拼写中&#xff0c;它只是一个没有声音对应关系的字母&#xff0c;因此RAE称其为“无声的H”&#xff08;hac…

昇思25天学习打卡营第4天|MindSpore数据集和数据变换

# 打卡 目录 # 打卡 Dateset&#xff1a;Pipeline 的起始 具体步骤 数据处理 Pipeline 代码例子 内置数据集的情况 自定义数据集的情况 可迭代的数据集 生成器 Transforms&#xff1a;数据预处理 代码例子 通用变换Compose 文本变换 Text Lambda变换 Dateset&…

ExtruOnt——为工业 4.0 系统描述制造机械类型的本体

概述 论文地址 &#xff1a;https://arxiv.org/abs/2401.11848 原文地址&#xff1a;https://ai-scholar.tech/articles/ontology/ExtruOnt 在工业 4.0 应用场景中&#xff0c;以机器可解释代码提供的、语义丰富的制造机械描述可以得到有效利用。然而&#xff0c;目前显然还缺…

【开源项目】LocalSend 局域网文件传输工具

【开源项目】LocalSend 局域网文件传输工具 一个免费、开源、跨平台的局域网传输工具 LocalSend 简介 LocalSend 是一个免费的开源跨平台的应用程序&#xff0c;允许用户在不需要互联网连接的情况下&#xff0c;通过本地网络安全地与附近设备共享文件和消息。 项目地址&…

​RAG与LLM原理及实践(8)--- Chroma 应用场景及限制

前言 通过前面几节的介绍&#xff0c;你应该对Chroma的运作原理有相当透彻的理解。Chroma的设计正如之前描述的&#xff1a; Chroma提供的工具&#xff1a; 存储文档数据和它们的元数据&#xff1a;store embeddings and their metadata 嵌入&#xff1a;embed documents an…

.mkp勒索病毒:深度解析与防范

引言&#xff1a; 在数字化时代&#xff0c;网络安全问题日益严峻&#xff0c;其中勒索病毒作为一种极具破坏性的恶意软件&#xff0c;严重威胁着个人用户和企业机构的数据安全。在众多勒索病毒家族中&#xff0c;.mkp勒索病毒以其强大的加密能力和广泛的传播方式&#xff0c;成…

Amesim中删除计算结果保存计算文件

前言 Amesim在工程应用中计算的结果文件有时会很大&#xff0c;为了节省电脑存储空间&#xff0c;项目结束后可以将计算结果删除进行保存以存档。 操作步骤 具体操作步骤如下&#xff1a; Step1&#xff1a;在①File下打开&#xff08;Open&#xff09;需要删除计算结果的项…

PyQt5开发笔记:2. 2D与3D散点图、水平布局和边框修饰

一、装pyqtgraph和PyOpenGL库 pip install pyqtgraph pip install PyOpenGL 注意&#xff1a;一定不要pip install OpenGL&#xff0c;否则会找不到 二、3D散点图效果 import pyqtgraph as pg import pyqtgraph.opengl as gl import numpy as np# 创建应用程序 app pg.mkQ…

《机器学习》读书笔记:总结“第4章 决策树”中的概念

&#x1f4a0;决策树 基于树结构进行决策。 一棵决策树包括&#xff1a; 一个 根节点&#xff08;起点&#xff09;若干 叶节点&#xff08;没有下游节点的节点&#xff09;若干 内部节点(分支节点) 即&#xff1a; #mermaid-svg-Mxe3d0kNg29PM2n8 {font-family:"treb…