课程设计大作业
功能:
1.具有点对点通信功能,任意客户端之间能够发送消息。
2.具有群组通信功能:
- 客户端可以自主建立群组,添加或删除组成员;
- 客户端能够向组内成员同时发送消息,其他组成员不能收到。
3.具有广播功能
- 客户端能够向所有其他成员广播消息;
- 服务器可以向所以客户端广播系统消息。
4.其他功能
- 服务器
- 可以强制下线用户
- 根据客户端上线下线情况,实时刷新在线用户列表
- 客户端
- 登录:登录时只有账号密码合法才能登录成功,进入聊天界面。若该用户未注册过,则使用其输入的账户和密码为其注册,下次使用该密码进行审核。
- 实时刷新用户列表:客户端的上线下线能够在其他客户端上面实时刷新。
- 切换聊天对象:用户切换聊天对象时在同一个界面之间进行切换,切换不同聊天对象时,聊天记录不会消失。
- 消息提示:当接收到新消息,且发送方不是当前的聊天对象时,会点亮该发送方,提醒用户。当用户点击该好友进行聊天时,会取消点亮。
- 加密与解密:对消息进行了简单的加密保护。
为了界面较为美观且代码简洁,使用了Swing UI designer进行界面设计。
登录界面
客户端界面
服务器界面
主要数据结构
服务器Server
在线用户——clients——Map
在线用户列表——onlineClient——List
用户列表——userList——Jlist
系统消息记录——sysMessageList——Jlist
组群+成员——groups——Map<String, List>
客户端Client
当前聊天对象——receiver——String
在线用户——onlineUser——List
好友列表——friendList——JList
所属组群——groups——List
当前界面消息记录——message_List——JList
高亮好友列表——highlightFrined——Set
聊天记录——chatRecord——Map
主要成员函数
服务器Server
- start():服务器启动函数,创建服务器套接字,接受来自客户端的连接请求,并为每个新的客户端创建一个新线程(ClientHandler)来处理该客户端的消息。
- ClientHandler:内部类,负责处理每个客户端的请求。其主要成员函数包括:
- run(): 持续读取客户端的消息,根据消息类型执行不同的操作,如:用户上线(1111),广播消息(2333),私聊消息(1333),创建小组(5555),添加小组成员(6666),移除小组成员(7777),小组消息(8888)等。
- broadcast():向所有在线用户广播消息,用于广播和发送系统消息。
- broadcastToGroup():向某个小组的所有成员广播消息,用于处理组群聊。
- sendTo(): 向特定用户发送消息,用于处理私聊。
- sendOnlineList(): 发送当前在线用户列表到特定用户,用于刷新用户列表。
- refresh_message(): 服务器发送系统消息给所有在线用户或群聊。
- forceDisconnect():服务器强制某个用户下线。
- broadcast(): 向所有在线用户广播消息。
- encryptWrite():将发送的消息进行简单的加密并写入输出流。
- readDecrypt(): 从输入流中读取并解密消息。
- nowDate(): 返回当前的日期和时间。
客户端Client
- init(): 用于初始化界面和各个组件的事件监听器。
- refresh_message(): 用于发送消息并刷新消息列表。
- run(): 是程序的运行逻辑。首先创建并显示聊天窗口的界面。然后,创建一个新的线程用于每秒钟更新聊天记录或好友列表。接下来,创建一个新的线程来处理与服务器的通信。
- HighlightedListCellRenderer: 用于自定义好友列表的渲染器,达到点亮好友的效果。
- encryptWrite(): 将发送的消息进行简单的加密并写入输出流。
- readDecrypt(): 从输入流中读取并解密消息。
- nowDate(): 返回当前的日期和时间。
登录窗口Login
- Login(): 构造函数,加载账户信息,添加监听器。
- login():检查账户是否存在以及密码是否正确。
- loadAccounts(): 从指定文本文件中加载账户信息。
- saveAccounts(): 把所有的账户信息保存到指定文本文件中。
PS:由于使用了Swing UI designer进行界面设计,源代码中没有主要的UI设计代码,需要下载整个文件才能成功运行。
服务器源代码
package Chat;import javax.swing.*;import java.awt.event.*;import java.io.*;import java.net.*;import java.time.format.DateTimeFormatter;import java.util.*;import java.time.LocalDateTime;public class Server {private int port = 5000;private ServerSocket serverSocket = null;private Map clients = new HashMap();private List onlineClient = new ArrayList();private JPanel panel1;private JList userList;private JList sysMessageList;private JTextField sysMessageFiled;private JButton send_Button;private DefaultListModel userListModel;private DefaultListModel sysMessageListModel;private Map<String, List> groups = new HashMap();public void start() throws Exception {JFrame frame = new JFrame("服务器");frame.setContentPane(this.panel1);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.pack();frame.setVisible(true);//聊天信息、好友列表绑定模型userListModel = new DefaultListModel();userList.setModel(userListModel);sysMessageListModel = new DefaultListModel();sysMessageList.setModel(sysMessageListModel);serverSocket = new ServerSocket(port);System.out.println("Server started, listening on port " + port);while (true) {Socket clientSocket = serverSocket.accept();new Thread(new ClientHandler(clientSocket)).start();}}class ClientHandler implements Runnable {private Socket clientSocket;private DataInputStream input;private DataOutputStream output;private String account;ClientHandler(Socket clientSocket) throws Exception {this.clientSocket = clientSocket;this.input = new DataInputStream(clientSocket.getInputStream());this.output = new DataOutputStream(clientSocket.getOutputStream());}@Overridepublic void run() {try {while (true) {String message = readDecrypt(input);System.out.println("Received: " + message);String[] parts = message.split("&", 4);int code = Integer.parseInt(parts[0]);account = parts[1];List groupMembers = new ArrayList(); // 初始化为一个空列表String groupName = parts[1];groupMembers = groups.get(groupName);switch (code) {case 1111:clients.put(account, output);onlineClient.add(account);userListModel.addElement(account);sendOnlineList(account);broadcast("1111&"+account);break;case 2333:broadcast("5555&"+account + ";" + parts[2]);break;case 1333:String recipient = parts[2];String privateMessage = parts[3];sendTo(recipient, account +";"+ privateMessage);break;case 5555: // 创建小组groupName = parts[1];groups.put(groupName, new ArrayList());String account = parts[2];groupMembers = groups.get(groupName);groupMembers.add(account);break;case 6666: // 添加成员到小组String newMember = parts[2];if (groupMembers != null) {groupMembers.add(newMember);DataOutputStream output = clients.get(newMember);encryptWrite("6666&"+groupName, output);}break;case 7777: // 从小组中移除成员String memberToRemove = parts[2];if (groupMembers != null) {groupMembers.remove(memberToRemove);DataOutputStream output = clients.get(memberToRemove);encryptWrite("7777&"+groupName, output);}break;case 8888://小组消息groupName = parts[1];groupMembers = groups.get(groupName);if (groupMembers != null) {broadcastToGroup(groupName,parts[2]);}break;default:System.out.println("Unknown message type: " + code);break;}}} catch (EOFException | SocketException e) {System.err.println("Connection was closed by client or network error occurred.");} catch (Exception e) {e.printStackTrace();} finally {clients.remove(account);onlineClient.remove(account);userListModel.removeElement(account);System.out.println(account+"下线");try {broadcast("4444&"+account);} catch (Exception e) {throw new RuntimeException(e);}try {if (clientSocket != null) {clientSocket.close();}} catch (Exception e) {e.printStackTrace();}}}//广播public void broadcast(String message) throws Exception {for (DataOutputStream output : clients.values()) {encryptWrite(message, output);}}//小组广播public void broadcastToGroup(String groupName, String message) throws Exception {List groupMembers = groups.get(groupName);if (groupMembers != null) {for (String member : groupMembers) {DataOutputStream output = clients.get(member);if (output != null) {encryptWrite("8888&"+groupName+"&"+message, output);}}}}//私聊private void sendTo(String recipient, String message) throws Exception {DataOutputStream output = clients.get(recipient);if (output != null) {//private_encryptWrite(message,output);encryptWrite("0000&"+message, output);} else {System.out.println("Recipient not found: " + recipient);}}//更新用户列表private void sendOnlineList(String recipient)throws Exception{DataOutputStream output = clients.get(recipient);if (output != null) {encryptWrite("2222&" + String.join(",", onlineClient), output);} else {System.out.println("Recipient not found: " + recipient);}}}public Server() {send_Button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {refresh_message();}});sysMessageFiled.addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyChar() == KeyEvent.VK_ENTER)refresh_message();}});userList.addMouseListener(new MouseAdapter() {public void mouseClicked(MouseEvent e) {if (e.getClickCount() == 2) { // 双击事件String selectedUser = userList.getSelectedValue().toString();int confirm = JOptionPane.showConfirmDialog(null, "是否要强制下线用户:" + selectedUser, "强制下线", JOptionPane.YES_NO_OPTION);if (confirm == JOptionPane.YES_OPTION) {forceDisconnect(selectedUser);}}}});}输入//给所有用户、群聊发送系统消息private void refresh_message() {String message = sysMessageFiled.getText();for (DataOutputStream output : clients.values()) {try {encryptWrite("0000&系统消息"+";("+nowDate()+"):"+message, output);} catch (IOException ex) {throw new RuntimeException(ex);}}sysMessageFiled.setText("");sysMessageListModel.addElement("系统消息"+"("+nowDate()+"):"+message);//自动往下滚sysMessageList.ensureIndexIsVisible(sysMessageListModel.size() - 1);}// 强制下线用户private void forceDisconnect(String account) {DataOutputStream output = clients.get(account);if (output != null) {try {encryptWrite("3333",output); // 发送下线信号给客户端output.close();clients.remove(account); // 在服务器端移除该客户端broadcast("4444&" + account); // 广播下线信息} catch (IOException e) {e.printStackTrace();}}}public void broadcast(String message) {for (DataOutputStream output : clients.values()) {try {encryptWrite(message, output);} catch (IOException ex) {throw new RuntimeException(ex);}}}public void encryptWrite(String src,DataOutputStream output)throws IOException{char[] char_arr = src.toCharArray();//加密for(int i=0;i<char_arr.length;i++){output.writeChar(char_arr[i]+13);}//结束标识符output.writeChar(2333);System.out.println(output);output.flush();}public String readDecrypt(DataInputStream input)throws IOException{String rtn = "";while(true){int char_src = input.readChar();if(char_src!=2333){rtn += (char)(char_src-13);}else{break;}}return rtn;}public String nowDate(){LocalDateTime now = LocalDateTime.now();DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");String formatDateTime = now.format(formatter);return formatDateTime;}public static void main(String[] args) {try {Server server = new Server(); // 创建Server对象server.start(); // 运行服务器} catch (IOException e) {e.printStackTrace();} catch (Exception e) {throw new RuntimeException(e);}}}
客户端源代码
package Chat;import javax.swing.*;import javax.swing.event.ListSelectionEvent;import javax.swing.event.ListSelectionListener;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.io.*;import java.net.Socket;import java.time.format.DateTimeFormatter;import java.util.*;import java.util.HashSet;import java.util.List;import java.util.Map;import java.util.Set;import java.util.concurrent.TimeUnit;import java.time.LocalDateTime;import java.lang.Object;public class Client {private String IP = "127.0.0.1";private int port = 5000;public Socket socket = null;public DataOutputStream output = null;public DataInputStream input = null;public String send;public String account ;public String receiver = "聊天大厅";private JPanel panel1;private JTextField message_Field;private JButton send_Button;private JList message_List;private JList friendList;private JLabel ReceiverName;private JButton createGroupButton;private JButton addMemberButton;private JButton removeMemberButton;private List onlineUser = new ArrayList();private DefaultListModel messageListModel;private DefaultListModel friendListModel;private Map chatRecord = new HashMap();private DefaultListModel chatHallRecord = new DefaultListModel();private DefaultListModel systemRecord = new DefaultListModel();private Set highlightFriend = new HashSet();//private Set Group = new HashSet();private List groups = new ArrayList();public static void main(String[] args) throws IOException {Client client = new Client("哈哈哈");client.run();}public Client() {this.account = "momo";init();}public Client(String account) {this.account = account;init();}private void init(){chatRecord.put("系统消息",systemRecord);chatRecord.put("聊天大厅",chatHallRecord);ReceiverName.setText(receiver);message_List.setModel(chatHallRecord);message_List.ensureIndexIsVisible(chatHallRecord.size() - 1);friendList.setCellRenderer(new HighlightedListCellRenderer());send_Button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if(receiver == "系统消息"){JOptionPane.showMessageDialog(null,"无法向系统发送消息!");}else{refresh_message();}}});message_Field.addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyChar() == KeyEvent.VK_ENTER) {if(receiver == "系统消息"){JOptionPane.showMessageDialog(null,"无法向系统发送消息!");}else{refresh_message();}}}});friendList.addListSelectionListener(new ListSelectionListener() {@Overridepublic void valueChanged(ListSelectionEvent e) {String selectFriend = (String) friendList.getSelectedValue();if (selectFriend!=receiver){message_Field.setText("");if(selectFriend == null || selectFriend == "聊天大厅"){receiver = "聊天大厅";}else if(chatRecord.containsKey(selectFriend)){receiver = selectFriend;}else{receiver = selectFriend;chatRecord.put(receiver, new DefaultListModel());}ReceiverName.setText(receiver);DefaultListModel receiveChatHistory = chatRecord.get(receiver);message_List.setModel(receiveChatHistory);message_List.ensureIndexIsVisible(receiveChatHistory.size() - 1);if (highlightFriend.contains(receiver)) {highlightFriend.remove(receiver);}friendList.repaint();friendList.revalidate();}for (Map.Entry entry : chatRecord.entrySet()) {String key = entry.getKey();DefaultListModel value = entry.getValue();System.out.println("Key = " + key + ", Value = " + value);}}});createGroupButton.addActionListener(e -> {String groupName = JOptionPane.showInputDialog("请输入小组名:");if (groupName != null && !groupName.isEmpty()) {try {encryptWrite("5555&" + groupName+"&"+account, output);friendListModel.addElement(groupName);groups.add(groupName);} catch (IOException ex) {ex.printStackTrace();}}});addMemberButton.addActionListener(e -> {// 创建一个列表模型,并添加所有在线用户DefaultListModel listModel = new DefaultListModel();for (String user : onlineUser) {listModel.addElement(user);}JList list = new JList(listModel);list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // 允许选择多个用户int response = JOptionPane.showConfirmDialog(null, new JScrollPane(list), "请选择要添加的成员", JOptionPane.OK_CANCEL_OPTION);if (response == JOptionPane.OK_OPTION) {List selectedUsers = list.getSelectedValuesList();for (String user : selectedUsers) {try {encryptWrite("6666&" + receiver + "&" + user, output);} catch (IOException ex) {ex.printStackTrace();}}}});removeMemberButton.addActionListener(e -> {// 创建一个列表模型,并添加所有在线用户DefaultListModel listModel = new DefaultListModel();for (String user : onlineUser) {listModel.addElement(user);}JList list = new JList(listModel);list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // 允许选择多个用户int response = JOptionPane.showConfirmDialog(null, new JScrollPane(list), "请选择要删除的成员", JOptionPane.OK_CANCEL_OPTION);if (response == JOptionPane.OK_OPTION) {List selectedUsers = list.getSelectedValuesList();for (String user : selectedUsers) {try {encryptWrite("7777&" + receiver + "&" + user, output);} catch (IOException ex) {ex.printStackTrace();}}}});}//发送信息// 刷新消息列表private void refresh_message() {String message = message_Field.getText();message_Field.setText("");String send2 ="";//if (groups.contains(receiver)) { // 如果接收者是一个小组send2 = "8888&" + receiver + "&" + account +"(" + nowDate()+"):"+message; // 使用新的消息类型8888来发送小组消息} else if(!receiver.equals("聊天大厅")){//私聊send2 = "1333&" + account + "&" + receiver + "&(" + nowDate()+"):"+message;}else{//群聊send2 = "2333&" + account + "&(" + nowDate()+"):"+message;}try {encryptWrite(send2, output);} catch (IOException ex) {ex.printStackTrace();}System.out.println(send2);if(chatRecord.containsKey(receiver)){DefaultListModel receiveChatHistory = chatRecord.get(receiver);message_List.setModel(receiveChatHistory);if(!receiver.equals("聊天大厅")&&!groups.contains(receiver))receiveChatHistory.addElement(account+"("+nowDate()+"):"+message);message_List.ensureIndexIsVisible(receiveChatHistory.size() - 1);}else{messageListModel = new DefaultListModel();chatRecord.put(receiver, messageListModel);DefaultListModel receiveChatHistory = chatRecord.get(receiver);message_List.setModel(receiveChatHistory);receiveChatHistory.addElement(account+"("+nowDate()+"):"+message);message_List.ensureIndexIsVisible(receiveChatHistory.size() - 1);}}public void run() throws IOException {try {JFrame frame = new JFrame(account);frame.setContentPane(this.panel1);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.pack();frame.setVisible(true);frame.toFront();frame.requestFocus();// 线程,每秒更新聊天记录new Thread(() -> {while (true) {try {TimeUnit.SECONDS.sleep(1);// 这里添加更新聊天记录或好友列表的代码} catch (InterruptedException e) {e.printStackTrace();}}}).start();Thread.sleep(250);new Thread(() -> {//聊天信息、好友列表绑定模型messageListModel = new DefaultListModel();message_List.setModel(messageListModel);message_List.updateUI();message_List.ensureIndexIsVisible(messageListModel.size() - 1);friendListModel = new DefaultListModel();friendList.setModel(friendListModel);friendListModel.addElement("系统消息");friendListModel.addElement("聊天大厅");receiver = "聊天大厅";message_List.setModel(chatHallRecord);message_List.ensureIndexIsVisible(chatHallRecord.size() - 1);try {socket = new Socket(IP, port);} catch (IOException e) {throw new RuntimeException(e);}try {output = new DataOutputStream(socket.getOutputStream());} catch (IOException e) {throw new RuntimeException(e);}try {input = new DataInputStream(socket.getInputStream());} catch (IOException e) {throw new RuntimeException(e);}//建立连接,上线//把昵称发送给server,以便告知其加入聊天室send = "1111&"+account;try {encryptWrite(send, output);} catch (IOException e) {throw new RuntimeException(e);}//接收消息while (true) {System.out.println(input);String receive = null;try {receive = readDecrypt(input);} catch (IOException e) {throw new RuntimeException(e);}//如果收到 3333 则下线if ("3333".equals(receive)) {JOptionPane.showMessageDialog(null,"你已被强制下线!");frame.dispose();try {input.close();} catch (IOException e) {throw new RuntimeException(e);}try {output.close();} catch (IOException e) {throw new RuntimeException(e);}try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}System.exit(0);}String []parts = receive.split("&");System.out.println(parts[0]);System.out.println(parts[1]);SwingUtilities.invokeLater(()-> {if (parts[0].equals("1111")) {if (!parts[1].equals(account)) {//添加新进入的客户端friendListModel.addElement(parts[1]);onlineUser.add(parts[1]);}} else if (parts[0].equals("2222")) {//添加之前进入的客户端String[] onlineFriend = parts[1].split(",");for (String friend : onlineFriend) {if(!friend.equals(account)) {friendListModel.addElement(friend);onlineUser.add(friend);}}} else if (parts[0].equals("4444")) {//离线friendListModel.removeElement(parts[1]);onlineUser.remove(parts[1]);} else if (parts[0].equals("0000")) {//私聊String sender = parts[1].split(";")[0];System.out.println(sender);//messageListModel.addElement(parts[1]);String message = sender+parts[1].split(";")[1];if (!chatRecord.containsKey(sender)) {chatRecord.put(sender, new DefaultListModel());}DefaultListModel senderChatHistory = chatRecord.get(sender);senderChatHistory.addElement(message);System.out.println("receiver:"+receiver);// 如果这是当前显示的聊天窗口,立即在聊天窗口中显示这条消息if (sender.equals(receiver)) {message_List.setModel(senderChatHistory);message_List.ensureIndexIsVisible(senderChatHistory.size() - 1);}else{highlightFriend.add(sender);friendList.repaint();friendList.revalidate();}}else if (parts[0].equals("8888")) { // 如果是小组消息String groupName = parts[1];String message = parts[2];DefaultListModel groupChatHistory = chatRecord.get(groupName);groupChatHistory.addElement(message);if (groupName.equals(receiver)) { // 如果这是当前显示的小组message_List.setModel(groupChatHistory);message_List.ensureIndexIsVisible(groupChatHistory.size() - 1);} else {highlightFriend.add(groupName);friendList.repaint();friendList.revalidate();}} else if(parts[0].equals("6666")){friendListModel.addElement(parts[1]);groups.add(parts[1]);}else if(parts[0].equals("7777")){friendListModel.removeElement(parts[1]);groups.remove(parts[1]);}else if(parts[0].equals("5555")){//更新群聊聊天记录String [] part = parts[1].split(";");String message = part[0]+part[1];chatHallRecord.addElement(message);if ("聊天大厅".equals(receiver)) {message_List.setModel(chatHallRecord);message_List.ensureIndexIsVisible(chatHallRecord.size() - 1);}else{highlightFriend.add("聊天大厅");friendList.repaint();friendList.revalidate();}}else{System.out.println("非法字符!");}});}}).start();}catch(Exception e){e.printStackTrace();} finally{try {if (socket != null)socket.close();input.close();output.close();} catch (Exception e) {e.printStackTrace();}}}public void encryptWrite(String src,DataOutputStream output)throws IOException {//将一个字符串转化为字符数组char[] char_arr = src.toCharArray();//加密操作for(int i = 0;i<char_arr.length;i++){output.writeChar(char_arr[i]+13);}//用作结束标志符output.writeChar(2333);output.flush();}//读取并解密public String readDecrypt(DataInputStream input)throws IOException{String rtn="";while(true){int char_src =input.readChar();if(char_src!=2333 && char_src!=1333 && char_src!=1111 &&char_src!=3333){rtn=rtn+(char)(char_src-13);}else{break;}}System.out.println(rtn);return rtn;}public String nowDate(){LocalDateTime now = LocalDateTime.now();DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");String formatDateTime = now.format(formatter);return formatDateTime;}//点亮用户public class HighlightedListCellRenderer extends DefaultListCellRenderer {@Overridepublic Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);if (highlightFriend.contains(value)) {component.setBackground(Color.ORANGE);} else {component.setBackground(Color.white);}return component;}}}
登录界面源代码
package Chat;import javax.swing.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.*;import java.util.HashMap;import java.util.Map;public class Login {private JPanel panel1;private JButton Login_Button;private JTextField account_Filed;private JTextField password_Filed;private JLabel welcome_titile;private JFrame frame;private static final String ACCOUNT_FILE = "./src/Chat/account.txt";private static final Map accounts = new HashMap();private String IP = "127.0.0.1";private int port = 5000;public Login() {loadAccounts();setComponents(panel1);Login_Button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String account = account_Filed.getText();String password = password_Filed.getText();//防止未输入,或输入制表符if(account == null || account.trim().equals("")){JOptionPane.showMessageDialog(null,"账号不能为空");return;}if(password == null || password.trim().equals("")){JOptionPane.showMessageDialog(null,"密码不能为空");return;}if (login(account, password)) {SwingUtilities.invokeLater(new Runnable() {@Overridepublic void run() {Client client = new Client(account);try {client.run();} catch (IOException ex) {throw new RuntimeException(ex);}}});frame.dispose();} else {JOptionPane.showMessageDialog(null,"账户名或密码错误!");}}});}private void setComponents(JPanel panel1){}private static boolean login(String account, String password) {if (accounts.containsKey(account)) {String storedPassword = accounts.get(account);if (storedPassword.equals(password)) {return true;}} else {accounts.put(account, password);saveAccounts();return true;}return false;}private static void loadAccounts() {try (BufferedReader reader = new BufferedReader(new FileReader(ACCOUNT_FILE))) {String line;while ((line = reader.readLine()) != null) {String[] parts = line.split(":");if (parts.length == 2) {String username = parts[0];String password = parts[1];accounts.put(username, password);}}} catch (IOException e) {// 处理文件读取异常e.printStackTrace();}}private static void saveAccounts() {try (BufferedWriter writer = new BufferedWriter(new FileWriter(ACCOUNT_FILE))) {for (Map.Entry entry : accounts.entrySet()) {String username = entry.getKey();String password = entry.getValue();String line = username + ":" + password;writer.write(line);writer.newLine();}} catch (IOException e) {// 处理文件写入异常e.printStackTrace();}}public void run(){frame = new JFrame("Login");frame.setContentPane(this.panel1);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.pack();frame.setVisible(true);}public static void main(String[] args) {new Login().run();}}