Java Swing座位预订系统:持久化座位状态及登录后无法打开预订窗口问题求助
Java Swing座位预订系统:持久化座位状态及登录后无法打开预订窗口问题求助
我正在用Java Swing做一个座位预订系统,想实现用户预订的座位能保存下来——这样其他用户打开预订窗口时,就选不了已经被订走的座位了。这是我第一次提问,要是表述有问题还请见谅~
我尝试用Serializable接口来保存用户的输入,打算在其他用户登录时加载这些数据,但现在遇到个问题:换另一个用户登录后,座位预订的窗口根本打不开,啥反应都没有。
以下是我的代码:
Main类代码
public class Main { public static void main(String[] args) { UserIDAndPasswords idandPasswords = new UserIDAndPasswords(); UserLogin userlogin = new UserLogin(idandPasswords.getLoginInfo()); } }
UserIDAndPasswords类代码
public class UserIDAndPasswords { HashMap<String,String> logininfo = new HashMap<String,String>(); UserIDAndPasswords(){ logininfo.put("Zain","Hallelujah101"); logininfo.put("Arsal","BakedCash222"); logininfo.put("Basil","ABC123"); } public HashMap getLoginInfo(){ return logininfo; } }
UserLogin类代码
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.util.HashMap; public class UserLogin implements ActionListener, Serializable { JFrame frame = new JFrame("Dubai Software Limited"); JLabel label = new JLabel("Welcome to JApp 01"); JButton loginButton = new JButton("Login"); JButton resetButton = new JButton("Reset"); JTextField userIDField = new JTextField(); JPasswordField userPasswordField = new JPasswordField(); JLabel userIDLabel = new JLabel("userID:"); JLabel userPasswordLabel = new JLabel("password:"); JLabel messageLabel = new JLabel(); HashMap<String,String> logininfo = new HashMap<String,String>(); UserLogin(HashMap<String, String> loginInfoOriginal){ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(420,420); frame.setLayout(null); frame.setVisible(true); frame.setLocationRelativeTo(null); label.setBounds(140,-120,200,400); logininfo = loginInfoOriginal; userIDLabel.setBounds(50,100,75,25); userPasswordLabel.setBounds(50,150,75,25); messageLabel.setBounds(125,250,250,35); userIDField.setBounds(125,100,200,25); userPasswordField.setBounds(125,150,200,25); loginButton.setBounds(125,200,100,25); loginButton.setFocusable(false); loginButton.addActionListener(this); resetButton.setBounds(225,200,100,25); resetButton.setFocusable(false); resetButton.addActionListener(this); frame.add(userIDLabel); frame.add(userPasswordLabel); frame.add(messageLabel); frame.add(userIDField); frame.add(userPasswordField); frame.add(loginButton); frame.add(resetButton); frame.add(label); } @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==resetButton) { userIDField.setText(""); userPasswordField.setText(""); } if(e.getSource()==loginButton) { String userID = userIDField.getText(); String password = String.valueOf(userPasswordField.getPassword()); if(logininfo.containsKey(userID)) { if(logininfo.get(userID).equals(password)) { messageLabel.setForeground(Color.green); messageLabel.setText("Login successful"); frame.dispose(); try { JAppUser userApp = null; File file = new File("ReservedSeats.ser"); if(file.exists()) { FileInputStream filein = new FileInputStream(file); ObjectInputStream in = new ObjectInputStream(filein); userApp = (JAppUser)in.readObject(); in.close(); filein.close(); } else { JAppUser user = new JAppUser(); } } catch (IOException | ClassNotFoundException e1) { e1.printStackTrace(); } } else { messageLabel.setForeground(Color.red); messageLabel.setText("Wrong password"); } } else { messageLabel.setForeground(Color.red); messageLabel.setText("username not found"); } } } }
JAppUser类代码
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; public class JAppUser implements ActionListener, Serializable { JFrame frame = new JFrame("Dubai Software Limited"); JPanel button_panel = new JPanel(); JButton[] buttons = new JButton[50]; Font font = new Font("Times New Roman", Font.BOLD, 7); int count; JAppUser() { frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(800, 800); frame.setLayout(new BorderLayout()); frame.setVisible(true); frame.setLocationRelativeTo(null); button_panel.setLayout(new GridLayout(10, 5)); for (int i = 0; i < buttons.length; i++) { buttons[i] = new JButton(); buttons[i].setBounds(10, 10, 10, 10); button_panel.add(buttons[i]); buttons[i].setFocusable(false); buttons[i].addActionListener(this); buttons[i].setEnabled(true); } buttons[0].setText("Confirm"); Integer num = 1; for (int j = 5; j < buttons.length; j += 5) { String strnum = num.toString(); buttons[j].setText(strnum); num++; buttons[j].setEnabled(false); } String[] buttonName = { "A", "B", "C", "D" }; int buttonNum = 0; for (int k = 1; k < 5; k++) { buttons[k].setText(buttonName[buttonNum]); buttonNum++; buttons[k].setEnabled(false); } frame.add(button_panel); } public void actionPerformed(ActionEvent e) { for (int i = 0; i < buttons.length; i++) { if (e.getSource() == buttons[i]) { if (buttons[i].getText().equals("")) { buttons[i].setForeground(Color.BLACK); buttons[i].setText("X"); count++; System.out.println("Seat has been reserved."); } else if (buttons[i].getText().equals("X")) { buttons[i].setText(""); for (int j = 0; j < buttons.length; j++) { if (buttons[j].getText().equals("") || buttons[j].getText().equals("X")) { buttons[j].setEnabled(true); } } count--; System.out.println("Seat has been unreserved."); } else { try { FileOutputStream file = new FileOutputStream("ReservedSeats.ser"); ObjectOutputStream out = new ObjectOutputStream(file); out.writeObject(this); out.close(); file.close(); System.out.print("Saved Succesfully"); } catch (IOException e1) { e1.printStackTrace(); } UserIDAndPasswords idandPasswords = new UserIDAndPasswords(); UserLogin userlogin = new UserLogin(idandPasswords.getLoginInfo()); frame.dispose(); } } stop(count); } } public void stop(int count) { for (int i = 0; i < buttons.length; i++) { if (count >= 3) { for (int j = 0; j < buttons.length; j++) { if (buttons[i].getText().equals("")) { buttons[i].setEnabled(false); buttons[0].setEnabled(true); } } } } } }
问题分析与修复方案
1. 登录后无法打开预订窗口的核心原因
你在登录成功后的代码里,要么读取了userApp但没有显示它的窗口,要么创建了新的JAppUser但没有把它赋值给变量并确保窗口可见。修改UserLogin类中登录成功的代码块:
try { JAppUser userApp = null; File file = new File("ReservedSeats.ser"); if(file.exists()) { FileInputStream filein = new FileInputStream(file); ObjectInputStream in = new ObjectInputStream(filein); userApp = (JAppUser)in.readObject(); in.close(); filein.close(); // 关键:读取后要显示窗口 userApp.frame.setVisible(true); } else { // 直接创建并显示新窗口 userApp = new JAppUser(); } } catch (IOException | ClassNotFoundException e1) { e1.printStackTrace(); // 加载失败时,默认创建新的预订窗口 new JAppUser(); }
2. 序列化Swing组件的错误(隐藏坑)
直接序列化JAppUser类是错误的——Swing组件(比如JFrame、JButton)大多没有实现Serializable接口,强行序列化会抛出异常,而且序列化整个UI对象完全没必要。正确的做法是只序列化座位的状态数据,比如哪些座位被预订了:
首先创建一个专门保存座位状态的可序列化类:
import java.io.Serializable; import java.util.HashSet; import java.util.Set; public class SeatReservationState implements Serializable { // 用集合保存被预订的座位索引 private Set<Integer> reservedSeats = new HashSet<>(); public void reserveSeat(int seatIndex) { reservedSeats.add(seatIndex); } public void unreserveSeat(int seatIndex) { reservedSeats.remove(seatIndex); } public boolean isSeatReserved(int seatIndex) { return reservedSeats.contains(seatIndex); } public Set<Integer> getReservedSeats() { return reservedSeats; } }
然后修改JAppUser类,在构造函数中加载状态,在确认时保存状态:
// 新增加载状态的方法 private void loadSeatReservationState() { File file = new File("ReservedSeats.ser"); if(file.exists()) { try(FileInputStream filein = new FileInputStream(file); ObjectInputStream in = new ObjectInputStream(filein)) { SeatReservationState state = (SeatReservationState) in.readObject(); // 根据保存的状态初始化按钮 for(Integer seatIdx : state.getReservedSeats()) { if(seatIdx >=0 && seatIdx < buttons.length) { buttons[seatIdx].setText("X"); count++; } } // 更新按钮可用状态 stop(count); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } } // 新增保存状态的方法 private void saveSeatReservationState() { SeatReservationState state = new SeatReservationState(); // 遍历按钮,收集被预订的座位索引 for(int i=0; i<buttons.length; i++) { if("X".equals(buttons[i].getText())) { state.reserveSeat(i); } } // 用try-with-resources自动关闭流,避免资源泄漏 try(FileOutputStream file = new FileOutputStream("ReservedSeats.ser"); ObjectOutputStream out = new ObjectOutputStream(file)) { out.writeObject(state); System.out.print("Saved Succesfully"); } catch (IOException e1) { e1.printStackTrace(); } } // 修改构造函数,添加加载逻辑 JAppUser() { // ...原有的窗口初始化代码... // 加载保存的座位状态 loadSeatReservationState(); // ...原有的按钮初始化代码... } // 修改actionPerformed中的保存逻辑 @Override public void actionPerformed(ActionEvent e) { for (int i = 0; i < buttons.length; i++) { if (e.getSource() == buttons[i]) { if (buttons[i].getText().equals("")) { // ...原有的预订逻辑... } else if (buttons[i].getText().equals("X")) { // ...原有的取消预订逻辑... } else if(buttons[i].getText().equals("Confirm")) { // 调用新的保存方法 saveSeatReservationState(); UserIDAndPasswords idandPasswords = new UserIDAndPasswords(); UserLogin userlogin = new UserLogin(idandPasswords.getLoginInfo()); frame.dispose(); } } stop(count); } }
3. 其他优化建议
- 去掉
UserLogin类的Serializable接口,这个类不需要序列化 - 尽量避免使用
setLayout(null)(空布局),改用Swing的布局管理器(比如BorderLayout、GridBagLayout),否则窗口缩放时组件会错位 - 所有IO流尽量用
try-with-resources语法,自动关闭流,避免资源泄漏
备注:内容来源于stack exchange,提问作者Zain Reshi
相关产品推荐
相关产品推荐

