<Java>20 项目(多用户通讯系统)

本文最后更新于:2022年5月24日 早上

20 项目:多用户通讯系统

项目见(多用户通讯系统)

服务端启动位置(多用户通讯系统\项目:通讯系统(服务端)\src\com\melody\transmission\common\ClientConnect.java)

客户端启动位置(项目:通讯系统(客户端)\src\com\melody\transmission\Test1.java)

20.1 需求分析

  1. 用户登录
  2. 拉取在线用户列表
  3. 无异常退出(客户端、服务端)
  4. 私聊
  5. 群聊
  6. 发文件
  7. 服务器推送新闻

20.1.1 登录

服务端

  1. 客户端连接到服务器后,会得到一个 Socket
  2. 启动一个线程,该线程持有该 Socket 对象
  3. 为了更好地管理线程,需要使用集合来管理

客户端

  1. 和服务端通信时,使用对象方式,可以使用对象流来读写
  2. 客户端连接到服务端后,也会得到 Socket
  3. 启动一个线程,该线程持有该 Socket 对象
  4. 为了更好地管理线程,需要使用集合来管理

20.1.2 无异常退出

写下面内容的之前,我已经把代码都完成了。

韩老师的思路都是最基本的思路,这些其实应该不参考笔记自己去想。

想不通的地方才看答案(笔记),我认为是比较好的方法。

服务端

  1. 服务器端和某个客户端通信的线程接到一个退出请求后,关闭 socket 并退出线程

客户端

  1. 调用方法,向服务端发送登出请求,之后客户端调用方法正常退出

下略

没记

附录

多用户通讯系统

开始写的时候思路没整理好,最后乱七八糟的

又没什么注释,所以别往下翻了

通用部分(客户端 & 服务端)

MyTools.java:工具类

UserData.java:用户数据类,包含完整的用户信息。这些信息存储在服务端。每个客户端只可能在验证通过的场合,持有最多一个来自服务端的属于客户自己的该类对象

User.java:简易的用户类。只是用以传递一组账号和密码。一般由客户端发送往服务端。这些账号和密码未必是正确的。

Message.java:数据包。客户端和服务端的所有通信都以传递该数据包的形式进行。

MessageType.java:代码表。客户端和服务端各自持有一份相同的该表,用以对数据包进行识别。

  • MyTools.java

    精简了一下放上来

    package com;
    
    import java.io.*;
    import java.util.Arrays;
    import java.util.Scanner;
    
    public class MyTools {
        private static Scanner inp = new Scanner(System.in);
    
    
        //这个方法能读取一个 输入流 的内容
        public static byte[] whatInputIs(InputStream is) throws IOException {
            ByteArrayOutputStream bis = new ByteArrayOutputStream();
            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = is.read(bytes, 0, bytes.length)) != -1) {
                bis.write(bytes, 0, len);
            }
            return bis.toByteArray();
        }
    }
  • User.java

    package com.melody.transmission.common;
    
    import java.io.Serializable;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class User implements Serializable {
        private String id;
        private String pw;
    
        public User(String id, String pw) {
            this.id = id;
            this.pw = pw;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getPw() {
            return pw;
        }
    
        public void setPw(String pw) {
            this.pw = pw;
        }
    }
  • UserData.java

    package com.melody.transmission.common;
    
    import java.io.Serializable;
    import java.util.Objects;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class UserData implements Serializable {
    
        private static final long serialVersionUID = 1L;
        private final String ID;
        private String name;
        private String pw;
        private boolean online = false;
        private String[] friendID;
        public final StringBuilder leftMessage = new StringBuilder();
    
        UserData(String name, String pw, String ID) {
            this.name = name;
            this.pw = pw;
            this.ID = ID;
        }
    
        public String getId() {
            return ID;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPw() {
            return pw;
        }
    
        public void setPw(String pw) {
            this.pw = pw;
        }
    
        public boolean isOnline() {
            return online;
        }
    
        public void setOnline(boolean online) {
            this.online = online;
        }
    
        public String listed() {
            return ((online ? "·在线" : "离线中") + "\t用户名:(" + ID + ")" + name);
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            UserData userData = (UserData) o;
            return online == userData.online && Objects.equals(ID, userData.ID) && Objects.equals(name, userData.name) && Objects.equals(pw, userData.pw);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(ID, name, pw, online);
        }
    }
  • Message.java

    package com.melody.transmission.common;
    
    import java.io.Serializable;
    import java.time.LocalDateTime;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class Message implements Serializable, MessageType {
    
        private static final long serialVersionUID = 1L;
        private String message;
        private String time;
        private String sender;
        private String receiver;
        private String messageType;
        private Object object;
    
        public Message(String message, String sender, String receiver, String messageType) {
            this.message = message;
            this.time = getDateTime();
            this.sender = sender;
            this.receiver = receiver;
            this.messageType = messageType;
        }
    
        public Object getObject() {
            return object;
        }
    
        public void setObject(Object object) {
            this.object = object;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public String getTime() {
            return time;
        }
    
        public void setTime(String time) {
            this.time = time;
        }
    
        public String getSender() {
            return sender;
        }
    
        public void setSender(String sender) {
            this.sender = sender;
        }
    
        public String getReceiver() {
            return receiver;
        }
    
        public void setReceiver(String receiver) {
            this.receiver = receiver;
        }
    
        public String getMessageType() {
            return messageType;
        }
    
        public void setMessageType(String messageType) {
            this.messageType = messageType;
        }
    
        private static String getDate() {
            return getDate(LocalDateTime.now());
        }
    
        private static String getDate(LocalDateTime ldt) {
            int mon = ldt.getMonthValue();
            int day = ldt.getDayOfMonth();
            return ldt.getYear() + "." + (mon < 10 ? "0" + mon : mon) + "." + (day < 10 ? "0" + day : day);
        }
    
        private static String time() {
            return time(LocalDateTime.now());
        }
    
        private static String time(LocalDateTime ldt) {
            int hour = ldt.getHour();
            int min = ldt.getMinute();
            int sec = ldt.getSecond();
            return (hour < 10 ? "0" + hour : hour) + ":" + (min < 10 ? "0" + min : min) + ":" + (sec < 10 ? "0" + sec : sec);
        }
    
        public static String getDateTime() {
            LocalDateTime ldt = LocalDateTime.now();
            return getDate(ldt) + "  " + time();
        }
    }
  • MessageType.java

    package com.melody.transmission.common;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public interface MessageType {
        String LOGIN_SUCCESS = "lS";
        String LOGIN_FAILED = "lF";
        String LOGIN_USER_NOT_EXIST = "lU";
        String LOGIN_WRONG_PW = "lP";
        String LOGGED_SHOW_LIST = "11SL";
        String LOGGED_SHOW_ONLINE_LIST = "11SO";
        String CHAT = "CM";
        String GROUP_CHAT = "GM";
        String FILE = "CF";
        String LOGGED_CHANGE_NAME = "15CN";
        String LOGGED_CHANGE_PW = "16CP";
        String LOGGED_CHANGE_HIDE = "17CH";
        String LOGGED_LOGOUT = "19OT";
        String REQUEST_ALLOWED = "RE";
        String REQUEST_REJECTED = "RR";
        String REPEAT_LOGIN = "EXC_RL";
    }

服务端

ClientConnet.java:入口

ClientLogin.java:管理所有登录活动。该线程将持续监听用户登录。用户登录成功后启动一个专用的会话线程。

Serve.java:这就是那个专用会话线程。会持续监听用户请求,并作出反应。

ServeCollection.java:该类收集所有活动中的 Serve 线程。

UserDataEnum.java:记录所有用户数据的枚举类。数据库的替代方法(还没学数据库)

  • ClientConnet.java(入口)

    package com.melody.transmission.common;
    
    import com.melody.transmission.login.ClientLogin;
    
    import java.net.Socket;
    import java.util.HashMap;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class ClientConnect {
        public final static String thisIP = "192.168.3.16";
        public final static HashMap<String, UserData> data = new HashMap<>();
        public final static HashMap<String, Socket> sockets = new HashMap<>();
        static {
            for (UserDataEnum userData : UserDataEnum.values()) {
                data.put(userData.user.getId(), userData.user);
            }
        }
    
    
        public static void main(String[] args){
            new Thread(new ClientLogin()).start();
        }
    }
  • ClientLogin.java

    package com.melody.transmission.login;
    
    import com.melody.transmission.common.*;
    import com.melody.transmission.connected.Serve;
    
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.InetAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class ClientLogin implements Runnable {
        @Override
        public void run() {
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket(9000);
                while (true) {
                    login(serverSocket);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private void login(ServerSocket serverSocket) throws IOException {
            Socket clientSocket = serverSocket.accept();
    
            ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
            ObjectOutputStream oos = new ObjectOutputStream(clientSocket.getOutputStream());
    
            String checkRes;
            User clientUser = null;
    
            Message toSend = new Message(null, InetAddress.getLocalHost().getHostAddress(), clientSocket.getInetAddress().getHostAddress(), null);
            toSend.setObject(null);
    
            try {
                clientUser = (User) ois.readObject();
                checkRes = checkUserData(clientUser);
            } catch (Exception e) {
                checkRes = MessageType.LOGIN_FAILED;
            }
            toSend.setMessageType(checkRes);
            if (checkRes.equals(MessageType.LOGIN_SUCCESS)) {
                ClientConnect.data.get(clientUser.getId()).setOnline(true);
                toSend.setObject(ClientConnect.data.get(clientUser.getId()));
                oos.writeObject(toSend);
                Serve serve = new Serve(clientSocket, oos, ois, clientUser.getId());
                new Thread(serve).start();
    //            ClientSocketsCollection.addSocket(clientUser.getId(), clientSocket);
                ServeCollection.add(clientUser.getId(), serve);
            } else {
                oos.writeObject(toSend);
                oos.close();
                ois.close();
                clientSocket.close();
            }
        }
    
        private String checkUserData(User inp) {
            UserData inpIDUser = ClientConnect.data.get(inp.getId());
            if (inpIDUser == null) {
                return MessageType.LOGIN_USER_NOT_EXIST;
            } else if (!inpIDUser.getPw().equals(inp.getPw())) {
                return MessageType.LOGIN_WRONG_PW;
            }
            Serve temp = ServeCollection.get(inpIDUser.getId());
            if (temp != null){
                try {
                    temp.sendRepeatLoginException();
                    System.out.println(Message.getDateTime() + " " + temp.id + " 重复登陆");
                    temp.forceLogout();
                } catch (IOException e) {
                    return MessageType.LOGIN_FAILED;
                }
            }
            return MessageType.LOGIN_SUCCESS;
        }
    }
  • Serve.java(主干)

    package com.melody.transmission.connected;
    
    import com.melody.transmission.common.*;
    
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.Socket;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class Serve implements Runnable {
        private Socket clientSocket;
        private ObjectOutputStream oos;
        private ObjectInputStream ois;
        private boolean connecting = true;
        public final String id;
    
        public Serve(Socket clientSocket, ObjectOutputStream oos, ObjectInputStream ois, String id) {
            this.clientSocket = clientSocket;
            this.oos = oos;
            this.ois = ois;
            this.id = id;
        }
    
        @Override
        public void run() {
            System.out.println(Message.getDateTime() + " " + id + " 登录 " + clientSocket.getLocalAddress().getHostName());
            ClientConnect.data.get(id).setOnline(true);
            while (connecting) {
                try {
                    serve();
                } catch (IOException | ClassNotFoundException e) {
                    try {
                        forceLogout();
                        System.out.println(Message.getDateTime() + " " + id + " 系统强行登出 " + e.toString());
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }
    
        private void serve() throws IOException, ClassNotFoundException {
            Message inp = (Message) ois.readObject();
            Message toSend = new Message(null, ClientConnect.thisIP, clientSocket.getInetAddress().getHostAddress(), null);
            if (inp == null) {
                return;
            } else if (inp.getMessageType().equals(MessageType.LOGGED_SHOW_LIST)) {
                sendList(inp, toSend);
            } else if (inp.getMessageType().equals(MessageType.LOGGED_CHANGE_NAME)) {
                setNewName(inp, toSend);
            } else if (inp.getMessageType().equals(MessageType.LOGGED_CHANGE_HIDE)) {
                changeHide(inp, toSend);
            } else if (inp.getMessageType().equals(MessageType.LOGGED_CHANGE_PW)) {
                changPw(inp, toSend);
            } else if (inp.getMessageType().equals(MessageType.LOGGED_SHOW_ONLINE_LIST)) {
                sendOnlineList(inp, toSend);
            } else if (inp.getMessageType().equals(MessageType.CHAT)) {
                chat(inp, toSend);
            } else if (inp.getMessageType().equals(MessageType.GROUP_CHAT)) {
                groupChat(inp, toSend);
            } else if (inp.getMessageType().equals(MessageType.LOGGED_LOGOUT)) {
                logout(inp);
            } else if (inp.getMessageType().equals(MessageType.FILE)) {
                sendFile(inp, toSend);
            }
        }
    
    
        private void sendList(Message inp, Message toSend) throws IOException {
            StringBuilder sb = new StringBuilder();
            for (UserData userData : ClientConnect.data.values()) {
                sb.append(userData.listed());
                sb.append("\n");
            }
            toSend.setMessage(sb.toString());
            toSend.setMessageType(MessageType.REQUEST_ALLOWED);
            oos.writeObject(toSend);
        }
    
        private void sendOnlineList(Message inp, Message toSend) throws IOException {
            StringBuilder sb = new StringBuilder();
            for (UserData userData : ClientConnect.data.values()) {
                if (userData.isOnline()) {
                    sb.append(userData.listed());
                    sb.append("\n");
                }
            }
            toSend.setMessage(sb.toString());
            toSend.setMessageType(MessageType.REQUEST_ALLOWED);
            oos.writeObject(toSend);
        }
    
        private void setNewName(Message inp, Message toSend) throws IOException {
            String newName = inp.getMessage();
            UserData temp = (UserData) inp.getObject();
            if (!temp.getId().equals(id) || !temp.equals(ClientConnect.data.get(id))) {
                toSend.setMessageType(MessageType.REQUEST_REJECTED);
            } else {
                temp.setName(newName);
                ClientConnect.data.put(id, temp);
                toSend.setObject(ClientConnect.data.get(temp.getId()));
                toSend.setMessageType(MessageType.REQUEST_ALLOWED);
            }
            oos.writeObject(toSend);
        }
    
        private void changPw(Message inp, Message toSend) throws IOException {
            String newPw = inp.getMessage();
            UserData temp = (UserData) inp.getObject();
            if (!temp.getId().equals(id) || !temp.equals(ClientConnect.data.get(id))) {
                toSend.setMessageType(MessageType.REQUEST_REJECTED);
            } else {
                temp.setPw(newPw);
                ClientConnect.data.put(id, temp);
                toSend.setObject(ClientConnect.data.get(id));
                toSend.setMessageType(MessageType.REQUEST_ALLOWED);
            }
            oos.writeObject(toSend);
        }
    
        private void changeHide(Message inp, Message toSend) throws IOException {
            UserData temp = (UserData) inp.getObject();
            if (!temp.getId().equals(id) || !temp.equals(ClientConnect.data.get(id))) {
                toSend.setMessageType(MessageType.REQUEST_REJECTED);
            } else {
                temp.setOnline(!temp.isOnline());
                ClientConnect.data.put(id, temp);
                toSend.setObject(ClientConnect.data.get(temp.getId()));
                toSend.setMessageType(MessageType.REQUEST_ALLOWED);
            }
            oos.writeObject(toSend);
        }
    
        private void chat(Message inp, Message toSend) throws IOException {
            User[] users = (User[]) inp.getObject();
            if (!users[0].getId().equals(id) || !users[0].getPw().equals(ClientConnect.data.get(id).getPw())) {
                toSend.setMessageType(MessageType.REQUEST_REJECTED);
            } else if (users[1].getId().equals(id) || ClientConnect.data.get(users[1].getId()) == null) {
                toSend.setMessageType(MessageType.REQUEST_REJECTED);
            } else {
                UserData tar = ClientConnect.data.get(users[1].getId());
                UserData form = ClientConnect.data.get(id);
                StringBuilder send = new StringBuilder();
                toSend.setMessageType(MessageType.CHAT);
                send.append(inp.getTime()).append(" ").append(form.getName()).append(" 对 你 说:").append(inp.getMessage());
                if (ServeCollection.get(tar.getId()) != null) {
                    toSend.setMessage(send.toString());
                    ServeCollection.get(tar.getId()).oos.writeObject(toSend);
                } else {
                    ClientConnect.data.get(tar.getId()).leftMessage.append(send).append("\n");
                }
                toSend.setObject(new User(tar.getName(), null));
                toSend.setMessageType(MessageType.REQUEST_ALLOWED);
            }
            oos.writeObject(toSend);
        }
    
        private void groupChat(Message inp, Message toSend) throws IOException {
            User user = (User) inp.getObject();
            if (!user.getId().equals(id) || !user.getPw().equals(ClientConnect.data.get(id).getPw())) {
                toSend.setMessageType(MessageType.REQUEST_REJECTED);
            } else {
                toSend.setMessageType(MessageType.GROUP_CHAT);
                String word = "[群发]" + inp.getTime() + " " + ClientConnect.data.get(id).getName() +
                        " 说:" + inp.getMessage();
                toSend.setMessage(word);
                for (Serve serve : ServeCollection.toValue()) {
                    serve.oos.writeObject(toSend);
                }
                toSend.setMessageType(MessageType.REQUEST_ALLOWED);
            }
            oos.writeObject(toSend);
        }
    
        private void sendFile(Message inp, Message toSend) throws IOException {
            User user = new User(id, inp.getSender());
            if (!user.getPw().equals(ClientConnect.data.get(id).getPw())) {
                toSend.setMessageType(MessageType.REQUEST_REJECTED);
            } else if (inp.getReceiver().equals(id) || ClientConnect.data.get(inp.getReceiver()) == null) {
                toSend.setMessageType(MessageType.REQUEST_REJECTED);
            } else {
                toSend.setMessageType(MessageType.FILE);
                toSend.setMessage(inp.getMessage());
                toSend.setSender(id);
                toSend.setReceiver(inp.getReceiver());
                toSend.setObject(inp.getObject());
                try {
                    ServeCollection.get(inp.getReceiver()).oos.writeObject(toSend);
                    toSend.setMessageType(MessageType.REQUEST_ALLOWED);
                } catch (IOException e) {
                    toSend.setMessageType(MessageType.REQUEST_REJECTED);
                }
                toSend.setObject(null);
            }
            oos.writeObject(toSend);
        }
    
    
        private void logout(Message inp) throws IOException {
            UserData temp = (UserData) inp.getObject();
            if (!temp.getId().equals(id) || !temp.equals(ClientConnect.data.get(id))) {
                return;
            } else {
                ClientConnect.data.get(id).setOnline(false);
                ois.close();
                oos.close();
                clientSocket.close();
                connecting = false;
                ServeCollection.remove(id);
                System.out.println(Message.getDateTime() + " " + id + " 用户登出 " + clientSocket.getInetAddress().getHostName());
            }
        }
    
        public void forceLogout() throws IOException {
            ClientConnect.data.get(id).setOnline(false);
            ois.close();
            oos.close();
            clientSocket.close();
            connecting = false;
            ServeCollection.remove(id);
        }
    
        public void sendRepeatLoginException() throws IOException {
            oos.writeObject(new Message(null, null, null, MessageType.REPEAT_LOGIN));
        }
    }
  • ServeCollection.java

    package com.melody.transmission.common;
    
    import com.melody.transmission.connected.Serve;
    
    import java.net.Socket;
    import java.util.Collection;
    import java.util.HashMap;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class ServeCollection {
        public static final HashMap<String, Serve> serves = new HashMap<>();
    
        public static void add(String id, Serve serve){
            serves.put(id, serve);
        }
    
        public static Serve get(String id) {
            return serves.get(id);
        }
    
        public static Collection<Serve> toValue(){
            return serves.values();
        }
    
        public static void remove(String id){
            serves.remove(id);
        }
    }
  • UserDataEnum.java

    package com.melody.transmission.common;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public enum UserDataEnum {
        USER01("申鹤", "123456", "0001"),
        USER02("胡桃", "123456", "0002"),
        USER03("甘雨", "123456", "0003"),
        USER04("刻晴", "123456", "0004"),
        USER05("香菱", "123456", "0005"),
        USER06("凝光", "123456", "0006"),
        USER07("云堇", "123456", "0007"),
        USER08("留云借风真君", "123456", "0008"),
        USER09("降魔大圣", "123456", "0009"),
        USER10("歌尘浪市真君", "123456", "0010"),
        USER11("理水叠山真君", "123456", "0011"),
        USER12("摩拉克斯", "123456", "0012"),
        USER13("救苦渡厄真君", "123456", "0013");
        public final UserData user;
    
        UserDataEnum(String name, String pw, String ID) {
            user = new UserData(name, pw, ID);
        }
    }

客户端

Test1.java:程序入口

ClientInterface.java:程序的主干

ClientThread.java:由这个线程收集服务端发来的数据,并记录

ClientThreadCollection.java:思路混乱的产物。现在我也不知道这是干嘛的(好在没几行代码)

Utility.java:工具类

  • Test1.java(入口)

    package com.melody.transmission;
    
    import com.melody.transmission.common.ClientInterface;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class Test1 {
        public static void main(String[] args) {
            new ClientInterface().menu_0();
        }
    }
  • ClientInterface.java(主干)

    package com.melody.transmission.common;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.time.LocalDateTime;
    import java.util.Date;
    import java.util.Scanner;
    
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class ClientInterface {
        private Scanner scanner = new Scanner(System.in);
        private String thisIP = "192.168.3.16";
        private static String serverIP = "192.168.3.16";
        private UserData loggedUser = null;
        private User user = null;
        private ClientThread ct;
        private Socket socket;
        private Message message;
        ObjectOutputStream oos;
        ObjectInputStream ois;
        public boolean running = true;
        public boolean cancelMenu = false;
        public File filePath = new File("d:\\");
    
    
        //一级菜单、登录
        public void menu_0() {
            boolean running0 = true;
            while (running0) {
                System.out.println("===========欢迎使用通讯系统(试做版)===========");
                System.out.println("\t\t\t1. 用户登录");
                System.out.println("\t\t\t9. 退出系统");
                System.out.print("请输入:");
                String inpString = Utility.readKeyBoard(1, false);
                System.out.println("--------------------------------------------");
                try {
                    if (inpString.equals("1")) {
                        menuLogin_0_1();
                    } else if (inpString.equals("9")) {
                        running0 = false;
                    } else {
                        throw new RuntimeException();
                    }
                } catch (RuntimeException | ClassNotFoundException e) {
                    System.out.println("错误");
                } catch (IOException d) {
                    System.out.println("链接失败!");
                } finally {
                    System.out.println("--------------------------------------------");
                }
            }
            System.out.println("再见~");
        }
    
    
        //一级菜单、登录
        private void menuLogin_0_1() throws IOException, ClassNotFoundException {
            System.out.println("-----------------用户登录-------------------");
            System.out.print("请输入用户ID(4位):");
            String id = Utility.readKeyBoard(4, false);
            System.out.print("请输入密码(6位):");
            String pw = Utility.readKeyBoard(6, false);
            System.out.println();
            System.out.println("--------------------------------------------");
            user = new User(id, pw);
            loggedUser = tryLogin_0_1_1(user);
            if (loggedUser == null) {
                System.out.println("登录失败");
                oos.close();
                ois.close();
                socket.close();
            } else {
                System.out.println("欢迎回来," + loggedUser.getName());
                isLoggedIn_1();
            }
        }
    
    
        private UserData tryLogin_0_1_1(User user) throws IOException, ClassNotFoundException {
            socket = new Socket(InetAddress.getByName(serverIP), 9000);
            oos = new ObjectOutputStream(socket.getOutputStream());
            ois = new ObjectInputStream(socket.getInputStream());
            oos.writeObject(user);
            Message received = (Message) ois.readObject();
            String reply = received.getMessageType();
            if (reply.equals(MessageType.LOGIN_WRONG_PW)) {
                System.out.println("密码错误");
            } else if (reply.equals(MessageType.LOGIN_USER_NOT_EXIST)) {
                System.out.println("用户名不存在");
            } else if (reply.equals(MessageType.LOGIN_SUCCESS)) {
                return (UserData) received.getObject();
            } else if (reply.equals(MessageType.LOGIN_FAILED)) {
                System.out.println("错误");
            }
            return null;
        }
    
    
        //二级菜单
        private void isLoggedIn_1() {
            ct = new ClientThread(socket, oos, ois, this);
            new Thread(ct).start();
            running = true;
            showBasicMenu_1_();
            System.out.println(loggedUser.leftMessage);
            cancelMenu = true;
            if (loggedUser.leftMessage.length() != 0) {
                System.out.println("----------------以上是留言----------------");
            }
            while (running) {
                showBasicMenu_1_();
                System.out.print("请选择:");
                char inp = Utility.readChar();
                System.out.println("--------------------------------------------");
                switch (inp) {
                    case '1':
                        loggedGetList_1_1();
                        break;
                    case '2':
                        loggedChat_1_2();
                        break;
                    case '3':
                        loggedGroupChat_1_3();
                        break;
                    case '4':
                        loggedSendFile_1_4();
                        break;
                    case '5':
                        loggedChangeName_1_5();
                        break;
                    case '6':
                        loggedChangePw_1_6();
                        break;
                    case '7':
                        loggedChangeHide_1_7();
                        break;
                    case '8':
                        showOthersMenu_1_();
                        break;
                    case '9':
                        try {
                            loggedLogout_1_9();
                        } catch (IOException e) {
                            System.out.println("复位");
                        }
                        break;
                    case 'M':
                    case 'm':
                        break;
                    case 'L':
                    case 'l':
                        loggedShowLeftMessage_1_L();
                        break;
                    case 'H':
                    case 'h':
                        loggedShowChatMessage_1_H();
                        break;
                    case 'C':
                    case 'c':
                        loggedClearMessage_1_C();
                        break;
                    case 'D':
                    case 'd':
                        loggedFileDeal_1_D();
                        break;
                    case 'F':
                    case 'f':
                        loggedShowFilePath_1_F();
                        break;
                    case 'N':
                    case 'n':
                        loggedChangeFilePath_1_N();
                        break;
                    default:
                        System.out.println("错误:请检查输入内容");
                        break;
                }
            }
        }
    
    
        public void showBasicMenu_1_() {
            if (cancelMenu) {
                cancelMenu = false;
                return;
            }
            System.out.println("================" + loggedUser.getName() + "(" + loggedUser.getID() + ")================");
            System.out.println("\t\t\t1. 获取用户列表");
            System.out.println("\t\t\t2. 聊天");
            System.out.println("\t\t\t3. 群聊");
            System.out.println("\t\t\t4. 发送文件");
            System.out.println("\t\t\t5. 修改昵称");
            System.out.println("\t\t\t6. 修改密码");
            System.out.println("\t\t\t7. 切换隐身状态(目前:" + (loggedUser.isOnline() ? "非隐身)" : "隐身★~)"));
            System.out.println("\t\t\t8. 其他");
            System.out.println("\t\t\t9. 退出");
            System.out.println("--------------------------------------------");
        }
    
        private void showOthersMenu_1_() {
            System.out.println("================" + loggedUser.getName() + "(" + loggedUser.getID() + ")================");
            System.out.println("\t\t\tC. 清空在线消息");
            System.out.println("\t\t\tD. 查看文件");
            System.out.println("\t\t\tH. 在线消息记录");
            System.out.println("\t\t\tL. 查看离线留言");
            System.out.println("\t\t\tF. 查看文件存放目录");
            System.out.println("\t\t\tN. 更改文件存放目录");
            System.out.println("\t\t\tM. 返回(显示一级菜单)");
            cancelMenu = true;
        }
    
    
        private void loggedGetList_1_1() {
            message = new Message(null, loggedUser.getID(), serverIP, MessageType.LOGGED_SHOW_LIST);
            sendAndReceive();
            if (message == null) {
                System.out.println("获取列表失败");
            } else if (message.getMessageType().equals(MessageType.REQUEST_ALLOWED)) {
                ct.messageReceived = false;
                System.out.println("----------------成员列表如下----------------");
                System.out.println(message.getMessage());
            } else {
                System.out.println("获取列表失败");
            }
        }
    
        private void loggedGetActiveList_1_1A() {
            message = new Message(null, loggedUser.getID(), serverIP, MessageType.LOGGED_SHOW_ONLINE_LIST);
            sendAndReceive();
            if (message == null) {
                System.out.println("获取在线成员列表失败");
            } else if (message.getMessageType().equals(MessageType.REQUEST_ALLOWED)) {
                ct.messageReceived = false;
                System.out.println("--------------在线成员列表如下--------------");
                System.out.println(message.getMessage());
            } else {
                System.out.println("获取在线成员列表失败");
            }
        }
    
        private void loggedChat_1_2() {
            loggedGetActiveList_1_1A();
            message = new Message(null, loggedUser.getID(), serverIP, MessageType.CHAT);
            System.out.print("请输入私聊对象:");
            String tarId = Utility.readKeyBoard(10, true);
            if (tarId == null || tarId.equals("")) {
                System.out.println("取消");
                return;
            } else if (tarId.equals(loggedUser.getID())) {
                System.out.println("不能私聊自己");
                return;
            }
            System.out.print("发送内容:");
            String word = Utility.readKeyBoard(100, true);
            if (word == null || word.equals("")) {
                System.out.println("取消");
                return;
            }
            User[] temp = new User[2];
            temp[0] = user;
            temp[1] = new User(tarId, null);
            message.setObject(temp);
            message.setMessage(word);
            showBasicMenu_1_();
            sendAndReceive();
            if (message == null) {
                System.out.println("\r访问失败");
            } else if (message.getMessageType().equals(MessageType.REQUEST_ALLOWED)) {
                ct.sb.append("\n").append(message.getTime()).append(" 你对 ").append(((User) message.getObject()).getId()).append(" 说:").append(word);
                System.out.println(ct.sb);
                System.out.println("\r发送成功");
                cancelMenu = true;
            } else if (message.getMessageType().equals(MessageType.REQUEST_REJECTED)) {
                System.out.println("\r请求被拒绝");
            } else {
                System.out.println("\r发送失败");
            }
        }
    
    
        private void loggedGroupChat_1_3() {
            message = new Message(null, loggedUser.getID(), serverIP, MessageType.GROUP_CHAT);
            System.out.print("发送内容:");
            String word = Utility.readKeyBoard(100, true);
            if (word == null || word.equals("")) {
                System.out.println("取消");
                return;
            }
            message.setObject(user);
            message.setMessage(word);
            showBasicMenu_1_();
            sendAndReceive();
            if (message == null) {
                System.out.println("\r访问失败");
            } else if (message.getMessageType().equals(MessageType.REQUEST_ALLOWED)) {
                System.out.println("\r发送成功");
                cancelMenu = true;
            } else if (message.getMessageType().equals(MessageType.REQUEST_REJECTED)) {
                System.out.println("\r请求被拒绝");
            } else {
                System.out.println("\r发送失败");
            }
        }
    
        private void loggedSendFile_1_4() {
            loggedGetActiveList_1_1A();
            message = new Message(null, loggedUser.getID(), serverIP, MessageType.FILE);
            System.out.println("请输入要发送的用户:");
            String tar = Utility.readKeyBoard(4, true);
            message.setReceiver(tar);
            if (tar == null || tar.equals("")) {
                System.out.println("取消");
                return;
            } else if (tar.equals(loggedUser.getID())) {
                System.out.println("错误:不能发给自己");
                return;
            } else if (tar.length() < 4) {
                System.out.println("错误:用户 ID 是 4 位字符");
            }
            System.out.print("请输入文件完整路径:");
            String file_Str = Utility.readKeyBoard(500, true);
            if (file_Str == null || file_Str.equals("")) {
                System.out.println("取消");
                return;
            }
            cancelMenu = true;
            File file = null;
            byte[] data = null;
            try {
                file = new File(file_Str);
                if (!file.isFile()) {
                    throw new RuntimeException();
                }
                data = Utility.loadFile(file);
            } catch (Exception e) {
                showBasicMenu_1_();
                System.out.println("错误:文件路径错误");
                return;
            }
            message.setSender(loggedUser.getPw());
            message.setObject(data);
            message.setMessage(file.getName());
            sendAndReceive();
            if (message == null) {
                System.out.println("发送失败");
            } else if (message.getMessageType().equals(MessageType.REQUEST_ALLOWED)) {
                ct.messageReceived = false;
                System.out.println("文件发送成功");
            } else if (message.getMessageType().equals(MessageType.REQUEST_REJECTED)) {
                System.out.println("请求被拒绝");
            } else {
                System.out.println("请求失败");
            }
            cancelMenu = false;
        }
    
        private void loggedChangeName_1_5() {
            message = new Message(null, loggedUser.getID(), serverIP, MessageType.LOGGED_CHANGE_NAME);
            System.out.print("请输入一个新名字(不超过10位):");
            String newName = Utility.readKeyBoard(10, true);
            if (newName == null || newName.equals("")) {
                System.out.println("取消");
                return;
            }
            message.setMessage(newName);
            message.setObject(loggedUser);
            loggedUser = null;
            sendAndReceive();
            if (message == null) {
                System.out.println("访问失败");
            } else if (message.getMessageType().equals(MessageType.REQUEST_ALLOWED)) {
                ct.messageReceived = false;
                loggedUser = (UserData) message.getObject();
                System.out.println("修改完毕:(" + loggedUser.getID() + ")" + loggedUser.getName());
            } else if (message.getMessageType().equals(MessageType.REQUEST_REJECTED)) {
                System.out.println("请求被拒绝");
            } else {
                System.out.println("请求失败");
            }
        }
    
        private void loggedChangePw_1_6() {
            message = new Message(null, loggedUser.getID(), serverIP, MessageType.LOGGED_CHANGE_PW);
            System.out.print("请输入原密码:");
            String pw = Utility.readKeyBoard(20, true);
            if (pw == null || pw.equals("")) {
                System.out.println("取消");
                return;
            } else if (!pw.equals(loggedUser.getPw())) {
                System.out.println("错误:密码错误");
                return;
            }
            System.out.print("请输入新密码(6位):");
            pw = Utility.readKeyBoard(6, true);
            if (pw == null || pw.equals("")) {
                System.out.println("取消");
                return;
            } else if (pw.length() != 6) {
                System.out.println("错误:密码长度应该是 6 位");
                return;
            }
            message.setMessage(pw);
            message.setObject(loggedUser);
            sendAndReceive();
            if (message == null) {
                System.out.println("访问失败");
            } else if (message.getMessageType().equals(MessageType.REQUEST_ALLOWED)) {
                ct.messageReceived = false;
                System.out.println("密码修改成功");
                loggedUser = (UserData) message.getObject();
            } else if (message.getMessageType().equals(MessageType.REQUEST_REJECTED)) {
                System.out.println("请求被拒绝");
            } else {
                System.out.println("请求失败");
            }
        }
    
        private void loggedChangeHide_1_7() {
            message = new Message(null, loggedUser.getID(), serverIP, MessageType.LOGGED_CHANGE_HIDE);
            message.setObject(loggedUser);
    //        loggedUser = null;
            sendAndReceive();
            if (message == null) {
                System.out.println("访问失败");
            } else if (message.getMessageType().equals(MessageType.REQUEST_ALLOWED)) {
                loggedUser = (UserData) message.getObject();
            } else if (message.getMessageType().equals(MessageType.REQUEST_REJECTED)) {
                System.out.println("请求被拒绝");
            } else {
                System.out.println("请求失败");
            }
        }
    
        private void loggedLogout_1_9() throws IOException {
            System.out.println("确认退出吗?(Y/N)");
            if (Utility.readConfirmSelection() == 'Y') {
                message = new Message(null, loggedUser.getID(), serverIP, MessageType.LOGGED_LOGOUT);
                message.setObject(loggedUser);
                oos.writeObject(message);
                loggedUser = null;
                socket.close();
                ct.running = false;
                running = false;
            }
        }
    
        private void loggedShowChatMessage_1_H() {
            System.out.println(ct.sb);
            cancelMenu = true;
            System.out.println("----------------没有更多了----------------");
        }
    
        private void loggedShowLeftMessage_1_L() {
            System.out.println(loggedUser.leftMessage);
            cancelMenu = true;
            System.out.println("----------------没有更多了----------------");
        }
    
        private void loggedClearMessage_1_C() {
            ct.sb.delete(0, ct.sb.length());
            System.out.println("完成");
        }
    
        private void loggedFileDeal_1_D() {
            boolean fileMenuRunning = true;
            while (fileMenuRunning) {
                showFileDealMenu_1_D_();
                System.out.print("请选择:");
                char inp = Utility.readChar();
                System.out.println("--------------------------------------------");
                switch (inp) {
                    case '1':
                        fileShowAllName_1_D_1();
                        break;
                    case '2':
                        fileShowNewestName_1_D_2();
                        break;
                    case '3':
                        fileDeleteNewestOne_1_D_3();
                        break;
                    case '4':
                        fileDownloadNewestOne_1_D_4();
                        break;
                    case '5':
                        fileDownloadAll_1_D_5();
                        break;
                    case '6':
                        loggedChangeFilePath_1_N();
                        break;
                    case '9':
                        fileMenuRunning = false;
                        break;
                    default:
                        System.out.println("错误:请检查输入内容");
                        break;
                }
            }
        }
    
        private void showFileDealMenu_1_D_() {
            if (cancelMenu) {
                cancelMenu = false;
                return;
            }
            System.out.println("---------------文件管理----------------");
            ct.showFilesRemain();
            loggedShowFilePath_1_F();
            System.out.println("-------------------------------------");
            System.out.println("\t\t\t1. 查看所有文件");
            System.out.println("\t\t\t2. 查看最新文件");
            System.out.println("\t\t\t3. 删除最新的文件");
            System.out.println("\t\t\t4. 下载最新的文件");
            System.out.println("\t\t\t5. 全部下载");
            System.out.println("\t\t\t6. 修改存放路径");
            System.out.println("\t\t\t9. 返回上级目录");
        }
    
        private void fileShowAllName_1_D_1() {
            showFileDealMenu_1_D_();
            cancelMenu = true;
            if (ct.filesToDeal.length == 0) {
                System.out.println("没有未处理的文件了★~~");
                return;
            }
            int n = 0;
            do {
                System.out.println((n + 1) + ". " + ct.fileName[n]);
            } while (++n < ct.fileName.length);
        }
    
        private void fileShowNewestName_1_D_2() {
            showFileDealMenu_1_D_();
            cancelMenu = true;
            if (ct.filesToDeal.length == 0) {
                System.out.println("没有未处理的文件了★~~");
            } else {
                System.out.println(ct.fileName.length + ". " + ct.fileName[ct.fileName.length - 1]);
            }
        }
    
        private void fileDeleteNewestOne_1_D_3() {
            showFileDealMenu_1_D_();
            cancelMenu = true;
            if (ct.filesToDeal.length == 0) {
                System.out.println("没有未处理的文件了★~~");
                return;
            }
            System.out.println(ct.fileName.length + ". " + ct.fileName[ct.fileName.length - 1]);
            System.out.println("确定删除吗?");
            System.out.println("确认退出吗?(Y/N)");
            if (Utility.readConfirmSelection() == 'N') {
                System.out.println("取消");
                return;
            }
            if (ct.deleteNewestFile()) {
                System.out.println("删除成功");
            }
        }
    
        private void fileDownloadNewestOne_1_D_4() {
            showFileDealMenu_1_D_();
            cancelMenu = true;
            if (ct.filesToDeal.length == 0) {
                System.out.println("没有未处理的文件了★~~");
                return;
            }
            String str = ct.fileName[ct.fileName.length - 1];
            if (ct.downloadNewestFile()) {
                System.out.println(str + " 下载成功");
            }
        }
    
        private void fileDownloadAll_1_D_5() {
            showFileDealMenu_1_D_();
            cancelMenu = true;
            if (ct.filesToDeal.length == 0) {
                System.out.println("没有未处理的文件了★~~");
                return;
            }
            do {
                fileDownloadNewestOne_1_D_4();
            } while (ct.filesToDeal.length > 0);
            cancelMenu = false;
        }
    
        private void loggedShowFilePath_1_F() {
            System.out.println("文件保存目录如下:" + filePath);
            cancelMenu = true;
        }
    
        private void loggedChangeFilePath_1_N() {
            loggedShowFilePath_1_F();
            System.out.print("请输入一个新的路径");
            String newPath = Utility.readKeyBoard(500, true);
            if (newPath == null || newPath.equals("")) {
                System.out.println("取消");
                cancelMenu = false;
                return;
            }
            File path;
            try {
                path = new File(newPath);
                path.mkdir();
            } catch (Exception e) {
                System.out.println("错误:路径输入错误");
                return;
            }
            filePath = path;
            cancelMenu = false;
            showBasicMenu_1_();
            System.out.println("成功");
            loggedShowFilePath_1_F();
        }
    
        private void sendAndReceive() {
            long now = (new Date()).getTime();
            ct.messageReceived = false;
            try {
                oos.writeObject(message);
            } catch (IOException e) {
                System.out.println("异常");
                return;
            }
            do {
                if (new Date().getTime() - now >= 5000) {
                    System.out.println("超时");
                    message = null;
                    break;
                } else if (ct.messageReceived) {
                    message = ct.message;
                    break;
                }
            } while (true);
            ct.messageReceived = false;
        }
    
    
        private static String getDate() {
            return getDate(LocalDateTime.now());
        }
    
        private static String getDate(LocalDateTime ldt) {
            return ldt.getYear() + "." + ldt.getMonthValue() + "." + ldt.getDayOfMonth();
        }
    
        private static String getTime() {
            return getTime(LocalDateTime.now());
        }
    
        private static String getTime(LocalDateTime ldt) {
            return ldt.getHour() + ":" + ldt.getMinute() + ":" + ldt.getSecond();
        }
    
        private static String getDateTime() {
            LocalDateTime ldt = LocalDateTime.now();
            return getDate(ldt) + "  " + getTime();
        }
    
    //    private Message packageMessage(String str) {
    //        return new Message(str, thisIP, serverIP, "0");
    //    }
    }
  • ClientThread.java

    package com.melody.transmission.common;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.Socket;
    import java.util.Arrays;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class ClientThread implements Runnable {
        private Socket socket;
        private ObjectOutputStream oos;
        private ObjectInputStream ois;
        public Message message = null;
        public boolean messageReceived = false;
        public boolean running = true;
        public final StringBuilder sb = new StringBuilder();
        private ClientInterface ci;
        //    public byte[] fileToDeal;
        public boolean receivedFileDealt = true;
        public byte[][] filesToDeal = new byte[0][];			//这里改为创建一个本地缓存,在内存里存放路径更好
        														//但我懒得改了
        public String[] fileName = new String[0];
    
    
        @Override
        public void run() {
            try {
                while (running) {
                    message = (Message) ois.readObject();
                    if (message.getMessageType().equals(MessageType.CHAT) || message.getMessageType().equals(MessageType.GROUP_CHAT)) {
                        chatReceived();
                    } else if (message.getMessageType().equals(MessageType.FILE)) {
                        filesReceived();
                    }
                    messageReceived = true;
                }
            } catch (IOException | ClassNotFoundException e) {
                ci.running = false;
                System.out.print("\r已离线:");
            }
        }
    
        public ClientThread(Socket socket, ObjectOutputStream oos, ObjectInputStream ois, ClientInterface ci) {
            this.socket = socket;
            this.oos = oos;
            this.ois = ois;
            this.ci = ci;
        }
    
        public Socket getSocket() {
            return socket;
        }
    
        private void chatReceived() {
            sb.append("\n");
            sb.append(message.getMessage());
            System.out.println("\r");
            ci.showBasicMenu_1_();
            System.out.print("\r          ");
            System.out.print("\r" + sb);
            System.out.print("\n请选择:");
            message.setMessageType(MessageType.REQUEST_ALLOWED);
        }
    
        private void filesReceived() {
            filesToDeal = Arrays.copyOf(filesToDeal, filesToDeal.length + 1);
            filesToDeal[filesToDeal.length - 1] = (byte[]) message.getObject();
            fileName = Arrays.copyOf(fileName, fileName.length + 1);
            fileName[fileName.length - 1] = message.getMessage();
            receivedFileDealt = false;
            showFilesRemain();
        }
    
        public void showFilesRemain() {
            System.out.println("\r★您有 " + filesToDeal.length + " 个文件等待处理★");
    //        System.out.println("\r★按 D 键处理★");
            if (filesToDeal.length == 0){
                receivedFileDealt = true;
            }
        }
    
    
        public boolean deleteNewestFile() {
            try {
                filesToDeal = Arrays.copyOf(filesToDeal, filesToDeal.length - 1);
                fileName = Arrays.copyOf(fileName, fileName.length - 1);
                if (fileName.length != filesToDeal.length){
                    fileName = Arrays.copyOf(fileName, filesToDeal.length - 1);
                    System.out.println("错误:文件或文件名丢失");
                    throw new RuntimeException();
                }
            } catch (Exception e) {
                return false;
            } finally {
                showFilesRemain();
            }
            return true;
        }
    
        public boolean downloadNewestFile() {
            File savePath = new File(ci.filePath, fileName[fileName.length - 1]);
            if (Utility.saveFile(filesToDeal[filesToDeal.length -1], savePath)){
                return deleteNewestFile();
            } else {
                System.out.println("错误:文件存储失败");
                return false;
            }
        }
    }
  • ClientThreadCollection.java

    package com.melody.transmission.common;
    
    import java.util.HashMap;
    
    /**
     * @author Melody
     * @version 1.0
     */
    public class ClientThreadCollection {
        public static final HashMap<String, ClientThread> threads = new HashMap<>();
    
        public static void addSocket(String ip, ClientThread ct) {
            threads.put(ip, ct);
        }
    
        public static ClientThread get(String ip) {
            return threads.get(ip);
        }
    
    }
  • Utility.java(工具类,不是我写的)

    package com.melody.transmission.common;
    
    
    /**
     * @author 韩顺平
     * 工具类的作用:
     * 处理各种情况的用户输入,并且能够按照程序员的需求,得到用户的控制台输入。
     */
    
    
    import javax.imageio.IIOException;
    import java.io.*;
    import java.util.Scanner;
    
    /**
     *
     */
    public class Utility {
        //静态属性。。。
        private static Scanner scanner = new Scanner(System.in);
    
        /**
         * 功能:读取键盘输入的一个菜单选项,值:1——5的范围
         *
         * @return 1——5
         */
        public static char readMenuSelection() {
            char c;
            for (; ; ) {
                String str = readKeyBoard(1, false);//包含一个字符的字符串
                c = str.charAt(0);//将字符串转换成字符char类型
                if (c != '1' && c != '2' &&
                        c != '3' && c != '4' && c != '5') {
                    System.out.print("选择错误,请重新输入:");
                } else break;
            }
            return c;
        }
    
        /**
         * 功能:读取键盘输入的一个字符
         *
         * @return 一个字符
         */
        public static char readChar() {
            String str = readKeyBoard(1, false);//就是一个字符
            return str.charAt(0);
        }
    
        /**
         * 功能:读取键盘输入的一个字符,如果直接按回车,则返回指定的默认值;否则返回输入的那个字符
         *
         * @param defaultValue 指定的默认值
         * @return 默认值或输入的字符
         */
    
        public static char readChar(char defaultValue) {
            String str = readKeyBoard(1, true);//要么是空字符串,要么是一个字符
            return (str.length() == 0) ? defaultValue : str.charAt(0);
        }
    
        /**
         * 功能:读取键盘输入的整型,长度小于2位
         *
         * @return 整数
         */
        public static int readInt() {
            int n;
            for (; ; ) {
                String str = readKeyBoard(10, false);//一个整数,长度<=10位
                try {
                    n = Integer.parseInt(str);//将字符串转换成整数
                    break;
                } catch (NumberFormatException e) {
                    System.out.print("数字输入错误,请重新输入:");
                }
            }
            return n;
        }
    
        /**
         * 功能:读取键盘输入的 整数或默认值,如果直接回车,则返回默认值,否则返回输入的整数
         *
         * @param defaultValue 指定的默认值
         * @return 整数或默认值
         */
        public static int readInt(int defaultValue) {
            int n;
            for (; ; ) {
                String str = readKeyBoard(10, true);
                if (str.equals("")) {
                    return defaultValue;
                }
                //异常处理...
                try {
                    n = Integer.parseInt(str);
                    break;
                } catch (NumberFormatException e) {
                    System.out.print("数字输入错误,请重新输入:");
                }
            }
            return n;
        }
    
        /**
         * 功能:读取键盘输入的指定长度的字符串
         *
         * @param limit 限制的长度
         * @return 指定长度的字符串
         */
        public static String readString(int limit) {
            return readKeyBoard(limit, false);
        }
    
        /**
         * 功能:读取键盘输入的指定长度的字符串或默认值,如果直接回车,返回默认值,否则返回字符串
         *
         * @param limit        限制的长度
         * @param defaultValue 指定的默认值
         * @return 指定长度的字符串
         */
        public static String readString(int limit, String defaultValue) {
            String str = readKeyBoard(limit, true);
            return str.equals("") ? defaultValue : str;
        }
    
        /**
         * 功能:读取键盘输入的确认选项,Y或N
         * 将小的功能,封装到一个方法中.
         *
         * @return Y或N
         */
        public static char readConfirmSelection() {
    //        System.out.println("请输入你的选择(Y/N): 请小心选择");
            char c;
            for (; ; ) {//无限循环
                //在这里,将接受到字符,转成了大写字母
                //y => Y n=>N
                String str = readKeyBoard(1, false).toUpperCase();
                c = str.charAt(0);
                if (c == 'Y' || c == 'N') {
                    break;
                } else {
                    System.out.print("请重新输入(输入 Y/N):");
                }
            }
            return c;
        }
    
        /**
         * 功能: 读取一个字符串
         *
         * @param limit       读取的长度
         * @param blankReturn 如果为true ,表示 可以读空字符串。
         *                    如果为false表示 不能读空字符串。
         *                    <p>
         *                    如果输入为空,或者输入大于limit的长度,就会提示重新输入。
         * @return
         */
        public static String readKeyBoard(int limit, boolean blankReturn) {
    
            //定义了字符串
            String line = "";
            //scanner.hasNextLine() 判断有没有下一行
            while (scanner.hasNextLine()) {
                line = scanner.nextLine();//读取这一行
    
                //如果line.length=0, 即用户没有输入任何内容,直接回车
                if (line.length() == 0) {
                    if (blankReturn) return line;//如果blankReturn=true,可以返回空串
                    else continue; //如果blankReturn=false,不接受空串,必须输入内容
                }
                //如果用户输入的内容大于了 limit,就提示重写输入
                //0 < 如果用户如的内容  <= limit ,我就接受
                if (line.length() < 1 || line.length() > limit) {
                    System.out.print("输入长度(不能大于" + limit + ")错误,请重新输入:");
                    continue;
                }
                break;
            }
            return line;
        }
    
        public static byte[] receiveFile(InputStream is) throws IOException {
            ByteArrayOutputStream bis = new ByteArrayOutputStream();
            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = is.read(bytes, 0, bytes.length)) != -1) {
                bis.write(bytes, 0, len);
            }
            return bis.toByteArray();
        }
    
        public static byte[] loadFile(File path) throws IOException {
            ByteArrayOutputStream bis = new ByteArrayOutputStream();
            FileInputStream is = new FileInputStream(path);
            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = is.read(bytes, 0, bytes.length)) != -1) {
                bis.write(bytes, 0, len);
            }
            bytes = bis.toByteArray();
            bis.close();
            return bytes;
        }
    
        public static boolean saveFile(byte[] data, File path) {
            int n = 1;
            File temp = path;
            while (temp.isFile()) {
                temp = new File(path.getParent(), "(拷贝" + n++ + ")" + path.getName());
            }
            try {
                FileOutputStream is = new FileOutputStream(temp);
                is.write(data);
                is.close();
            } catch (IOException e) {
                return false;
            }
            return true;
        }
    }

<Java>20 项目(多用户通讯系统)
https://i-melody.github.io/2022/01/16/Java/入门阶段/20 项目:多用户通讯系统/
作者
Melody
发布于
2022年1月16日
许可协议