JDBC阶段项目--满汉楼
- 技术概括
满汉楼界面
去除界面设计,使用控制台界面
- 项目介绍
就是一个 点餐项目,
满汉楼只是一个名字,就是高级饭店的名字,
本项目不是界面的,是采用命令行的.
涉及到的技术:
javase+jdbc+mysql+druid+apache-dbutils工具类
- 各个界面演示
满汉楼分层设计
- 项目框架图
由DAO层和数据库进行交互
界面层会调用service层(业务层)(根据实际情况来增加业务层相应的类),业务层调用DAO层
为什么要分层?
各司其职
对于软件分层的理解
- 1.软件分层是逻辑概念
- 2.可以用不同包来存放对应的类
- 3.体现了一个调用的关系,可以各司其职
满汉楼工具类
将每一层存储在一个包中
将需要到的jar包拷贝到我们的项目中(mysql+durid+dbtuils),并将其导入到我们的工程中
将utility(用于处理用户输入)和JDBCutilsByDruid工具类(处理连接数据库)的工具类拷贝到utils包下面,将前面写的BasicDAO拷贝到新的项目下面
将druid需要的配置文件复制过来,复制到新的项目中文件可能会失效(识别为了文本文件),重写文件类型就可以了
我们将将一些其他代码的类导入到新的项目中,最好新建一个测试类测试一下测试一下导入 的类是否存在问题
满汉楼的菜单(完成界面层view)
写项目先写框架然后写细节
应该当我们登录成功了满汉楼系统(一级菜单),输入正确的员工号和密码进行才能进入到二级菜单
这里的look属性可以同时控制2个菜单
在这个步骤中我们完成主菜单和二级菜单(完成大致框架即可,其他后面完成)
满汉楼登录
在数据库中进行登录验证
我们在分析的时候(代码调用的时候)是从下往上。而我们在写代码的时候,从最下层往最上层写
我们在进行登录验证的时候(在数据库中验证),肯定要先创建一张员工表,每张表对应一个DAO。然后一层一层往上写。
- 创建employee表
CREATE DATABASE mhl-- 创建满汉楼数据库
USE mhl-- 将数据库转换成mhl
-- 创建员工表
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,-- 主键且自增
empId VARCHAR(50)unique NOT NULL DEFAULT '',-- 员工号
pwd CHAR(32) NOT NULL DEFAULT '',-- 密码md5
NAME VARCHAR(50)NOT NULL DEFAULT '',-- 姓名
job VARCHAR(50) NOT 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,'6668666',MD5('123456'),'老韩','经理')
SELECT * FROM employee
- 创建employee表对应的javaBean类
因为我们具体的业务都需要在业务层中进行调用,所有我们需要将需要对employee表的操作都写出来(从最底层到业务层)
我们注意将配置文件中的数据库换成新的数据库
完成在菜单中的登录功能。登录功能需要调用业务层中的实现功能---->实现业务层。而业务层需要调用下一层中的功能实现。依次需要完成。1.创建所需要的表和数据库2.完成表所对应的javaBean类(一张表对应一个类)3.完成表对应的DAO类(继承自BasicDAO类)4.完成该表对应的服务层类EmployeeService
满汉楼餐桌
从最底层分析起:应该有一个表diningtable,然后有该表对应的javaBean类,然后还需要有该表对应的DAO,然后还有业务层类
- 餐桌表的创建
-- 创建餐桌表
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,'空','','')
然后需要创建该表所对应的domin类
然后创建该表对应的DAO类
还需要创建该表对应的Serviece层,用于调用DAO
分析:需要显示餐桌的状态,需要先1.创建一个餐桌表2.进而创建对应的JavaBean3.然后创建该表对应的DAO类4.然后创建该表的Serveice类(自下往上分析)
满汉楼订桌1(完成业务层中的获取餐桌和更新状态)
我们在写sql语句的时候,可以将我们写的sql,放在myqll查询分析器中执行一些,封装sql语句写错了
满汉楼订桌2(完成view层中的具体订餐工作)
该不完成view层中对于业务层的调用即可,业务逻辑较为简单
显示菜品
- 创建菜单表menu并添加测试数据
-- 创建菜单表
CREATE TABLE 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#价格
)CHARSET =utf8;
SELECT * FROM menu
-- 添加测试数据
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
- 创建和menu表对应的javaBean类
- 创建该表对应的DAO(负责对该表进行操作)
- 书写Serviece层
- 书写界面层对业务层进行调用
也可以单独设计一张表表示,菜品的类别
满汉楼点餐1
和涉及多张表
在点餐的时候,生成账单
- 实现分析
需要创建一个bill账单表,然后创建其它对应的Bill类,然后创建其DAO类和Service类
-- 创建bill账单表
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(50)NOT NULL DEFAULT ''-- 账单状态(未结账 已经结账 挂单等)
)CHARSET = utf8
- 账单效果
满汉楼点餐2
我们的各个Service之间可以相互协作来完成一个功能,通过在这个Service里面定义另一个service的属性来完成
各个业务层各司其职,只做针对自己这张表的工作
- 思路分析
按照一层一层的往上写,将界面层放在最后
满汉楼账单
问题:餐桌号=为什么显示Null
试错档案:由于在Domin类中的类型刚刚开始没有和表中的类型对应,造成了后面不知名的错误
注意:在Bill中bill表中的Datatime使用String来对应
满汉楼结账1
满汉楼结账2
满汉楼多表处理
如果我们需要显示下面的全新格式的账单(包含菜品名),我们该怎么样处理?
方案一:我们可以将多张表的字段映射成一个名为MultTableBean的javaBean,并并提供其对应的MultTableBeanDAO类,但是提不提供Service类,看业务需求。DAO主要是提供给其他的Service类使用
我们需要重点考虑:多表查询之后的返回结果是什么东西:他可能返回的不是一个单独表的对象,而是一个混合属性的对象。所有这种情况下我们需要重构我们的javaBean类
解决具有菜品名的新账单
如果我们还想再账单中加上价格的话,只用再MultiTableBean中加上相应的映射字段就可以了
如果我们javaBean类中的一些属性,在查询的时候,该字段不要求显示,select的时候会将该字段显示为Null,不影响程序的运行。其实就是在生成集合的时候
其中对象的属性默认值就是为null
我们在查询的时候,其实在底层是通过反射调用我们的无参构造和setter方法,来生成我们的javaBean类对象,并包装成对应的集合的。不需要调用我们javaBean类的有参构造,所有说javaBean类的有参构造可以不需要
表中有4条记录,所有需要调用4次无参构造,生成了4个javaBean类对象
将来字段越来越多,该怎么处理?
**拆分成不同的多表Bean
满汉楼多表细节2
我们的javaBean类在映射表的时候,属性名是不是要和列名保存一致?
需要保持一致。因为在底层在封装查询的到结果的时候 ,是根据列名找到该表对应的javaBean类中对应的set列名方法,将该表的记录封装成对象的。当列名和属性名不一致,则无法进行赋值,而使用默认赋值为null,到时候将会显示为Null
当我们的javaBean类是映射多个表的信息,当多个表中有相同名称的列名,在映射的时候该怎样处理呢?
在不修改表的情况下(不修改列名)可以在查询的时候,将该列名设置别名,在封装的时候,将默认调用和别名一样的setter方法(属性也要改成别名)
满汉楼的拓展功能
功能拓展1:登录改进思路
功能拓展2
建议实现:完成登录管理,人事管理
完整代码部分
dao包
- BasicDAO
package com.hspedu.mhl.dao;
import com.hspedu.mhl.utils.JDBCUtilsByDluid;
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 queryRunner = new QueryRunner();//用于执行sql
//通用的DML方法(返回所影响的行数)
//适用于任意表
//parames:表示传入的?的具体值
public int update(String sql, Object... parames) {//这里连接的获取放在在函数里面比较好
Connection connection = null;
try {
connection = JDBCUtilsByDluid.getConnection();
final int affectedRow = queryRunner.update(connection, sql, parames);//可变参数本质是数组
return affectedRow;
//执行sql
} catch (SQLException e) {
throw new RuntimeException(e);
}
//在update方法的内部,connection resultSet preparedStatement都已经被关闭
}
//查询的结果返回多个对象(即返回多行结果,使用List包装)
//适用于任意表
/*
参数解释:
clazz:表示传入一个类的Class对象,比如Actor.class
params:传入?的具体值
返回对应的ArrayList集合
*/
public List<T> queryMulti(String sql, Class<T> clazz, Object... params) {
Connection connection = null;
try {
connection = JDBCUtilsByDluid.getConnection();
final List<T> list = queryRunner.query(connection, sql, new BeanListHandler<T>(clazz), params);
return list;//返回一个List集合
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//返回单行结果的通用方法(返回一个javaBean对象 )
public T querySingle(String sql, Class<T> clazz, Object... params) {
Connection connection = null;
try {
connection = JDBCUtilsByDluid.getConnection();
T t = queryRunner.query(connection, sql, new BeanHandler<T>(clazz), params);
return t;//返回一个javaBean对象
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//返回单行单列,返回一个单值
//因为是返回一个单值不需要封装,所有不用传入Class对象
public Object queryScalar(String sql,Object...parames){
Connection connection = null;
try {
connection = JDBCUtilsByDluid.getConnection();
Object object = queryRunner.query(connection, sql, new ScalarHandler<>(), parames);
return object;//返回任意一个单值
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
- BillDAO
package com.hspedu.mhl.dao;
import com.hspedu.mhl.domin.Bill;
public class BillDAO extends BasicDAO<Bill>{//此处指定父类泛型类型
//这里可以写特有的方法
}
- DiningTableDAO
package com.hspedu.mhl.dao;
import com.hspedu.mhl.domin.DiningTable;
public class DiningTableDAO extends BasicDAO<DiningTable>{//此时指定父类的泛型
//如果有特殊的操作可以写在DiningTableDAO中
}
- EmployeeDAO
package com.hspedu.mhl.dao;
import com.hspedu.mhl.domin.Employee;
public class EmployeeDAO extends BasicDAO<Employee>{//指定父类的泛型
//这里可以写特有操作
}
- MenuDAO
package com.hspedu.mhl.dao;
import com.hspedu.mhl.domin.Menu;
public class MenuDAO extends BasicDAO<Menu>{//此时指定父类的泛型
//这里可以添加特有操作
}
- MultiTableBeanDAO
package com.hspedu.mhl.dao;
import com.hspedu.mhl.domin.MultiTableBean;
public class MultiTableBeanDAO extends BasicDAO<MultiTableBean>{//这里指定泛型
}
domin包
- Bill
package com.hspedu.mhl.domin;
//和bill(账单表)表对应的javaBean类
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;
}
/**
* 获取
* @return id
*/
public Integer getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取
* @return billId
*/
public String getBillId() {
return billId;
}
/**
* 设置
* @param billId
*/
public void setBillId(String billId) {
this.billId = billId;
}
/**
* 获取
* @return menuId
*/
public Integer getMenuId() {
return menuId;
}
/**
* 设置
* @param menuId
*/
public void setMenuId(Integer menuId) {
this.menuId = menuId;
}
/**
* 获取
* @return nums
*/
public Integer getNums() {
return nums;
}
/**
* 设置
* @param nums
*/
public void setNums(Integer nums) {
this.nums = nums;
}
/**
* 获取
* @return money
*/
public Double getMoney() {
return money;
}
/**
* 设置
* @param money
*/
public void setMoney(Double money) {
this.money = money;
}
/**
* 获取
* @return diningTableId
*/
public Integer getDiningTableId() {
return diningTableId;
}
/**
* 设置
* @param diningTableId
*/
public void setDiningTableId(Integer diningTableId) {
this.diningTableId = diningTableId;
}
/**
* 获取
* @return billDate
*/
public String getBillDate() {
return billDate;
}
/**
* 设置
* @param billDate
*/
public void setBillDate(String billDate) {
this.billDate = billDate;
}
/**
* 获取
* @return state
*/
public String getState() {
return state;
}
/**
* 设置
* @param state
*/
public void setState(String state) {
this.state = state;
}
public String toString() {
return id+"\t\t\t"
+menuId+"\t\t\t"
+nums+"\t\t\t"
+money+"\t\t"
+diningTableId+"\t\t"
+billDate+"\t\t\t\t"+state;
}
}
- DiningTable
package com.hspedu.mhl.domin;
//diningTable所对应的javaBean类
public class DiningTable {
private Integer id;//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;
}
/**
* 获取
* @return id
*/
public Integer getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取
* @return state
*/
public String getState() {
return state;
}
/**
* 设置
* @param state
*/
public void setState(String state) {
this.state = state;
}
/**
* 获取
* @return orderName
*/
public String getOrderName() {
return orderName;
}
/**
* 设置
* @param orderName
*/
public void setOrderName(String orderName) {
this.orderName = orderName;
}
/**
* 获取
* @return orderTel
*/
public String getOrderTel() {
return orderTel;
}
/**
* 设置
* @param orderTel
*/
public void setOrderTel(String orderTel) {
this.orderTel = orderTel;
}
public String toString() {
return id+"\t\t\t"+state;
}
}
- Employee
package com.hspedu.mhl.domin;
//这是一个javaBean类和employee表对应(数据类型建议都使用类)
public class Employee {
private Integer id;//id
private String empId;//员工编号
private String pwd;//密码
private String name;//姓名
private String job;//工作
public Employee() {
}
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;
}
/**
* 获取
* @return id
*/
public Integer getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取
* @return empId
*/
public String getEmpId() {
return empId;
}
/**
* 设置
* @param empId
*/
public void setEmpId(String empId) {
this.empId = empId;
}
/**
* 获取
* @return pwd
*/
public String getPwd() {
return pwd;
}
/**
* 设置
* @param pwd
*/
public void setPwd(String pwd) {
this.pwd = pwd;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return job
*/
public String getJob() {
return job;
}
/**
* 设置
* @param job
*/
public void setJob(String job) {
this.job = job;
}
public String toString() {
return "Employee{id = " + id + ", empId = " + empId + ", pwd = " + pwd + ", name = " + name + ", job = " + job + "}";
}
}
- Menu
package com.hspedu.mhl.domin;
//menu表所对应的JavaBean类
public class Menu {
private Integer id;//菜品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;
}
/**
* 获取
* @return id
*/
public Integer getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return type
*/
public String getType() {
return type;
}
/**
* 设置
* @param type
*/
public void setType(String type) {
this.type = type;
}
/**
* 获取
* @return price
*/
public Double getPrice() {
return price;
}
/**
* 设置
* @param price
*/
public void setPrice(Double price) {
this.price = price;
}
public String toString() {
return id+"\t\t\t"+name+"\t\t"+type+"\t\t"+price;
}
}
- MultiTableBean
package com.hspedu.mhl.domin;
//这是一个javaBean类,可以和多张表进行映射(包含bill和menu表)
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;//账单状态
private String name;//菜品名称(来自menu表)
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) {
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;
}*/
/**
* 获取
* @return id
*/
public Integer getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取
* @return billId
*/
public String getBillId() {
return billId;
}
/**
* 设置
* @param billId
*/
public void setBillId(String billId) {
this.billId = billId;
}
/**
* 获取
* @return menuId
*/
public Integer getMenuId() {
return menuId;
}
/**
* 设置
* @param menuId
*/
public void setMenuId(Integer menuId) {
this.menuId = menuId;
}
/**
* 获取
* @return nums
*/
public Integer getNums() {
return nums;
}
/**
* 设置
* @param nums
*/
public void setNums(Integer nums) {
this.nums = nums;
}
/**
* 获取
* @return money
*/
public Double getMoney() {
return money;
}
/**
* 设置
* @param money
*/
public void setMoney(Double money) {
this.money = money;
}
/**
* 获取
* @return diningTableId
*/
public Integer getDiningTableId() {
return diningTableId;
}
/**
* 设置
* @param diningTableId
*/
public void setDiningTableId(Integer diningTableId) {
this.diningTableId = diningTableId;
}
/**
* 获取
* @return billDate
*/
public String getBillDate() {
return billDate;
}
/**
* 设置
* @param billDate
*/
public void setBillDate(String billDate) {
this.billDate = billDate;
}
/**
* 获取
* @return state
*/
public String getState() {
return state;
}
/**
* 设置
* @param state
*/
public void setState(String state) {
this.state = state;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
public String toString() {
return id+"\t\t\t"
+menuId+"\t\t\t"
+nums+"\t\t\t"
+money+"\t\t"
+diningTableId+"\t\t"
+billDate+"\t\t\t\t"+state
+"\t\t"+name;
}
}
service包
- BillService
package com.hspedu.mhl.service;
import com.hspedu.mhl.dao.BillDAO;
import com.hspedu.mhl.dao.MultiTableBeanDAO;
import com.hspedu.mhl.domin.Bill;
import com.hspedu.mhl.domin.MultiTableBean;
import java.util.List;
import java.util.UUID;
/*
业务层:处理和账单bill相关的业务
*/
public class BillService {
//定义BillDAO属性
private BillDAO billDAO = new BillDAO();
//定义MultiTableBeanDAO属性
MultiTableBeanDAO multiTableBeanDAO = new MultiTableBeanDAO();
//定义一个MenuService属性
private MenuService menuService = new MenuService();
//定义一个DiningTableService的的属性
DiningTableService diningTableService = new DiningTableService();
/*
编写点餐的方法:
1.需要生成账单
2.需要更新餐桌的状态
3.成功返回true 失败返回false
*/
public boolean orderMenu(int menuId,int nums,int diningTableId){
/*
id自增即可
billId使用UUID生成
money金额需要获取单价然后计算得出
billDate使用now()
*/
//1.获取账单号
final String billId = UUID.randomUUID().toString();
//我们需要在MenuService中提供获取对应菜品编号单价的业务
//我们根据MenuService对象调用MenuService中的服务
//生成账单
final int update = billDAO.update("insert into bill values(null,?,?,?,?,?,now(),'未结账')",
billId, menuId, nums,
menuService.getMenuById(menuId).getPrice() * nums, diningTableId);
if(update<=0){
return false;//点餐失败
}
//还需要更新对应餐桌的状态
//餐桌状态对应DiningTableService的业务,我们在此处需要进行调用
return diningTableService.updateDiningTableState(diningTableId, "就餐中");
}
//返回所有的菜单(其中包含菜品名)提供给view层使用
public List<MultiTableBean>list1(){
final List<MultiTableBean> list = multiTableBeanDAO.queryMulti("SELECT bill.* FROM bill,menu " +
"WHERE bill.menuId=menu.id", MultiTableBean.class);
return list;
}
//返回所有的账单,提供给view使用(不用返回菜品名)
public List<Bill> list (){
final List<Bill> bills = billDAO.queryMulti("select * from bill", Bill.class);
return bills;
}
//查看某个餐桌是否有没结账的账单
/*
需要满足:
1.该餐桌存在
2.餐桌状态为未结账
*/
public boolean hasBillByDiningTableId(int diningTableId){
final Bill bill = billDAO.querySingle("SELECT * FROM bill WHERE diningTableId =? AND state=? LIMIT 0,1", Bill.class, diningTableId, "未结账");
return bill!=null;//bill不为空则有没有结账的账单
}
//完成结账【如果餐桌存在,并且该餐桌有未结账的账单】
/*
如果成功,返回true,失败返回false
*/
public boolean payBill(int diningTableId,String payMode){//根据餐桌来结账
//注意:这里会用到2条sql语句,可以使用事务来保证,可以使用ThreadLocal来解决,框架中比如mybatis提供了支持
//1.修改bill表
final 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;
}
}
- DiningTableService
package com.hspedu.mhl.service;
import com.hspedu.mhl.dao.DiningTableDAO;
import com.hspedu.mhl.domin.DiningTable;
import java.util.List;
//DiningTable表的业务层
public class DiningTableService {
//定义一个DiningTableDAO的属性
DiningTableDAO diningTableDAO = new DiningTableDAO();
//返回餐桌的信息(返回的是多行记录)
public List<DiningTable> list (){
//要求查出id和状态
final List<DiningTable> list =
diningTableDAO.queryMulti("select id,state from diningTable ",
DiningTable.class);
return list;
}
//根据id,查询对应的餐桌DiningTable对象(检测餐桌是否存在)
//如果返回Null,该id对应的餐桌不存在
/*
小技巧:将sql语句放在查询编译器上测试一些可以提前避免错误
*/
public DiningTable getDiningTableById(int id){
final DiningTable diningTable = diningTableDAO.querySingle
("select * from diningTable where id=?", DiningTable.class, id);
return diningTable;
}
//如果餐桌可以预定,对餐桌的状态进行更新(包含预定人的名字和电话)
public boolean orderDiningTable(int id,String orderName,String orderTel){// 通过id指定餐桌
final int update = diningTableDAO.update("update diningTable set state = '已经预定',orderName=? ,orderTel=? where id=?"
, orderName, orderTel,id);
return update>0;//用所影响行数来判断时候状态时候更新成功
}
//这里需要向(BillService)提供一个更新餐桌状态的方法
public boolean updateDiningTableState(int diningTableId,String state){
final int update = diningTableDAO.update
("update diningTable set state=? where id=?", state, diningTableId);
if(update>0){
return true;
}else {
return false;
}
}
//提供方法,将指定的餐桌修改成初始状态
public boolean updateDiningTableToFree(int diningTableId,String state){
final int update = diningTableDAO.update
("update diningTable set state=? ,orderName='',orderTel='' where id=?", state, diningTableId);
if(update>0){
return true;
}else {
return false;
}
}
}
- EmployeeService
package com.hspedu.mhl.service;
import com.hspedu.mhl.dao.EmployeeDAO;
import com.hspedu.mhl.domin.Employee;
/*
*业务层:该类完成对employee表的各种操作(通过调用EmployeeDAO对象来完成)
*
*/
public class EmployeeService {
//定义一个EmployeeDAO属性
private EmployeeDAO employeeDAO = new EmployeeDAO();
/*
*根据empId和pwd返回一个Employee对象(在数据库中进行登录验证)
* 如果查询不到,就返回null(querySingle方法调用的query方法,当查询结果为null,将返回null)
*/
public Employee getEmployeeByIdAndPwd(String empId,String pwd){
Employee employee = employeeDAO.querySingle
("select * from employee where empId=? and pwd=md5(?) ",
Employee.class, empId, pwd);
return employee;
}
}
- MenuService
package com.hspedu.mhl.service;
import com.hspedu.mhl.dao.MenuDAO;
import com.hspedu.mhl.domin.Menu;
import java.util.List;
/*
Menu的业务层:完成对menu表的各种操作(通过调用MenDAO)
*/
public class MenuService {
//定义MenDAO属性
private MenuDAO menuDAO = new MenuDAO();
//返回所有的菜品,返回给界面层使用(返回多行多列)
public List<Menu>list(){
final List<Menu> menus = menuDAO.queryMulti("select * from menu", Menu.class);
return menus;
}
//根据菜品编号获取一个菜品对象
public Menu getMenuById(int menuId){
final Menu menu = menuDAO.querySingle("select " +
" * from menu where id = ?", Menu.class, menuId);
return menu;
}
}
utils包
- JDBCUtilsByDluid
package com.hspedu.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实现JDBC连接池
public class JDBCUtilsByDluid {
private static DataSource ds;//定义一个连接池
//准备初始化连接池
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src\\deluid.properities"));
ds = DruidDataSourceFactory.createDataSource(properties);//初始化连接池
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//1.编写获取连接的方法(得到一个连接)
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//关闭资源
/*
*注意:在数据库连接池技术中,close不是真的断开连接
* 而是把使用的Connection对象放回连接池
*
*
*/
public static void close(ResultSet set , Statement statement,Connection connection){
try {
if (set!=null){
set.close();
}
if (statement!=null){
statement.close();
}
if(connection!=null){
connection.close();//这里不是真正的关闭连接
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
- Utility
package com.hspedu.mhl.utils;
/**
工具类的作用:
处理各种情况的用户输入,并且能够按照程序员的需求,得到用户的控制台输入。
*/
import java.util.*;
/**
*/
public class Utility {
//静态属性。。。
private static Scanner scanner = new Scanner(System.in);
/**
* 功能:读取键盘输入的一个菜单选项,值:1——5的范围
* @return 1——5
*/
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') {
System.out.print("选择错误,请重新输入:");
} 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;
for (; ; ) {
String str = readKeyBoard(10, false);//一个整数,长度<=10位
try {
n = Integer.parseInt(str);//将字符串转换成整数
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
* 功能:读取键盘输入的 整数或默认值,如果直接回车,则返回默认值,否则返回输入的整数
* @param defaultValue 指定的默认值
* @return 整数或默认值
*/
public static int readInt(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.print("数字输入错误,请重新输入:");
}
}
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.println("请确认是否预定(Y/N): 请小心选择");
char c;
for (; ; ) {//无限循环
//在这里,将接受到字符,转成了大写字母
//y => Y n=>N
String str = readKeyBoard(1, false).toUpperCase();
c = str.charAt(0);
if (c == 'Y' || c == 'N') {
break;
} else {
System.out.print("选择错误,请重新输入:");
}
}
return c;
}
/**
* 功能: 读取一个字符串
* @param limit 读取的长度
* @param blankReturn 如果为true ,表示 可以读空字符串。
* 如果为false表示 不能读空字符串。
*
* 如果输入为空,或者输入大于limit的长度,就会提示重新输入。
* @return
*/
private static String readKeyBoard(int limit, boolean blankReturn) {
//定义了字符串
String line = "";
//scanner.hasNextLine() 判断有没有下一行
while (scanner.hasNextLine()) {
line = scanner.nextLine();//读取这一行
//如果line.length=0, 即用户没有输入任何内容,直接回车
if (line.length() == 0) {
if (blankReturn) return line;//如果blankReturn=true,可以返回空串
else continue; //如果blankReturn=false,不接受空串,必须输入内容
}
//如果用户输入的内容大于了 limit,就提示重写输入
//如果用户如的内容 >0 <= limit ,我就接受
if (line.length() < 1 || line.length() > limit) {
System.out.print("输入长度(不能大于" + limit + ")错误,请重新输入:");
continue;
}
break;
}
return line;
}
}
view包
- MHLView
package com.hspedu.mhl.view;
import com.hspedu.mhl.domin.*;
import com.hspedu.mhl.service.BillService;
import com.hspedu.mhl.service.DiningTableService;
import com.hspedu.mhl.service.EmployeeService;
import com.hspedu.mhl.service.MenuService;
import com.hspedu.mhl.utils.Utility;
import java.util.List;
//满汉楼的界面层
public class MHLView {
private boolean loop = true;//控制是否退出主菜单
private String key = "";//接收用户的输入
private EmployeeService employeeService = new EmployeeService();//定义EmployeeService属性
private DiningTableService diningTableService = new DiningTableService();//定义DiningTableService属性
private MenuService menuService = new MenuService();//定义MenuService属性
private BillService billService = new BillService();
public void secondaryView(){
while (loop){
System.out.println("=============================满汉楼二级菜单===============================");
System.out.println("\t\t1.显示餐桌状态");
System.out.println("\t\t2.预定餐桌");
System.out.println("\t\t3.显示所有菜品");
System.out.println("\t\t4.点餐服务");
System.out.println("\t\t5.查看账单");//7 8用于以后的功能扩充
System.out.println("\t\t6.结账");
System.out.println("\t\t9.退出");
System.out.println("请输入你的选择:");
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("输入有误,请重新输入");
}
}
}
//满汉楼一级菜单
public void mainView() {
while (loop) {
System.out.println("================满汉楼=======================");
System.out.println("\t\t1.登录满汉楼");
System.out.println("\t\t2.退出满汉楼");
System.out.println("请输入你的选择:");
key = Utility.readString(1);// 现在用于输入字符串长度为1
switch (key) {
case "1":
//准备输入员工号和密码进行二级菜单
System.out.println("请输入员工号:");
String empId = Utility.readString(50);
System.out.println("输入密 码:");
String pwd = Utility.readString(50);
//验证用于登录
final Employee employee = employeeService.getEmployeeByIdAndPwd(empId, pwd);
if(employee!=null ){
System.out.println("========登录成功=="+employee.getName()+"=========");
//显示二级菜单
//这里为了避免冗余,独立成一个函数
secondaryView();
}else {
System.out.println("==========================================登录失败===============================");
}
break;
case "2":
loop=false;//标记退出菜单
break;
default:
System.out.println("你输入有误,请重新输入");
}
}
System.out.println("你退出了满汉楼系统");
}
//显示所有餐桌的状态
public void listDiningTable(){
System.out.println("\n餐桌编号\t\t餐桌状态");
final List<DiningTable> list = diningTableService.list();
for (DiningTable diningTable : list) {
System.out.println(diningTable);//这里需要重写Object的toString方法
}
System.out.println("==========================显示完毕================================");
}
//完成餐桌预定
public void orderDiningTable(){
System.out.println("===========================预定餐桌==================================");
System.out.println("请选择要预定餐桌的编号(-1退出):");
final int orderId = Utility.readInt();//得到可能需要预定的餐桌id
if(orderId == -1){
System.out.println("====================退出预定=====================");
return;
}
final char c = Utility.readConfirmSelection();
if(c == 'Y'){//确定预定
//判断该编号的餐桌的状态
final DiningTable diningTableById = diningTableService.getDiningTableById(orderId);
if(diningTableById == null){
System.out.println("==================================该餐桌不存在================================");
return;
}else {//开始预定
//判断餐桌是否为空
if(!("空".equals(diningTableById.getState()))){
System.out.println("====================餐桌处于已经预定或者就餐状态================");
return;
}else {
//正式开始预定
System.out.println("请输入预定人姓名:");
final String orderName = Utility.readString(20);
System.out.println("请输入预定人电话:");
final String orderTel = Utility.readString(20);
if(diningTableService.orderDiningTable(orderId, orderName, orderTel)){
System.out.println("=====================预定成功=============================");
}else {
System.out.println("===============预定失败====================================");
}
}
}
}else {//取消预定
System.out.println("=====================取消预定=====================================");
return;
}
}
//显示所有菜品
public void listMenu(){
final List<Menu> list = menuService.list();//得到菜品集合
System.out.println("菜品编号"+"\t\t"+"菜品名"+"\t\t"+"类别"+"\t\t"+"价格");
for (Menu menu : list) {//遍历集合
System.out.println(menu);
}
}
//完成点餐服务
public void orderMenu(){
System.out.println("=============================点餐服务===================================");
System.out.println("请选择点餐的桌位号(-1退出):");
final int diningTableId = Utility.readInt();
if(diningTableId == -1){
System.out.println("==========================取消点餐=====================");
return;
}
System.out.println("请选择菜品编号(-1退出):");
final int menuId = Utility.readInt();
if(menuId==-1){
System.out.println("===========================取消点餐==========================");
return;
}
System.out.println("请选择菜品数量(-1退出):");
final int nums = Utility.readInt();
if(nums==-1){
System.out.println("===============================取消点餐=================");
return;
}
//对餐桌号进行校验
final DiningTable diningTable = diningTableService.getDiningTableById(diningTableId);
if(diningTable==null){
System.out.println("====================餐桌号不存在=============================");
return;
}
//对菜品编号进行验证
final Menu menu = menuService.getMenuById(menuId);
if(menu==null){
System.out.println("===============================菜品编号不存在===========================");
return;
}
//可以正式点餐
final boolean flag = billService.orderMenu(menuId,nums,diningTableId);
if(flag){
System.out.println("==================================点餐成功======================");
}else {
System.out.println("==================================点餐失败=======================");
}
}
//显示账单的信息
public void listBill(){
System.out.println("\n编号\t\t菜品号\t\t菜品量\t\t金额\t\t桌号\t\t日期\t\t\t\t\t\t\t状态\t\t菜品名");
//final List<Bill> list = billService.list();//不显示菜品的账单显示
final List<MultiTableBean> list = billService.list1();//显示菜品名称的账单显示
for (MultiTableBean bill : list) {
System.out.println(bill.toString());
}
System.out.println("===============================================显示完毕==============================================");
}
//完成结账
public void payBill(){
System.out.println("===============================================结账服务==============================================");
System.out.println("请选择要结账的餐桌编号(-1退出):");
final int diningTableId = Utility.readInt();
if(diningTableId==-1){
System.out.println("===========================================取消结账================================================");
return ;
}
//验证餐桌是否存在
final DiningTable diningTable = diningTableService.getDiningTableById(diningTableId);
if(diningTable==null){
System.out.println("======================================结账的餐桌不存在===============================================");
}
//验证餐桌是否有需要结账的账单
if(!(billService.hasBillByDiningTableId(diningTableId))){
System.out.println("=========================================该餐位没有未结账的账单==================================================");
return ;
}
System.out.println("结账的方式(现金/支付宝/微信)回车表示退出:");
final String payMode = Utility.readString(20,"");//如果回车,就是返回""
if("".equals(payMode)){
System.out.println("==============================================取消结账===============================================");
return ;
}
if(Utility.readConfirmSelection()=='N'){
System.out.println("===========================================取消结账===============================================");
return ;
}
//开始正式进行结账
final boolean flag = billService.payBill(diningTableId, payMode);
if(flag){
System.out.println("============================================结账成功=================================================");
}else {
System.out.println("===========================================结账失败==================================================");
return ;
}
}
public static void main(String[] args) {
new MHLView().mainView();
}
}
druid的配置文件
- deluid.properties
#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mhl?useUnicode=true&
characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai
username=root
password=888888
#initial connection Size
initialSize=10
#min idle connection size
minIdle=5
#max active connection size
maxActive=100
#max wait time(3000 mil seconds)
maxWait=3000
所使用和实验的SQL语句汇总
CREATE DATABASE mhl-- 创建满汉楼数据库
USE mhl-- 将数据库转换成mhl
-- 创建员工表
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,-- 主键且自增
empId VARCHAR(50)UNIQUE NOT NULL DEFAULT '',-- 员工号(不可重复)
pwd CHAR(32) NOT NULL DEFAULT '',-- 密码md5
NAME VARCHAR(50)NOT NULL DEFAULT '',-- 姓名
job VARCHAR(50) NOT 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,'
',MD5('123456'),'张无忌','收银员');
INSERT INTO employee VALUES(NULL,'6668666',MD5('123456'),'老韩','经理');
SELECT * FROM employee
-- 创建餐桌表
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 WHERE id=2
UPDATE diningTable SET state = '已经预定',orderName='张三' ,orderTel='123'
SELECT * FROM diningTable
DROP TABLE diningTable
UPDATE diningTable SET state = '空',orderName='' ,orderTel='' WHERE id=1
-- 创建菜单表
CREATE TABLE 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#价格
)CHARSET =utf8;
SELECT * FROM menu
-- 添加测试数据
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
DROP TABLE menu
-- 创建bill账单表
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(50)NOT NULL DEFAULT ''-- 账单状态(未结账 已经结账 挂单等)
)CHARSET = utf8
SELECT * FROM bill
SELECT * FROM diningtable;
UPDATE diningTable SET state='用餐中' WHERE id=1
SELECT * FROM diningTable
SELECT * FROM bill
INSERT INTO diningtable VALUES(4,'空','','');
SELECT * FROM bill WHERE diningTableId =1 AND state='未结账' LIMIT 0,1
SELECT bill.*,NAME FROM bill,menu
WHERE bill.menuId=menu.id;