一、代码详解
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.预定餐桌 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.员工登录满汉楼程序
2.退出登录
二、点餐功能(二级菜单)
1.显示餐桌状态 2.预定餐桌 3.显示所有菜品
4.点餐服务 5.查看账单 6.结账
7.退出程序
1.2.1服务员需求:
菜单管理:能够轻松访问和更新菜单,包括菜品的名称、描述、价格。
点餐功能:快速且直观的点餐界面,能够添加、修改或取消订单。
桌位管理:跟踪桌位的状态,如预订、占用、空闲等,并能快速分配桌位。
支付处理:支持多种支付方式,包括现金、支付宝等。
1.2.2收银员需求:
结账速度:快速处理支付,减少顾客等待时间。
结账管理:对账单信息进行核实,查看账单信息。
员工管理:对员工信息进行录入,设置登录权限。
系统管理:系统升级与维护。
后端开发工具:
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解析等功能。
- mysql-connector-java-8.0.29.jar:是MySQL官方提供的Java数据库连接驱动程序,用于在Java应用程序中建立与MySQL数据库的连接并进行通信。
如图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
- dao层:每个Dao对应一个表
BasicDAO:开发BasicDAO,是其他DAO的父类。
如图2.4所示:
图2.4
- 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%) | 总评 |