java零基础Ⅲ-- 6.满汉楼项目
需求说明
要完成的满汉楼项目说明
满汉楼项目功能多,界面复杂,设及到复杂的awt 和 swing 技术 和事件编程,做如下调整
1、去掉界面和事件处理(工作中使用很少),使用控制台界面
2、完成满汉楼项目的 登录、订座、点餐和结账、查看账单 等功能
3、提示:在实际工作中,独立完成项目的新功能非常重要,这是锻炼编程能力和思想的重要途径
界面设计
用户登录
显示餐桌状态
预定
显示菜品
点餐
查看账单
结账
功能实现
准备工具类 Utility,提高开发效率,并搭建 项目的整体结构
项目结构:
添加依赖包到项目中:
在实际开发中,公司都会通过相应的工具类和开发库,可以提高开关效率
Utility工具类
package com.zzpedu.mhl.utils;
import java.util.Locale;
import java.util.Scanner;
/**
* 工具类的作用:
* 处理各种情况用户的输入,并且能够按照程序员的需求,得到用户的控制台输入
*/
public class Utility {
//静态属性...
private static Scanner scanner = new Scanner(System.in);
/**
* 功能:读取键盘输入的一个菜单选项,值:1--6的范围
* @return 1--6
*/
public static char readMenuSelection(){
char c;
for(; ;){
String str = readKeyBoard(1,false);//包含一个字符串
c = str.charAt(0);//将字符串转换成字符char类型
if(c != '1' && c != '2' &&
c != '3' && c != '4' && c != '5' && c != '6'){
System.out.println("选择错误,请重新输入(1-6):");
}else break;
}
return c;
}
/**
* 功能:读取键盘输入的一个字符
* @return 一个字符
*/
public static char readChar(){
String str = readKeyBoard(1,false);//就是一个字符
return str.charAt(0);
}
/**
* 功能:读取键盘输入的一个字符,如果直接按回车,则返回指定的默认值
* @param defaultValue 指定的默认值
* @return 默认值或者输入的字符
*/
public static char readChar(char defaultValue){
String str = readKeyBoard(1,true);//要么是空字符串,要么就是一个字符
return (str.length() == 0) ? defaultValue : str.charAt(0);
}
/**
* 功能:读取键盘输入的整型,长度小于2
* @return
*/
public static int readInt(){
int n = 0;
for (; ;){
String str = readKeyBoard(10,false);//一个整数,长度小于10位
try {
n = Integer.parseInt(str);//将字符串转成整数
break;
}catch (NumberFormatException e){
System.out.println("数字输入错误,请重新输入:");
}
}
return n;
}
/**
* 功能:读取键盘输入的 整数或者默认值,如果直接按回车,则返回指定的默认值,否则返回整数
* @param defaultValue 指定的默认值
* @return 整数或者默认值
*/
public static int rendInt(int defaultValue){
int n;
for (; ;){
String str = readKeyBoard(10,true);
if(str.equals("")){
return defaultValue;
}
//异常处理...
try {
n = Integer.parseInt(str);
break;
}catch (NumberFormatException e){
System.out.println("数字输入错误,请重新输入:");
}
}
return n;
}
/**
* 功能:读取键盘输入的指定长度的字符串
* @param limit 限制的长度
* @return 指定长度的字符串
*/
public static String readString(int limit){
return readKeyBoard(limit,false);
}
/**
* 功能:读取键盘输入的指定长度的字符串或者默认值,如果直接回车,则返回给定的默认值
* @param limit 限制的长度
* @param defaultValue 指定的默认值
* @return 指定长度的字符串
*/
public static String readString(int limit,String defaultValue){
String str = readKeyBoard(limit,true);
return str.equals("") ? defaultValue : str;
}
/**
* 功能:读取键盘输入的确定选项,Y或者N
* 将小的功能,封装到一个方法中
* @return Y或N
*/
public static char readConfirmSelection(){
System.out.print("确认是否预定(Y/N): ");
char c;
for(; ;){//无限循环
//在这里,将接受到字符,转成大写字母
//y => Y n => N
String str = readKeyBoard(1,false).toUpperCase(Locale.ROOT);
c = str.charAt(0);
if(c == 'Y' || c == 'N'){
break;
}else {
System.out.print("选择错误,请重新输入(Y/N): ");
}
}
return c;
}
/**
* 功能:读取键盘输入的字符串指定长度
* @param limit 指定长度
* @param flag 状态
* true:代表可以为空字符串
* false:不能为空字符串
* @return 字符串
*/
private static String readKeyBoard(int limit, boolean flag) {
String str = "";
do {
//nextLine():
//1.以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
//2.可以获得空白。
str = scanner.nextLine();
if(str.length() == 0){
if(flag) return str;//如果flag=true,可以返回空字符串
else continue;//如果flag=false,不接受空字符串,必须输入内容
}
//如果用户输入的内容大于了 limit ,就提示输入
//如果用户输入的内容 >0 <= limit,就返回退出
if (str.length() < 1 || str.length() > limit){
System.out.print("输入长度(不能大于" + limit +")错误,请重新输入:");
}else {
return str;
}
}while (true);
}
}
druid数据库连接池的工具类
package com.zzpedu.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 dataSource;
//在静态代码块完成 dataSource初始化
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src//druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//编写getConnection方法
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//关闭连接,强调:在数据库连接池技术中,close 不是真的断掉数据库连接
//而是把使用的Connection放回连接池
public static void close(ResultSet set, Statement statement,Connection connection){
//判断是否为null
try {
if(set != null){
set.close();
}
if(statement != null){
statement.close();
}
if(connection != null){
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
druid配置文件druid.properties 存放在 src目录下
#key=value
# 驱动名称
driverClassName=com.mysql.jdbc.Driver
# url数据库地址
url=jdbc:mysql://localhost:3306/mhl?useUnicode=true&characterEncoding=utf8&serverTimezone=PRC&useSSL=false&rewriteBatchedStatements=true
# 用户名
username=root
# 密码
password=123456
#initial connection Size
# 初始化连接数
initialSize=10
#min idle connection size
# 最小连接数(空闲数)
minIdle=5
#max active connection size
# 最大连接数
maxActive=50
#max wait time (5000 mil seconds)
# 最大等待时间5s(超时时间)
maxWait=5000
BasicDAO,是其他DAO的父类
package com.zzpedu.mhl.dao;
import com.zzpedu.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);
}
}
}
显示主菜单,二级菜单和退出系统功能
主界面:
package com.zzpedu.mhl.view;
import com.zzpedu.mhl.utils.Utility;
/**
* 这是主界面
*/
public class MHLView {
//控制是否退出菜单
private boolean loop = true;
//接收用户的输入
private String key = "";
public static void main(String[] args) {
new MHLView().mainMenu();
}
//显示主菜单方法
public void mainMenu(){
while (loop){
System.out.println("==============满汉楼==============");
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 id = Utility.readString(50);
System.out.print("输入密 码: ");
String pwd = Utility.readString(50);
//到数据库去判断【一会写】
if("123".equals(pwd)){
System.out.println("==============登录成功==============\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":
System.out.println("显示餐桌状态");
break;
case "2":
System.out.println("预定餐桌");
break;
case "3":
System.out.println("显示所以菜品");
break;
case "4":
System.out.println("点餐服务");
break;
case "5":
System.out.println("查看账单");
break;
case "6":
System.out.println("结账");
break;
case "9":
loop = false;
break;
default:
System.out.println("你输入有误,请求重新输入");
}
}
}else {
System.out.println("==============登录失败==============");
}
break;
case "2":
loop = false;
break;
default:
System.out.println("你输入有误,请求重新输入");
}
}
System.out.println("您退出了满汉楼系统~");
}
}
创建员工表信息
-- 创建满汉楼数据库
create database mhl;
-- 创建表 employee 表 (主键id,empId,name,pwd,job等,如果还有需要可以自己加字段)
create table employee(
id int primary key AUTO_INCREMENT, # 自增
empId varchar(50) unique null null default '', # 员工号
pwd char(32) null null default '', # 密码md5
`name` varchar(50) null null default '', # 姓名
job varchar(50) null null default '' # 岗位
)charset=utf8;
# 添加测试数据
insert into employee values (null,'6668612',md5('123456'),'张三丰','经理');
insert into employee values (null,'6668622',md5('123456'),'小龙女','服务员');
insert into employee values (null,'6668633',md5('123456'),'张无忌','收银员');
insert into employee values (null,'666',md5('123456'),'zzp','经理');
select * from employee;
domain层:
package com.zzpedu.mhl.domain;
/**
* 这是一个javabean 和 employee对应
*/
public class Employee {
private Integer id;
private String empId;
private String pwd;
private String name;
private String job;
public Employee() {//无参构造器,底层apache-dbutils反射需要
}
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; }
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", empId='" + empId + '\'' +
", pwd='" + pwd + '\'' +
", name='" + name + '\'' +
", job='" + job + '\'' +
'}';
}
}
dao层
package com.zzpedu.mhl.dao;
import com.zzpedu.mhl.domain.Employee;
/**
* EmployeeDAO
*/
public class EmployeeDAO extends BasicDAO<Employee> {
//这里还可以特有的操作
}
service层:
package com.zzpedu.mhl.service;
import com.zzpedu.mhl.dao.EmployeeDAO;
import com.zzpedu.mhl.domain.Employee;
/**
* 该类完成对employee表的各种操作(通过调用EmployeeDAO对象完成)
*/
public class EmployeeService {
//定义一个 EmployeeDAO属性
private EmployeeDAO employeeDAO = new EmployeeDAO();
//方法,根据empId 和 pwd 返回一个Employee对象
//如果查询不到,返回null
public Employee getEmployeeByIdAndPwd(String id,String pwd){
return employeeDAO.querySingle("select * from employee where empId=? and pwd=md5(?)",
Employee.class, id, pwd);
}
}
view层:
修改MHLView类,添加用户登录判断
/**
* 这是主界面
*/
public class MHLView {
//定义一个 EmployeeService属性
private EmployeeService employeeService = new EmployeeService();
public static void main(String[] args) {
new MHLView().mainMenu();
}
//显示主菜单方法
public void mainMenu(){
while (loop){
....
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){
......
}
}
显示餐桌状态
创建餐桌表
-- 创建 diningTable 餐桌表(id,state,orderName,orderTel)
create table 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 '' # 预定人的手机号
) charset=utf8;
# 测试数据
insert into diningTable values (null,'空','','');
insert into diningTable values (null,'空','','');
insert into diningTable values (null,'空','','');
select * from diningTable;
domain层
package com.zzpedu.mhl.domain;
/**
* 这是一个javabean 和 diningTable表对应
*/
public class DiningTable {
private Integer id;
private String state;
private String orderName;
private String orderTel;
public DiningTable() {
}
public DiningTable(Integer id, String state, String orderName, String orderTel) {
this.id = id;
this.state = state;
this.orderName = orderName;
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 getOrderName() { return orderName; }
public void setOrderName(String orderName) { this.orderName = orderName; }
public String getOrderTel() { return orderTel; }
public void setOrderTel(String orderTel) { this.orderTel = orderTel; }
@Override
public String toString() {
return id + "\t\t\t" + state;
}
}
dao层
package com.zzpedu.mhl.dao;
import com.zzpedu.mhl.domain.DiningTable;
/**
* DiningTableDAO
*/
public class DiningTableDAO extends BasicDAO<DiningTable>{
//这里还可以特有的操作,可以写在 DiningTableDAO
}
service层
package com.zzpedu.mhl.service;
import com.zzpedu.mhl.dao.DiningTableDAO;
import com.zzpedu.mhl.domain.DiningTable;
import java.util.List;
/**
* 该类完成对diningTable表的各种操作(通过调用DiningTableDAO对象完成)
*/
public class DiningTableService {//业务层
//定义一个 DiningTableDAO 对象
private DiningTableDAO diningTableDAO = new DiningTableDAO();
//返回所有餐桌的信息
public List<DiningTable> list(){
return diningTableDAO.queryMulti("select id,state from diningTable",DiningTable.class);
}
}
view层:
修改MHLView类,添加显示所有餐桌状态功能
package com.zzpedu.mhl.view;
import com.zzpedu.mhl.domain.DiningTable;
import com.zzpedu.mhl.domain.Employee;
import com.zzpedu.mhl.service.DiningTableService;
import com.zzpedu.mhl.service.EmployeeService;
import com.zzpedu.mhl.utils.Utility;
import java.util.List;
/**
* 这是主界面
*/
public class MHLView {
...
//定义一个 DiningTableService属性
private DiningTableService diningTableService = new DiningTableService();
//显示所有餐桌状态
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("\n==============显示完毕==============");
}
//显示主菜单方法
public void mainMenu(){
while (loop){
System.out.println("==============满汉楼==============");
...
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==============满汉楼二级菜单==============");
....
switch (key){
case "1":
listDiningTable();//显示餐桌状态
break;
.....
}
执行效果:
订座
功能说明:如果该订餐桌处于已经预定或者就餐状态,给出提示
分析:(1)要检查餐桌是否存在 (2)要检查餐桌的状态
在DiningTableService类,添加查询,更新方法
/**
* 该类完成对diningTable表的各种操作(通过调用DiningTableDAO对象完成)
*/
public class DiningTableService {//业务层
//定义一个 DiningTableDAO 对象
private DiningTableDAO diningTableDAO = new DiningTableDAO();
....
//根据id查询对应餐桌 DiningTable对象
//如果返回null,表示id编号对应的餐桌不存在
public DiningTable getDiningTableById(int id){
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;
}
}
view层:
修改MHLView类,添加完成订座方法
/**
* 这是主界面
*/
public class MHLView {
...
//定义一个 DiningTableService属性
private DiningTableService diningTableService = new DiningTableService();
//完成订座
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 diningTableById = diningTableService.getDiningTableById(orderId);
if(diningTableById == null){
System.out.println("==============预定餐桌不存在==============");
return;
}
//判断该餐桌状态是否 “空”
if(!"空".equals(diningTableById.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 mainMenu(){
while (loop){
System.out.println("==============满汉楼==============");
...
switch (key){
case "1":
....
while (loop){
System.out.println("\n==============满汉楼二级菜单==============");
.....
switch (key){
case "1":
listDiningTable();//显示餐桌状态
break;
case "2":
orderDiningTable();
break;
......
}
}
执行效果:
显示菜品
创建菜谱表
-- 创建 meun(菜谱)表(id,name,trpe,price)
create table menu(
id int primary key auto_increment, # 自增主键,作为菜谱编号(唯一)
`name` varchar(50) not null default '', # 菜谱名称
type varchar(12) not null default '', # 菜谱种类
price double not null default 0 # 价格
)charset=utf8;
# 测试数据
insert into menu values (null,'八宝饭','主食',10);
insert into menu values (null,'叉烧包','主食',20);
insert into menu values (null,'宫保鸡丁','热菜',30);
insert into menu values (null,'山药拨鱼','凉菜',14);
insert into menu values (null,'银丝卷','甜食',9);
insert into menu values (null,'水煮鱼','热菜',26);
insert into menu values (null,'甲鱼汤','汤类',100);
insert into menu values (null,'鸡蛋汤','汤类',16);
select * from menu;
domain层
package com.zzpedu.mhl.domain;
/**
* 这是一个javabean 和 menu表对应
*/
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;
}
}
dao层
package com.zzpedu.mhl.dao;
import com.zzpedu.mhl.domain.Menu;
/**
* MenuDAO
*/
public class MenuDAO extends BasicDAO<Menu>{
}
service层
package com.zzpedu.mhl.service;
import com.zzpedu.mhl.dao.MenuDAO;
import com.zzpedu.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);
}
}
view层:
修改MHLView类,添加 显示所有菜品方法
package com.zzpedu.mhl.view;
import com.zzpedu.mhl.domain.DiningTable;
import com.zzpedu.mhl.domain.Employee;
import com.zzpedu.mhl.domain.Menu;
import com.zzpedu.mhl.service.DiningTableService;
import com.zzpedu.mhl.service.EmployeeService;
import com.zzpedu.mhl.service.MenuService;
import com.zzpedu.mhl.utils.Utility;
import java.util.List;
/**
* 这是主界面
*/
public class MHLView {
//定义一个 MenuService属性
private MenuService menuService = new MenuService();
....
//显示所有菜品
public void listMenu(){
System.out.println("\n菜品编号\t\t菜品名\t\t类别\t\t价格");
List<Menu> list = menuService.list();
for(Menu menu : list){
System.out.println(menu);
}
System.out.println("==============显示完毕==============");
}
//显示主菜单方法
public void mainMenu(){
while (loop){
System.out.println("==============满汉楼==============");
....
key = Utility.readString(1);
switch (key){
case "1":
....
while (loop){
System.out.println("\n==============满汉楼二级菜单==============");
switch (key){
case "1":
listDiningTable();//显示餐桌状态
break;
case "2":
orderDiningTable();
break;
case "3":
listMenu();
break;
....
}
执行效果:
点餐
功能说明:要求对 餐桌号,菜品编号,做出合理性效验,如果不合理,给出提示信息
思路分析:(1) 餐桌号,菜品编号 效验 (2)点餐成功,需要修改餐桌状态 (3)生成账单
创建bill账单表
-- 增加表 bill 账单表(id,billId,menu,nums,billDate,money,state,diningTableId)
# 账单流水,考虑可以分开结账,并考虑将来分别统计各个不同菜品的销售情况
create table 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(24) not null default '' # 状态 '未结账' '已经结账' '挂单' '现金' '支付宝' '坏账'
)charset=utf8;
select * from bill;
domain层
package com.zzpedu.mhl.domain;
import java.util.Date;
/**
* 这是一个javabean 和 bill表对应
*/
public class Bill {
private Integer id;
private String billId;
private Integer menuId;
private Integer nums;
private Double money;
private Integer diningTableId;
private Date billDate;
private String state;
public Bill() {
}
public Bill(Integer id, String billId, Integer menuId, Integer nums, Double money, Integer diningTableId, Date 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 Date getBillDate() { return billDate; }
public void setBillDate(Date billDate) { this.billDate = billDate; }
public String getState() { return state; }
public void setState(String state) { this.state = state; }
}
dao层
package com.zzpedu.mhl.dao;
import com.zzpedu.mhl.domain.Bill;
/**
* BillDAO
*/
public class BillDAO extends BasicDAO<Bill>{
}
service层
package com.zzpedu.mhl.service;
import com.zzpedu.mhl.dao.BillDAO;
import java.util.UUID;
/**
* 该类完成对bill表的各种操作(通过调用BillDAO对象完成) 处理和账单相关的业务逻辑
*/
public class BillService {
//定义一个 BillDAO 对象
private BillDAO billDAO = new BillDAO();
//定义 MenuService属性
private MenuService menuService = new MenuService();
//定义 DiningTableService属性
private DiningTableService diningTableService = new DiningTableService();
//思考:
//编写点餐的方法
//1. 生成账单
//2. 对应餐桌的状态
//3. 如果成功返回true,否则返回false
public boolean orderMenu(int menuId,int nums,int diningTaleId){
//生成一个账单号,UUID
String billId = UUID.randomUUID().toString();
//将账单生成到bill表,要求直接计算账单金额
int update = billDAO.update("insert into bill values (null,?,?,?,?,?,now(),'未结账')",
billId, menuId, nums, menuService.getMenuById(menuId).getPrice() * nums, diningTaleId);
if(update <= 0){
return false;
}
//需要更新对应的餐桌状态
return diningTableService.updateDiningTableState(diningTaleId,"就餐中");
}
}
MenuService类,添加查询方法
/**
* 该类完成对menu表的各种操作(通过调用MenuDAO对象完成)
*/
public class MenuService {
//定义 MenuDAO属性
private MenuDAO menuDao = new MenuDAO();
....
//需要方法,根据id,返回Menu对象
public Menu getMenuById(int id){
return menuDao.querySingle("select * from menu where id=?",Menu.class,id);
}
}
DiningTableService类,添加更新方法
/**
* 该类完成对diningTable表的各种操作(通过调用DiningTableDAO对象完成)
*/
public class DiningTableService {//业务层
//定义一个 DiningTableDAO 对象
private DiningTableDAO diningTableDAO = new DiningTableDAO();
....
//需要提供一个更新 餐桌状态的方法
public boolean updateDiningTableState(int id,String state){
int update =
diningTableDAO.update("update diningTable set state=? where id=?", state,id);
return update > 0;
}
}
view层:
修改MHLView类,添加点餐方法
/**
* 这是主界面
*/
public class MHLView {
....
//定义一个 BillService属性
private BillService billService = new BillService();
//完成订餐
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 diningTableById = diningTableService.getDiningTableById(orderDiningTableId);
if(diningTableById == null){
System.out.println("==============餐桌号不存在==============");
return;
}
//验证菜品编号
Menu menuById = menuService.getMenuById(orderMenuId);
if(menuById == null){
System.out.println("==============菜品号不存在==============");
return;
}
//点餐
if(billService.orderMenu(orderMenuId, orderNums, orderDiningTableId)){
System.out.println("==============点餐成功==============");
}else {
System.out.println("==============点餐失败==============");
}
}
....
//显示主菜单方法
public void mainMenu(){
while (loop){
System.out.println("==============满汉楼==============");
...
switch (key){
case "1":
System.out.print("输入员工号: ");
...
if(employee != null){
System.out.println("==============登录成功[" + employee.getName() + "]==============\n");
//显示二级菜单,这里二级菜单是循环操作,所以做成while
while (loop){
System.out.println("\n==============满汉楼二级菜单==============");
...
switch (key){
case "1":
listDiningTable();//显示餐桌状态
break;
case "2":
orderDiningTable();
break;
case "3":
listMenu();
break;
case "4":
orderMenu();
break;
....
}
}
执行效果:
查看账单
domian层
Bill类,重写toString()方法
/**
* 这是一个javabean 和 bill表对应
*/
public class Bill {
....
@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;
}
}
service层
BillService类,添加查询所有账单方法
/**
* 该类完成对bill表的各种操作(通过调用BillDAO对象完成) 处理和账单相关的业务逻辑
*/
public class BillService {
//定义一个 BillDAO 对象
private BillDAO billDAO = new BillDAO();
.....
//返回所有的账单,提供View调用
public List<Bill> list(){
return billDAO.queryMulti("select * from bill",Bill.class);
}
}
view层
修改MHLView类,添加显示所有账单方法
/**
* 这是主界面
*/
public class MHLView {
...
//定义一个 BillService属性
private BillService billService = new BillService();
//显示账单信息
public void listBill(){
System.out.println("\n编号\t\t菜品号\t\t菜品量\t\t金额\t\t桌号\t\t日期\t\t\t\t\t\t\t状态");
List<Bill> allBills = billService.list();
for (Bill bill : allBills) {
System.out.println(bill);
}
System.out.println("==============显示完毕==============");
}
//显示主菜单方法
public void mainMenu(){
while (loop){
System.out.println("==============满汉楼==============");
...
switch (key){
case "1":
...
if(employee != null){
System.out.println("==============登录成功[" + employee.getName() + "]==============\n");
//显示二级菜单,这里二级菜单是循环操作,所以做成while
while (loop){
System.out.println("\n==============满汉楼二级菜单==============");
...
switch (key){
...
case "5":
listBill();//显示所有账单
break;
....
}
}
结账
思路分析:(1)对餐桌号进行效验 (2)修改bill表状态state (3)修改diningTable信息 (4)不需要增加新表,不需要增加新的类,需要增加方法
service层:
在BillService类,添加两个方法
/**
* 该类完成对bill表的各种操作(通过调用BillDAO对象完成) 处理和账单相关的业务逻辑
*/
public class BillService {
//定义一个 BillDAO 对象
private BillDAO billDAO = new BillDAO();
//定义 DiningTableService属性
private DiningTableService diningTableService = new DiningTableService();
...
//查看某个餐桌是否有未结账的账单
public boolean hasPayBillByDiningTableId(int diningTableId){
Bill bill =
billDAO.querySingle("select * from bill where diningTableId=? and state='未结账' limit 0, 1",
Bill.class, diningTableId);
return bill != null;
}
//完成结账[如果餐桌存在,并且该餐桌有未结账的账单]
//如果成功,返回true,失败返回false
public boolean payBill(int diningTableId,String payMode){
//如果这里使用事务的话,需要用ThreadLocal来解决,框架中比如:mybatis 提供了事务支持
//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 true;
}
return false;
}
}
在DiningTableService类,添加方法
/**
* 该类完成对diningTable表的各种操作(通过调用DiningTableDAO对象完成)
*/
public class DiningTableService {//业务层
//定义一个 DiningTableDAO 对象
private DiningTableDAO diningTableDAO = new DiningTableDAO();
...
//提供方法,将指定的餐桌设置为空闲状态
public boolean updateDiningTableToFree(int id,String state){
int update =
diningTableDAO.update("update diningTable set state=?,orderName='',orderTel='' where id=?", state,id);
return update > 0;
}
}
view层:
修改MHLView类,添加结账方法:
package com.zzpedu.mhl.view;
import com.zzpedu.mhl.domain.Bill;
import com.zzpedu.mhl.domain.DiningTable;
import com.zzpedu.mhl.domain.Employee;
import com.zzpedu.mhl.domain.Menu;
import com.zzpedu.mhl.service.BillService;
import com.zzpedu.mhl.service.DiningTableService;
import com.zzpedu.mhl.service.EmployeeService;
import com.zzpedu.mhl.service.MenuService;
import com.zzpedu.mhl.utils.Utility;
import java.util.List;
/**
* 这是主界面
*/
public class MHLView {
...
//定义一个 DiningTableService属性
private DiningTableService diningTableService = new DiningTableService();
//定义一个 BillService属性
private BillService billService = new BillService();
//完成结账
public void payBill(){
System.out.println("==============结账服务==============");
System.out.print("请选择要结账的餐桌编号(-1退出): ");
int diningTableId = Utility.readInt();
if(diningTableId == -1){
System.out.println("==============取消结账==============");
return;
}
//验证餐桌号是否存在
DiningTable diningTableById = diningTableService.getDiningTableById(diningTableId);
if(diningTableById == 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 mainMenu(){
while (loop){
System.out.println("==============满汉楼==============");
...
switch (key){
case "1":
...
if(employee != null){
System.out.println("==============登录成功[" + employee.getName() + "]==============\n");
//显示二级菜单,这里二级菜单是循环操作,所以做成while
while (loop){
System.out.println("\n==============满汉楼二级菜单==============");
...
switch (key){
..
case "6":
payBill();
break;
....
}
}
执行效果:
满汉楼 - 扩展思考
思考1:如果 多表查询 怎么处理?比如:查看账单时,希望显示菜品名称,怎么办? =>> 给出思路:https://www.pianshen.com/article/48341042440/
domain层
package com.zzpedu.mhl.domain;
import java.util.Date;
/**
* 这是一个javabean,可以多张表进行对应
*/
public class MultiTableBean {
//bill表字段
private Integer id;
private String billId;
private Integer menuId;
private Integer nums;
private Double money;
private Integer diningTableId;
private Date billDate;
private String state;
//增加一个来自menu表的列
//思考 这里的属性名是否一定要和表列名保持一致
// 解决:可以不一致,可以sql语句使用别名
private String name2;
private Double price;//默认值为null
public MultiTableBean() {
System.out.println("反射调用的....");
}
//getter setter方法...
@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" + name2 + "\t\t" + price;
}
}
dao层
package com.zzpedu.mhl.dao;
import com.zzpedu.mhl.domain.MultiTableBean;
/**
* MultiTableDAO
*/
public class MultiTableDAO extends BasicDAO<MultiTableBean>{
}
service层
在BillService添加查询方法
package com.zzpedu.mhl.service;
import com.zzpedu.mhl.dao.BillDAO;
import com.zzpedu.mhl.dao.MultiTableDAO;
import com.zzpedu.mhl.domain.Bill;
import com.zzpedu.mhl.domain.MultiTableBean;
import java.util.List;
import java.util.UUID;
/**
* 该类完成对bill表的各种操作(通过调用BillDAO对象完成) 处理和账单相关的业务逻辑
*/
public class BillService {
//定义 MultiTableDAO属性
private MultiTableDAO multiTableDAO = new MultiTableDAO();
...
//返回所有的账单并带有菜品名称,提供View调用
public List<MultiTableBean> list2(){
return multiTableDAO.queryMulti("select bill.*, name as name2,price from bill,menu where bill.menuId = menu.id",MultiTableBean.class);
}
}
view层
修改MHLView类的listBill方法
/**
* 这是主界面
*/
public class MHLView {
....
//显示账单信息
public void listBill(){
// System.out.println("\n编号\t\t菜品号\t\t菜品量\t\t金额\t\t桌号\t\t日期\t\t\t\t\t\t\t状态");
// List<Bill> allBills = billService.list();
// for (Bill bill : allBills) {
// System.out.println(bill);
// }
// System.out.println("==============显示完毕==============");
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价格");
List<MultiTableBean> allBills = billService.list2();
for (MultiTableBean bill : allBills) {
System.out.println(bill);
}
System.out.println("==============显示完毕==============");
}
}
执行效果:
思考2:员工信息字段可能有很多,而且员工数也会很多,为提高效率,可以采用 分表设计 employee 和 login