要求
- 编写一个宾馆入住程序
- 要求:用图形用户界面实现。
- 能实现宾馆人员入住、退房、修改入住信息、房间管理等功能。
分析
-
顾客信息肯定得保护好,所以得设置一个登录程序,可不能让其他人发现顾客的小秘密
-
得有图形化界面,就要用到JFrame
-
同样的,我们使用txt作为信息存储,所以得有文件的读写,就要用到文件的操作File,和数据流的操作
-
对房间的管理功能,可以提添加或者修改房间信息
-
交互方面,得参照正规入住手续来弄!得收集入住用户的一些基本信息:身份证号,入住人姓名、地址、电话等
本次编码我们将范围两部分进行:
- 登录、提示方法的封装;房间和用户信息的数据结构设计;房间管理功能
- 用户入住和退房功能
代码整起
一:方法的封装
封装:在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
封装的优点:
-
良好的封装能够减少耦合。
-
类内部的结构可以自由修改。
-
可以对成员变量进行更精确的控制。
-
隐藏信息,实现细节。
之前在做记事本程序是已近有一个登录程序了,这里我就直接哪来用了,创建名为Login的java类将之前的代码进行封装
public class Login {
Login(){
// 创建 JFrame 实例
JFrame frame = new JFrame("用户登录");
// Setting the width and height of frame
//设置窗口大小
frame.setSize(350, 200);
//设置窗口生出位置
frame.setLocationRelativeTo(null);
//添加关闭动作
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//创建JPanel 画布实例
JPanel panel = new JPanel();
// 将画布添加到JFrame中
frame.add(panel);
//调用方法初始化登录界面
initLogin(panel,frame);
// 设置界面可见
frame.setVisible(true);
}
/**
* 登录界面
* @param panel
* @param jFrame
*/
private void initLogin(JPanel panel,JFrame jFrame) {
//布局
panel.setLayout(null);
// 创建 JLabel 标签 用户名
JLabel userLabel = new JLabel("用户名:");
//定义组件位置 x 和 y 指定左上角的新位置,由 width 和 height 指定新的大小
userLabel.setBounds(10,20,80,25);
panel.add(userLabel);
//创建输入框组件 用户名文本域
JTextField userText = new JTextField(20);
userText.setBounds(100,20,165,25);
panel.add(userText);
// 创建 JLabel 标签 密码
JLabel passwordLabel = new JLabel("密码:");
passwordLabel.setBounds(10,50,80,25);
panel.add(passwordLabel);
//创建输入框组件 输入密码的文本域 这个类输入的信息会以点号代替,用于包含密码的安全性
JPasswordField passwordText = new JPasswordField(20);
passwordText.setBounds(100,50,165,25);
panel.add(passwordText);
// 创建登录按钮
JButton loginButton = new JButton("登录");
loginButton.setBounds(120,100,80,25);
panel.add(loginButton);
//为按钮添加点击事件,点击后判断用户名和密码正确性
loginButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String userName = userText.getText();
String password = String.valueOf(passwordText.getPassword());
if ("admin".equals(userName) && "123456".equals(password)){
jFrame.dispose();
//接着做后续操作
System.out.println("登录成功");
Main main = new Main();
List<HotelInfo> baseInfo = main.getBaseInfo();
main.hotelFrame(baseInfo);
}else{
//创建Tip实例提示 用户密码不对
Tip tip = new Tip("登录用户或密码不正确");
}
}
});
}
}
接着是提示消息的封装,之前我用的也是JFrame,用起来不是太友好,换一个简单点,更符合提示需求的方式,同样创建名为Tip的java类进行封装
/**
* @Author 消逝
* 消息提示
*/
public class Tip{
Tip(String msg){
//弹窗信息
JOptionPane.showMessageDialog(null,msg);
}
}
二:房间和用户数据结构设计
对房间和用户信息进行数据结构的设计,有利于我们对其信息的处理和存储,将房间或者用户的特性存储为一个公共类
/**
* 房间信息
* @Author 消逝
*/
public class HotelInfo {
private String roomNum;//房间号
private String roomType;//房间类型
private String floor;//房间所在楼层
private String empty;//是否已有客户入住
private String price;//价格
private String deposit;//押金
private String payment;//付款(可能会有多预存的情况)
private String startTime;//入住时间
private String endTime;//退房时间
private String remarks;//备注
private UserInfo user;//用户信息
//用于存储到txt的String结构
@Override
public String toString() {
return
"roomNum=" + roomNum +
", roomType=" + roomType +
", floor=" + floor +
", empty=" + empty +
", price=" + price +
", deposit=" + deposit +
", payment=" + payment +
", startTime=" + startTime +
", endTime=" + endTime +
", remarks=" + remarks +
", user=@" + user;
}
//无参构造
public HotelInfo() {
}
//有参构造
public HotelInfo(String roomNum, String roomType, String floor, String price) {
this.roomNum = roomNum;
this.roomType = roomType;
this.floor = floor;
this.price = price;
this.deposit = "";
this.payment = "";
this.startTime = "";
this.endTime = "";
this.user = new UserInfo();
this.empty = "空房";
this.remarks = "新房";
}
...省去git和set方法
/**
* 用户信息
* @Author 消逝
*/
public class UserInfo {
//顾客名称(多个用【,】隔开)
private String name;
//顾客年龄
private String age;
//顾客省份证号
private String idNum;
//顾客地址
private String address;
//顾客电话
private String phone;
//入住人数
private String numOfPeople;
public UserInfo() {
this.name = "";
this.age = "";
this.idNum = "";
this.address = "";
this.phone = "";
this.numOfPeople = "";
}
public String getName() {
return name;
}
//用于存储到txt的String结构
@Override
public String toString() {
return
"name=" + name +
", age=" + age +
", idNum=" + idNum +
", address=" + address +
", phone=" + phone +
", numOfPeople=" + numOfPeople;
}
...省去git和set方法
宾馆信息查询
/**
* 获取房间信息 每次启动就将房间信息读入系统程序
* @return
*/
List<HotelInfo> getBaseInfo(){
List<HotelInfo> result = new ArrayList<>();
String path = "C:\\Users\\20140\\Desktop\\hotel";
//读取宾馆信息
File file = new File(path);
//判断文件夹是否存在,不存在就先创建
if (!file.exists() || !file.isDirectory()){
//mkdir() : 创建此抽象路径名指定的目录。
//mkdirs() : 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。
file.mkdir();
}
//判断文件是否存在
path += "\\info.txt";
File file2 = new File(path);
if (!file2.exists()){
//如果不存在就尝试创建
try {
file2.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
//读取文件信息
try {
//构造一个BufferedReader类来读取文件
BufferedReader br = new BufferedReader(new FileReader(new File(path)));
String s = null;
//使用readLine方法,一次读一行
while((s = br.readLine())!=null){
//如果取到空字符串就跳过这次循环开始下一次
if ("".equals(s)){
continue;
}
HotelInfo hotelInfo = new HotelInfo();
UserInfo userInfo = new UserInfo();
//@分割房间信息和入住信息
String[] baseInfo = s.split("@");
//先解析房间信息
String[] roomInfo = baseInfo[0].split(",");
if (roomInfo.length > 0){
//封装房间信息
hotelInfo.setRoomNum(roomInfo[0].substring(roomInfo[0].indexOf("=")+1,roomInfo[0].length()));
hotelInfo.setRoomType(roomInfo[1].substring(roomInfo[1].indexOf("=")+1,roomInfo[1].length()));
hotelInfo.setFloor(roomInfo[2].substring(roomInfo[2].indexOf("=")+1,roomInfo[2].length()));
hotelInfo.setEmpty(roomInfo[3].substring(roomInfo[3].indexOf("=")+1,roomInfo[3].length()));
hotelInfo.setPrice(roomInfo[4].substring(roomInfo[4].indexOf("=")+1,roomInfo[4].length()));
hotelInfo.setDeposit(roomInfo[5].substring(roomInfo[5].indexOf("=")+1,roomInfo[5].length()));
hotelInfo.setPayment(roomInfo[6].substring(roomInfo[6].indexOf("=")+1,roomInfo[6].length()));
hotelInfo.setStartTime(roomInfo[7].substring(roomInfo[7].indexOf("=")+1,roomInfo[7].length()));
hotelInfo.setEndTime(roomInfo[8].substring(roomInfo[8].indexOf("=")+1,roomInfo[8].length()));
hotelInfo.setRemarks(roomInfo[9].substring(roomInfo[9].indexOf("=")+1,roomInfo[9].length()));
}
//再解析入住信息
if (baseInfo.length > 1){
String[] hotelUserInfo = baseInfo[1].split(",");
//封装房间入住信息
userInfo.setName(hotelUserInfo[0].substring(hotelUserInfo[0].indexOf("=")+1,hotelUserInfo[0].length()));
userInfo.setAge(hotelUserInfo[1].substring(hotelUserInfo[1].indexOf("=")+1,hotelUserInfo[1].length()));
userInfo.setIdNum(hotelUserInfo[2].substring(hotelUserInfo[2].indexOf("=")+1,hotelUserInfo[2].length()));
userInfo.setAddress(hotelUserInfo[3].substring(hotelUserInfo[3].indexOf("=")+1,hotelUserInfo[3].length()));
userInfo.setPhone(hotelUserInfo[4].substring(hotelUserInfo[4].indexOf("=")+1,hotelUserInfo[4].length()));
userInfo.setNumOfPeople(hotelUserInfo[5].substring(hotelUserInfo[5].indexOf("=")+1,hotelUserInfo[5].length()));
hotelInfo.setUser(userInfo);
}
//将房间信息放入List
result.add(hotelInfo);
}
br.close();
return result;
}catch (Exception e1){
System.out.println("文件读取错误");
return null;
}
}
不要停不要停!接着搞界面
/**
* 入住系统主界面
* @param baseInfo
*/
void hotelFrame(List<HotelInfo> baseInfo){
// 创建 JFrame 实例
listFrame = new JFrame("欢迎使用消逝的宾馆入住程序");
//设置窗口大小
listFrame.setSize(600,500);
//设置窗口生出位置
listFrame.setLocationRelativeTo(null);
//添加关闭动作
listFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//创建JPanel 画布实例
JPanel panel = new JPanel();
//创建菜单条
JMenuBar menuBar = new JMenuBar();
listFrame.setJMenuBar(menuBar);
//创建房间菜单对应功能
JMenu menuRoom = new JMenu("房间操作");
addRoom = new JMenuItem("添加", KeyEvent.VK_F);
//添加点击监听
addRoom.addActionListener(this);
//在房间菜单添加相应操作
menuRoom.add(addRoom);
//将菜单添加到菜单条里
menuBar.add(menuRoom);
//初始化房间显示
for (HotelInfo info : baseInfo) {
JButton roomButton = new JButton(info.getRoomNum()+info.getRoomType());
Dimension dimension = new Dimension(120,25);
roomButton.setPreferredSize(dimension);
if ("空房".equals(info.getEmpty())){
//空房的话用绿色表示
roomButton.setBackground(Color.green);
}else {
//有人的话用红色色表示
roomButton.setBackground(Color.red);
}
panel.add(roomButton);
listFrame.add(panel);
roomButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
hotelInfoForm(info);
}
});
}
// 设置界面可见
listFrame.setVisible(true);
}
//添加房间点击监听
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(addRoom)){
saveFrom();
}
}
效果展示
提示信息
主界面
添加房间
/**
* 添加房间
*/
private void saveFrom(){
// 创建 JFrame 实例
JFrame frame = new JFrame("房间信息");
// Setting the width and height of frame
//设置窗口大小
frame.setSize(300,180);
//创建JPanel 画布实例
JPanel panel = new JPanel();
//设置窗口生出位置
frame.setLocationRelativeTo(null);
//禁止改变窗口大小
frame.setResizable(false);
//添加用户信息操作框
JLabel roomNum = new JLabel("房间号码:");
roomNum.setBounds(50,50,80,25);
panel.add(roomNum);
//创建输入框组件文本域
JTextField roomNumText = new JTextField(20);
roomNumText.setBounds(140,50,165,25);
panel.add(roomNumText);
//添加用户信息操作框
JLabel roomType = new JLabel("房间类型:");
roomType.setBounds(50,75,80,25);
panel.add(roomType);
//创建输入框组件文本域
JTextField roomTypeText = new JTextField(20);
roomTypeText.setBounds(140,75,165,25);
panel.add(roomTypeText);
//添加用户信息操作框
JLabel floor= new JLabel("所在楼层:");
floor.setBounds(50,100,80,25);
panel.add(floor);
//创建输入框组件文本域
JTextField floorText = new JTextField(20);
floorText.setBounds(140,100,165,25);
panel.add(floorText);
//添加用户信息操作框
JLabel price = new JLabel("房间价格:");
price.setBounds(50,125,80,25);
panel.add(price);
//创建输入框组件文本域
JTextField priceText = new JTextField(20);
priceText.setBounds(140,125,165,25);
panel.add(priceText);
JButton save = new JButton("添加");
save.setBounds(150,150,100,50);
panel.add(save);
frame.add(panel);
// 设置界面可见
frame.setVisible(true);
save.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//保存
//先校验基础参数是否填写
String roomNum = roomNumText.getText();
String roomType = roomTypeText.getText();
String floor = floorText.getText();
String price = priceText.getText();
if ("".equals(roomNum) || "".equals(roomType) ||
"".equals(floor) || "".equals(price)){
new Tip("请填写正确房间信息");
}
//创建房间信息
HotelInfo info = new HotelInfo(roomNum,roomType,floor,price);
//获取原有的房间信息
List<HotelInfo> baseInfo = getBaseInfo();
baseInfo.add(info);
saveHotel(baseInfo);
listFrame.dispose();
frame.dispose();
hotelFrame(baseInfo);
}
});
}
/**
* 存储房间信息
* @param hotelInfo
*/
private void saveHotel(List<HotelInfo> hotelInfo){
File file = new File("C:\\Users\\20140\\Desktop\\hotel\\info.txt");
try {
OutputStream os = new FileOutputStream(file);
PrintWriter pw=new PrintWriter(os);
for (HotelInfo info : hotelInfo){
pw.println(info.toString()+"\n");
}
pw.close();
new Tip("保存成功");
}catch (Exception e){
System.out.println("写入错误");
new Tip("保存失败");
}
}
点击房间展示房间信息以及入住信息
/**
* 客房信息
* @param info
*/
private void hotelInfoForm(HotelInfo info){
// 创建 JFrame 实例
JFrame frame = new JFrame("房间信息");
//设置窗口大小
frame.setSize(400,480);
//创建JPanel 画布实例
JPanel panel = new JPanel();
//设置窗口生出位置
frame.setLocationRelativeTo(null);
//禁止改变窗口大小
frame.setResizable(false);
/**
* 创建内部类调用画笔工具
*/
class MyPant extends JPanel{
@Override
public void paint(Graphics g) {
g.drawString("房间号:"+info.getRoomNum(),50,25);
g.drawString("房间类型:"+info.getRoomType(),180,25);
g.drawString("所在楼层:"+info.getFloor(),50,55);
g.drawString("是否空房:"+info.getEmpty(),180,55);
g.drawString("价格/天:"+info.getPrice(),50,80);
g.drawString("收款:"+info.getPayment(),180,80);
g.drawString("入住时间:"+info.getStartTime(),50,105);
g.drawString("退房时间:"+info.getEndTime(),50,130);
g.drawString("天数:2",50,150);
g.drawString("押金:"+info.getDeposit(),180,150);
g.setColor(Color.red);
g.drawString(">>>>>>>>>>入住信息<<<<<<<<<<",100,165);
}
}
MyPant g = new MyPant();
//获取用户数据
UserInfo userInfo = info.getUser();
//添加用户信息操作框
JLabel userName = new JLabel("客户名称:");
userName.setBounds(50,175,80,25);
frame.add(userName);
//创建输入框组件文本域
JTextField userNameText = new JTextField(20);
userNameText.setBounds(140,175,165,25);
if (userInfo.getName() != null){
userNameText.setText(userInfo.getName());
}
frame.add(userNameText);
//身份证号
JLabel userIdCard = new JLabel("省份证号:");
userIdCard.setBounds(50,200,80,25);
frame.add(userIdCard);
JTextField userIdCardText = new JTextField(20);
userIdCardText.setBounds(140,200,165,25);
if (userInfo.getIdNum() != null){
userIdCardText.setText(userInfo.getIdNum());
}
frame.add(userIdCardText);
//地址
JLabel userAddress = new JLabel("用户地址:");
userAddress.setBounds(50,225,80,25);
frame.add(userAddress);
JTextField userAddressText = new JTextField(20);
userAddressText.setBounds(140,225,165,25);
if (userInfo.getAddress() != null){
userAddressText.setText(userInfo.getAddress());
}
frame.add(userAddressText);
//电话
JLabel userPhone = new JLabel("用户电话:");
userPhone.setBounds(50,250,80,25);
frame.add(userPhone);
JTextField userPhoneText = new JTextField(20);
userPhoneText.setBounds(140,250,165,25);
if (userInfo.getPhone() != null){
userPhoneText.setText(userInfo.getPhone());
}
frame.add(userPhoneText);
//备注
JLabel content = new JLabel("备注:");
content.setBounds(50,275,80,25);
frame.add(content);
//创建输入框组件 用户名文本域
// 创建一个 20 行 20 列的文本区域
JTextArea contentText = new JTextArea(20,20);
contentText.setBounds(50,300,300,100);
// 设置自动换行
contentText.setLineWrap(true);
if (info.getDeposit() != null){
contentText.setText(info.getDeposit());
}
frame.add(contentText);
JButton insert = new JButton("入住");
insert.setBounds(50,320,100,50);
panel.add(insert);
JButton del = new JButton("退房");
del.setBounds(180,320,100,50);
panel.add(del);
//将房间信息布局到中部
frame.add(g,BorderLayout.CENTER);
//将按钮布局到底部
frame.add(panel,BorderLayout.SOUTH);
// 设置界面可见
frame.setVisible(true);
}
已入住效果
未入住效果
至此第一部分的代码就好了!!!有错欢迎指正!!!
入住和退房以及其他代码优化会尽快完善!!!