You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 12:40:30