JAVA版聊天室小软件

这是一篇关于JAVA的聊天室室小软件,用的swing的技术同时也用到了socket。今天发布出来,希望能帮到大家。


开发环境

开发工具:IDEA2021.3.1
JDK版本:JDK8
JDK其他版本会有问题


项目结构

请添加图片描述
启动后服务的Server。

请添加图片描述
启动客户端MainLauncher

下载地址:

链接:https://pan.baidu.com/s/1CqRtwb-5Vbj8J-UmrPFi6w
提取码:4ysl


一、运行画面展示

请添加图片描述
登录界面,选择性别,输入用户名
请添加图片描述
聊天界面,第一个进来的界面里只有一个人

请添加图片描述
再登录一个账号。
请添加图片描述
两个人可以相互通信的界面


二、代码部分

1.客户端启动代码

package com.bjpowernode.client;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class MainLauncher extends Application {
    
    

    private static Stage primaryStageObj;

    @Override
    public void start(Stage primaryStage) throws Exception {
    
    
        primaryStageObj = primaryStage;
        Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("views/LoginView.fxml"));
        primaryStage.initStyle(StageStyle.UNDECORATED);
        primaryStage.setTitle("一起来聊天");
        primaryStage.getIcons().add(new Image(getClass().getClassLoader().getResource("images/logo.png").toString()));
        Scene mainScene = new Scene(root, 350, 420);
        mainScene.setRoot(root);
        primaryStage.setResizable(false);
        primaryStage.setScene(mainScene);
        primaryStage.show();
        primaryStage.setOnCloseRequest(e -> Platform.exit());
    }


    public static void main(String[] args) {
    
    
        launch(args);
    }

    public static Stage getPrimaryStage() {
    
    
        return primaryStageObj;
    }
}

LoginController类

package com.bjpowernode.client.login;



import com.bjpowernode.client.MainLauncher;
import com.bjpowernode.client.chat.ChatController;
import com.bjpowernode.client.chat.Listener;
import com.bjpowernode.client.util.Drag;
import com.bjpowernode.client.util.ThreadPoolUtil;
import com.trynotifications.util.ResizeHelper;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Duration;

import java.io.IOException;
import java.net.URL;
import java.util.Random;
import java.util.ResourceBundle;

public class LoginController implements Initializable {
    
    
    @FXML private ImageView defaultView;
    @FXML private ImageView girlView;
    @FXML private ImageView boyView;
    @FXML public  TextField hostnameTextfield;
    @FXML private TextField portTextfield;
    @FXML private TextField usernameTextfield;
    @FXML private ChoiceBox imagePicker;
    @FXML private Label selectedPicture;
    @FXML private BorderPane borderPane;
    public static ChatController chatController;
    private Scene scene;

    private static LoginController instance;

    public LoginController() {
    
    
        instance = this;
    }

    public static LoginController getInstance() {
    
    
        return instance;
    }

    /**
     *  处理点击登录按钮事件
     * @throws IOException
     */
    public void loginButtonAction() throws IOException {
    
    
        String hostname = hostnameTextfield.getText();
        int port = Integer.parseInt(portTextfield.getText());
        String username = usernameTextfield.getText();
        String picture = selectedPicture.getText();

        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/views/ChatView.fxml"));
        Parent window = (Pane) fxmlLoader.load();
        chatController = fxmlLoader.getController();

        //创建监听器对象
        Listener listener = new Listener(hostname, port, username, picture,chatController);
        //将监听器加入到线程池
        ThreadPoolUtil.poolExecutor.execute(listener);

        this.scene = new Scene(window);
    }

    /**
     *  显示界面场景
     */
    public void showScene() {
    
    
        Platform.runLater(() -> {
    
    
            Stage stage = (Stage) hostnameTextfield.getScene().getWindow();
            stage.setResizable(true);
            stage.setWidth(1040);
            stage.setHeight(620);

            stage.setOnCloseRequest((WindowEvent e) -> {
    
    
                Platform.exit();
                System.exit(0);
            });
            stage.setScene(this.scene);
            stage.setMinWidth(800);
            stage.setMinHeight(300);
            ResizeHelper.addResizeListener(stage);
            stage.centerOnScreen();
            chatController.setUsernameLabel(usernameTextfield.getText());
            chatController.setImageLabel(selectedPicture.getText());
        });
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
    
    
        imagePicker.getSelectionModel().selectFirst();
        selectedPicture.textProperty().bind(imagePicker.getSelectionModel().selectedItemProperty());
        selectedPicture.setVisible(false);

        //处理鼠标拖拽界面
        new Drag().handleDrag(borderPane);

        //处理头像
        imagePicker.getSelectionModel().selectedItemProperty().addListener((ChangeListener<String>) (selected, oldPicture, newPicture) -> {
    
    
            if (!oldPicture.equals(newPicture)) {
    
    
                //隐藏所有头像
                defaultView.setVisible(false);
                boyView.setVisible(false);
                girlView.setVisible(false);

                //展示用户选中的头像
                switch (newPicture) {
    
    
                    case "default":
                        defaultView.setVisible(true);
                        break;
                    case "boy":
                        boyView.setVisible(true);
                        break;
                    case "girl":
                        girlView.setVisible(true);
                        break;
                }
            }
        });
        int numberOfSquares = 30;
        while (numberOfSquares > 0){
    
    
            generateAnimation();
            numberOfSquares--;
        }
    }


    /**
     * 生成随机动画
     */
    public void generateAnimation(){
    
    
        Random rand = new Random();
        int size = rand.nextInt(50) + 1;
        int speed = rand.nextInt(10) + 5;
        int startXPoint = rand.nextInt(420);
        int startYPoint = rand.nextInt(350);
        int direction = rand.nextInt(5) + 1;

        KeyValue moveXAxis = null;
        KeyValue moveYAxis = null;
        Rectangle r1 = null;

        switch (direction){
    
    
            case 1 :
                // MOVE LEFT TO RIGHT
                r1 = new Rectangle(0,startYPoint,size,size);
                moveXAxis = new KeyValue(r1.xProperty(), 350 -  size);
                break;
            case 2 :
                // MOVE TOP TO BOTTOM
                r1 = new Rectangle(startXPoint,0,size,size);
                moveYAxis = new KeyValue(r1.yProperty(), 420 - size);
                break;
            case 3 :
                // MOVE LEFT TO RIGHT, TOP TO BOTTOM
                r1 = new Rectangle(startXPoint,0,size,size);
                moveXAxis = new KeyValue(r1.xProperty(), 350 -  size);
                moveYAxis = new KeyValue(r1.yProperty(), 420 - size);
                break;
            case 4 :
                // MOVE BOTTOM TO TOP
                r1 = new Rectangle(startXPoint,420-size ,size,size);
                moveYAxis = new KeyValue(r1.xProperty(), 0);
                break;
            case 5 :
                // MOVE RIGHT TO LEFT
                r1 = new Rectangle(420-size,startYPoint,size,size);
                moveXAxis = new KeyValue(r1.xProperty(), 0);
                break;
            case 6 :
                //MOVE RIGHT TO LEFT, BOTTOM TO TOP
                r1 = new Rectangle(startXPoint,0,size,size);
                moveXAxis = new KeyValue(r1.yProperty(), 420 - size);
                moveYAxis = new KeyValue(r1.xProperty(), 350 -  size);
                break;
        }

        r1.setFill(Color.web("#F89406"));
        r1.setOpacity(0.1);

        KeyFrame keyFrame = new KeyFrame(Duration.millis(speed * 1000), moveXAxis, moveYAxis);
        Timeline timeline = new Timeline();
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.setAutoReverse(true);
        timeline.getKeyFrames().add(keyFrame);
        timeline.play();
        borderPane.getChildren().add(borderPane.getChildren().size()-1,r1);
    }

    /**
     * 关闭
     */
    public void closeSystem(){
    
    
        Platform.exit();
        System.exit(0);
    }

    /**
     * 最小化
     */
    public void minimizeWindow(){
    
    
        MainLauncher.getPrimaryStage().setIconified(true);
    }


}

ChatController类

package com.bjpowernode.client.chat;

import com.bjpowernode.bean.Message;

import com.bjpowernode.bean.User;
import com.bjpowernode.client.util.Drag;
import com.bjpowernode.client.util.ThreadPoolUtil;
import com.trynotifications.animations.AnimationType;
import com.trynotifications.bean.BubbleSpec;
import com.trynotifications.bean.BubbledLabel;
import com.trynotifications.notification.TrayNotification;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.util.Duration;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;


public class ChatController implements Initializable {
    
    

    @FXML private TextArea messageBox;
    @FXML private Label usernameLabel;//显示的用户名
    @FXML private Label onlineCountLabel;//显示在线用户总数
    @FXML private ListView userList;//在线用户
    @FXML private ImageView userImageView;//头像
    @FXML ListView chatPane;
    @FXML BorderPane borderPane;

    /**
     * 处理发送按钮点击事件
     * @throws IOException
     */
    public void sendButtonAction() throws IOException {
    
    
        //获取用户输入的消息
        String msg = messageBox.getText();
        if (!msg.isEmpty()) {
    
    
            Listener.instance.send(msg);
            //清空输入框的消息
            messageBox.clear();
        }
    }


    /**
     *  显示发送的消息
     * @param msg
     */
    public synchronized void showMsg(Message msg) {
    
    

        //别人发送的信息
        Task<HBox> othersMessages = new Task<HBox>() {
    
    
            @Override
            public HBox call() {
    
    
                Image image = new Image(getClass().getClassLoader().getResource("images/" + msg.getPicture().toLowerCase() + ".png").toString());
                ImageView profileImage = new ImageView(image);
                profileImage.setFitHeight(32);
                profileImage.setFitWidth(32);
                BubbledLabel bl = new BubbledLabel();
                bl.setText(msg.getName() + ": " + msg.getMsg());
                bl.setBackground(new Background(new BackgroundFill(Color.WHITE,null, null)));
                HBox x = new HBox();
                bl.setBubbleSpec(BubbleSpec.FACE_LEFT_CENTER);
                x.getChildren().addAll(profileImage, bl);
                setOnlineLabel(String.valueOf(msg.getOnlineUsers().size()));
                return x;
            }
        };

        othersMessages.setOnSucceeded(event ->
            chatPane.getItems().add(othersMessages.getValue())
        );

        //自己发送的信息
        Task<HBox> yourMessages = new Task<HBox>() {
    
    
            @Override
            public HBox call() {
    
    
                Image image = userImageView.getImage();
                ImageView profileImage = new ImageView(image);
                profileImage.setFitHeight(32);
                profileImage.setFitWidth(32);

                BubbledLabel bl = new BubbledLabel();
                bl.setText(msg.getMsg());
                bl.setBackground(new Background(new BackgroundFill(Color.LIGHTGREEN,
                        null, null)));
                HBox x = new HBox();
                x.setMaxWidth(chatPane.getWidth() - 20);
                x.setAlignment(Pos.TOP_RIGHT);
                bl.setBubbleSpec(BubbleSpec.FACE_RIGHT_CENTER);
                x.getChildren().addAll(bl, profileImage);

                setOnlineLabel(String.valueOf(msg.getOnlineUsers().size()));
                return x;
            }
        };
        yourMessages.setOnSucceeded(event -> chatPane.getItems().add(yourMessages.getValue()));

        //将任务交给线程池运行
        if (msg.getName().equals(usernameLabel.getText())){
    
    
            //自己发送的消息
            ThreadPoolUtil.poolExecutor.execute(yourMessages);
        }else {
    
    
            //别人发送的消息
            ThreadPoolUtil.poolExecutor.execute(othersMessages);
        }

    }
    public void setUsernameLabel(String username) {
    
    
        this.usernameLabel.setText(username);
    }

    public void setOnlineLabel(String count) {
    
    
        Platform.runLater(() -> onlineCountLabel.setText(count));
    }

    public void setUserList(Message msg) {
    
    
        Platform.runLater(() -> {
    
    
            ObservableList<User> users = FXCollections.observableList(msg.getOnlineUsers());
            userList.setItems(users);
            userList.setCellFactory(new CellRenderer());
            setOnlineLabel(String.valueOf(msg.getOnlineUsers().size()));
        });
    }


    /**
     *  用户提示
     * @param msg
     * @param picture
     * @param title
     * @param sound
     */
    public void notify(String msg,String picture,String title,String sound) {
    
    
        Platform.runLater(() -> {
    
    
            Image profileImg = new Image(getClass().getClassLoader().getResource("images/" + picture +".png").toString(),50,50,false,false);
            TrayNotification tray = new TrayNotification();
            tray.setTitle(title);
            tray.setMessage(msg);
            tray.setRectangleFill(Paint.valueOf("#2C3E50"));
            tray.setAnimationType(AnimationType.POPUP);
            tray.setImage(profileImg);
            tray.showAndDismiss(Duration.seconds(5));
            try {
    
    
                Media hit = new Media(getClass().getClassLoader().getResource(sound).toString());
                MediaPlayer mediaPlayer = new MediaPlayer(hit);
                mediaPlayer.play();
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }

        });
    }

    public void sendMethod(KeyEvent event) throws IOException {
    
    
        if (event.getCode() == KeyCode.ENTER) {
    
    
            sendButtonAction();
        }
    }

    @FXML
    public void closeApplication() {
    
    
        Platform.exit();
        System.exit(0);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
    
    

        //处理鼠标拖拽界面
        new Drag().handleDrag(borderPane);

        //处理按下回车事件
        messageBox.addEventFilter(KeyEvent.KEY_PRESSED, ke -> {
    
    
            if (ke.getCode().equals(KeyCode.ENTER)) {
    
    
                try {
    
    
                    sendButtonAction();
                } catch (IOException e) {
    
    
                    e.printStackTrace();
                }
                ke.consume();
            }
        });

    }

    public void setImageLabel(String selectedPicture) {
    
    
        String path = "";

        switch (selectedPicture) {
    
    
            case "boy":
                path = "images/boy.png";
                break;
            case "girl":
                path = "images/girl.png";
                break;
            case "default":
                path = "images/default.png";
                break;
        }

        this.userImageView.setImage(new Image(getClass().getClassLoader().getResource(path).toString()));
    }

}

CellRenderer类

package com.bjpowernode.client.chat;

import com.bjpowernode.bean.User;
import javafx.geometry.Pos;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.util.Callback;

/**
 * A Class for Rendering users images / name on the userlist.
 */
class CellRenderer implements Callback<ListView<User>, ListCell<User>> {
    
    
    @Override
    public ListCell<User> call(ListView<User> p) {
    
    

        ListCell<User> cell = new ListCell<User>() {
    
    

            @Override
            protected void updateItem(User user, boolean bln) {
    
    
                super.updateItem(user, bln);
                setGraphic(null);
                setText(null);
                if (user != null) {
    
    
                    HBox hBox = new HBox();

                    Text name = new Text(user.getName());

                    ImageView statusImageView = new ImageView();

                    ImageView pictureImageView = new ImageView();
                    Image image = new Image(getClass().getClassLoader().getResource("images/" + user.getPicture().toLowerCase() + ".png").toString(), 50, 50, true, true);
                    pictureImageView.setImage(image);

                    hBox.getChildren().addAll(statusImageView, pictureImageView, name);
                    hBox.setAlignment(Pos.CENTER_LEFT);

                    setGraphic(hBox);
                }
            }
        };
        return cell;
    }
}

Listener类

package com.bjpowernode.client.chat;

import com.bjpowernode.bean.Message;
import com.bjpowernode.bean.MessageType;
import com.bjpowernode.client.login.LoginController;

import java.io.*;
import java.net.Socket;

/*
    监听客户端和服务器端的消息
 */
public class Listener implements Runnable {
    
    

    private String hostname;
    private int port;
    private String username;
    private String picture;
    private Socket socket;

    private ObjectInputStream ois;
    private InputStream inputStream;
    private ObjectOutputStream oos;
    private OutputStream outputStream;

    private ChatController chatController;

    public static Listener instance;

    public Listener(String hostname, int port, String username, String picture,ChatController chatController) {
    
    
        this.hostname = hostname;
        this.port = port;
        this.username = username;
        this.picture = picture;
        this.chatController = chatController;
        instance = this;
    }

    @Override
    public void run() {
    
    
        //获取socket对象
        try {
    
    
            socket = new Socket(hostname, port);
            outputStream = socket.getOutputStream();
            oos = new ObjectOutputStream(outputStream);
            inputStream = socket.getInputStream();
            ois = new ObjectInputStream(inputStream);

            connect();

            while (socket.isConnected()) {
    
    
                Message message = (Message)ois.readObject();
                if (message != null) {
    
    
                    switch (message.getType()) {
    
    
                        case NOTIFICATION:
                            LoginController.getInstance().showScene();
                            chatController.notify(message.getName() + "加入聊天",message.getPicture(),"新朋友加入","sounds/Global.wav");
                            break;
                        case ERROR:
                            chatController.notify(message.getMsg(),message.getPicture(),"出问题了","sounds/system.wav");
                            break;
                        case JOINED:
                        case DISCONNECTED:
                            chatController.setUserList(message);
                            break;
                        case TEXT:
                            chatController.showMsg(message);
                            break;
                    }
                }

            }

        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    /*
        发送文字消息
     */
    public void send(String msg) throws IOException {
    
    
        Message message = new Message();
        message.setName(username);
        message.setType(MessageType.TEXT);
        message.setMsg(msg);
        message.setPicture(picture);
        oos.writeObject(message);
        oos.flush();
    }

    /*
        连接
     */
    public void connect() throws IOException {
    
    
        Message message = new Message();
        message.setName(username);
        message.setType(MessageType.JOINED);
        message.setPicture(picture);
        message.setMsg("已连接");

        oos.writeObject(message);
    }
}

Drag类

package com.bjpowernode.client.util;

import com.bjpowernode.client.MainLauncher;
import javafx.scene.Cursor;
import javafx.scene.layout.BorderPane;

/**
 *  鼠标拖拽界面的处理
 */
public class Drag {
    
    
    private double xOffset;
    private double yOffset;

    public void handleDrag(BorderPane borderPane) {
    
    

        borderPane.setOnMousePressed(event -> {
    
    
            xOffset = MainLauncher.getPrimaryStage().getX() - event.getScreenX();
            yOffset = MainLauncher.getPrimaryStage().getY() - event.getScreenY();
            borderPane.setCursor(Cursor.CLOSED_HAND);
        });

        borderPane.setOnMouseDragged(event -> {
    
    
            MainLauncher.getPrimaryStage().setX(event.getScreenX() + xOffset);
            MainLauncher.getPrimaryStage().setY(event.getScreenY() + yOffset);

        });

        borderPane.setOnMouseReleased(event -> {
    
    
            borderPane.setCursor(Cursor.DEFAULT);
        });
    }
}

ThreadPoolUtil类

package com.bjpowernode.client.util;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolUtil {
    
    
    public static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3, 4, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(2));
}

2.后台启动代码

package com.bjpowernode.server;

import com.bjpowernode.bean.User;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Server {
    
    
    public static HashMap<String, User> userMap = new HashMap<>();
    public static HashSet<ObjectOutputStream> writers = new HashSet<>();
    //线程池对象
    public static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(16, 32, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(16));

    public static void main(String[] args) {
    
    
        try(ServerSocket listener = new ServerSocket(9001)) {
    
    
            while (true) {
    
    
                poolExecutor.execute(new Handler(listener.accept()));
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}

Handler.class类

package com.bjpowernode.server;

import com.bjpowernode.bean.Message;
import com.bjpowernode.bean.MessageType;
import com.bjpowernode.bean.User;

import java.io.*;
import java.net.Socket;
import java.util.ArrayList;

/*
    服务器端的处理器
 */
public class Handler implements Runnable {
    
    

    private Socket socket;

    private ObjectInputStream ois;
    private InputStream inputStream;
    private ObjectOutputStream oos;
    private OutputStream outputStream;

    private User user;

    public Handler(Socket socket) {
    
    
        this.socket = socket;
    }

    @Override
    public void run() {
    
    
        try {
    
    
            inputStream = socket.getInputStream();
            ois = new ObjectInputStream(inputStream);
            outputStream = socket.getOutputStream();
            oos = new ObjectOutputStream(outputStream);

            //将新加入的用户的输出流对象放入到set中
            Server.writers.add(oos);

            //获取客户端第一次登录的消息
            Message firstMessage = (Message) ois.readObject();

            if (!checkDuplicateUsername(firstMessage)) {
    
    
                return;
            }

            sendNotification(firstMessage);

            showOnlineUser();

            while (socket.isConnected()) {
    
    
                Message message = (Message) ois.readObject();
                switch (message.getType()) {
    
    
                    case TEXT:
                        write(message);
                        break;
                }
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            closeConnection();
        }
    }

    /*
        校验用户昵称是否重复
        要同步
     */
    private synchronized boolean checkDuplicateUsername(Message message) throws IOException {
    
    
        if (!Server.userMap.containsKey(message.getName())) {
    
    
            user = new User();
            user.setName(message.getName());
            user.setPicture(message.getPicture());
            Server.userMap.put(message.getName(), user);
            return true;
        } else {
    
    
            message.setMsg("用户名重复");
            message.setType(MessageType.ERROR);
            //将消息返回给当前登录者
            this.oos.writeObject(message);
            return false;
        }
    }


    /*
        客户端显示加入群聊消息
     */
    private void sendNotification(Message msg) throws IOException {
    
    
        msg.setMsg("加入群聊");
        msg.setType(MessageType.NOTIFICATION);

        write(msg);
    }

    /*
        向客户端展示当前在线用户
     */
    private void showOnlineUser() throws IOException {
    
    
        Message msg = new Message();
        msg.setMsg("欢迎加入聊天");
        msg.setName("SERVER");
        msg.setType(MessageType.JOINED);
        write(msg);
    }

    /*
        向客户端发送消息
     */
    private void write(Message msg) throws IOException {
    
    

        //设置在线用户
        msg.setOnlineUsers(new ArrayList<>(Server.userMap.values()));

        for (ObjectOutputStream writer : Server.writers) {
    
    
            writer.writeObject(msg);
        }
    }

    /*
        关闭链接
     */
    private void closeConnection() {
    
    
        try {
    
    
            //从用户map中移除退出的用户
            if (user.getName() != null) {
    
    
                Server.userMap.remove(user.getName());
            }

            if (oos != null) {
    
    
                Server.writers.remove(oos);
            }

            if (inputStream != null) {
    
    
                inputStream.close();
            }
            if (outputStream != null) {
    
    
                outputStream.close();
            }
            if (ois != null) {
    
    
                ois.close();
            }
            if (oos != null) {
    
    
                oos.close();
            }

            //通知其他在线用户,从在线用户列表中移除当前用户信息
            Message message = new Message();
            message.setMsg("离开聊天");
            message.setType(MessageType.DISCONNECTED);
            message.setName("SERVER");
            write(message);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

}

3.启动方法

先启动后台。找到com/bjpowernode/server/Server.java类,点击图中三角号。
请添加图片描述
让后台运行起来,如图:
请添加图片描述
后来启动起来的画面,只是多了一个窗口,并没有其他的变化。

接下来启动客户端,找到com/bjpowernode/client/MainLauncher.java类
请添加图片描述
点击图中三角号,启动客户端。
启动后,进入登录界面:
请添加图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45345143/article/details/127716787