Java高级Day39-QQ项目用户登录及基本框架

114.多用户通信系统(QQ)项目

QQ用户登录

QQServer包

===============//ManageClientThread//===============
public class ManageClientThread {
    private static HashMap<String,ServerConnectClientThread> hm = new HashMap<>();
    //添加线程对象到 hm 集合
    public static void addClientThread(String userId, ServerConnectClientThread serverConnectClientThread) {
        hm.put(userId, serverConnectClientThread);
    }
    //根据userId 返回ServerConnectClientThread线程
    public static ServerConnectClientThread getServerConnectClientThread(String userId){
        return hm.get(userId);
    }
}
​
​
===============//Message//===============
public class Message implements Serializable {
    private static final long serialVersionUID = 1L;
    private String sender;//发送方
    private String getter;//接收方
    private String content;//消息内容
    private String sendTime;//发送时间
    private String mesType;//消息类型[可以在接口中定义消息类型]
​
    public String getMesType() {
        return mesType;
    }
​
    public void setMesType(String mesType) {
        this.mesType = mesType;
    }
​
    public String getSender() {
        return sender;
    }
​
    public void setSender(String sender) {
        this.sender = sender;
    }
​
    public String getGetter() {
        return getter;
    }
​
    public void setGetter(String getter) {
        this.getter = getter;
    }
​
    public String getContent() {
        return content;
    }
​
    public void setContent(String content) {
        this.content = content;
    }
​
    public String getSendTime() {
        return sendTime;
    }
​
    public void setSendTime(String sendTime) {
        this.sendTime = sendTime;
    }
}
​
​
===============//MessageType//===============
public interface MessageType {
    //1.在接口中定义了一些常量
    //2.不同的常量表示不同的消息类型
    String MESSAGE_LOGIN_SUCCEED = "1";//表示登录成功
    String MESSAGE_LOGIN_FAIL = "2";//表示登录失败
}
​
​
===============//QQServer//===============
public class QQServer {
    private ServerSocket ss = null;
    //创建一个集合,存放多个用户,如果是这些用户登录,就认为是合法的
    private static HashMap<String, User> validUsers = new HashMap<>();
​
    static {//在静态代码块初始化validUsers
​
        validUsers.put("100", new User("100", "123456"));
        validUsers.put("200", new User("200", "123456"));
        validUsers.put("300", new User("300", "123456"));
        validUsers.put("至尊宝", new User("至尊宝", "123456"));
        validUsers.put("ZhangKewei", new User("ZhangKewei", "20040426"));
​
    }
    //验证用户是否有效的方法
    private boolean checkUser(String userId, String passwd) {
        User user = validUsers.get(userId);
        if (user ==  null) {//说明userId没有存在validUsers 的 key 中
            return false;
        }
        if (!(user.getPasswd().equals(passwd))) {//userId正确,密码错误
            return false;
        }
        return true;
    }
​
    public static void main(String[] args) {
        new QQServer();
    }
    public QQServer() {
        //注意:端口可以写在配置文件
        try {
            System.out.println("服务端在9999端口监听...");
            ss = new ServerSocket(9999);
​
            while (true) {//当和某个客户端连接后,会继续监听,因为while循环
                Socket socket = ss.accept();
                //得到Socket关联的对象输入流
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                //得到socket关联的对象输出流
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                User u = (User) ois.readObject();//读取客户端发送的User对象
                //创建一个Message对象,准备回复客户端
                Message message = new Message();
                //验证
                if (checkUser(u.getUserID(), u.getPasswd())){//合法用户
                    message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED);
                    //将message对象回复
                    oos.writeObject(message);
                    //创建一个线程,和客户端保持通信,该线程需要持有socket对象
                    ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, u.getUserID());
                    //启动该线程
                    serverConnectClientThread.start();
                    //把该线程对象,放入到一个集合中,进行管理
                    ManageClientThread.addClientThread(u.getUserID(), serverConnectClientThread);
                } else {//登陆失败
                    System.out.println("用户 id=" + u.getUserID() + " pwd=" + u.getPasswd() + "验证失败");
                    message.setMesType(MessageType.MESSAGE_LOGIN_FAIL);
                    oos.writeObject(message);
                    //关闭socket
                    socket.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //如果服务器退出了while,说明服务器端不在监听,因此需要关闭ServerSocket
            try{
                ss.close();
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}
​
​
===============//ServerConnectClientThread//===============
public class ServerConnectClientThread extends Thread {
    private Socket socket;
    private String userId;//连接到服务端端的用户id
​
    public ServerConnectClientThread(Socket socket, String userId) {
        this.socket = socket;
        this.userId = userId;
    }
    @Override
    public void run() {//这里的线程处于run状态,可以发送接收信息
        while (true) {
            try {
                System.out.println("服务器端和客户端" + userId + "保持通讯,读取数据...");
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message message = (Message) ois.readObject();
                //后面会使用message
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
​
​
===============//User//===============
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private String userID;//用户ID
    private String passwd;//用户密码
​
    public User(){}
    public User (String userID, String passwd) {
        this.userID = userID;
        this.passwd = passwd;
    }
​
    public String getUserID() {
        return userID;
    }
​
    public void setUserID(String userID) {
        this.userID = userID;
    }
​
    public String getPasswd() {
        return passwd;
    }
​
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}

QQClientService包

===============//ClientConncetServerThread//===============
public class ClientConncetServerThread extends Thread {
    //该线程需要持有Socket
    private Socket socket;
​
    //构造器可以接收一个Socket对象
    public ClientConncetServerThread(Socket socket){
        this.socket = socket;
    }
​
    @Override
    public void run() {
        //因为Thread需要在后台和服务器通信,所以我们要一个while循环
        while (true) {
            System.out.println("客户端线程,等待读取从服务器端发送的信息");
            try {
                System.out.println("客户端线程,等待读取从服务器端发送的信息");
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                //如果服务器没有发送Message对象,线程会阻塞在这里
                Message message = (Message) ois.readObject();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
​
    //为了更方便得到Socket
    public Socket getSocket() {
        return socket;
    }
}
​
​
===============//ManageClientConnectServerThread//===============
public class ManageClientConnectServerThread {
    //我们把多个线程放入一个HashMap集合,key 就是用户id;value 就是一个线程
    private static HashMap<String, ClientConncetServerThread> hm = new HashMap<>();
​
    //将某个线程加入到集合
    public static void addClientConnectServerThread(String userId, ClientConncetServerThread clientConncetServerThread){
        hm.put(userId, clientConncetServerThread);
    }
​
    //通过userId,可以得到对应的线程
    public static ClientConncetServerThread getClientConncetServerThread(String userId){
        return hm.get(userId);
    }
​
}
​
​
===============//UserClientService//===============
public class UserClientService {
    //因为可能在其他地方要使用User信息,所以做成属性
    private User u = new User();
    //因为Socket在其它地方也有可能使用,因此也做成属性
    private Socket socket;
    //根据userId 和 pwd 到服务器验证用户是否合法
    public boolean checkUser(String userId, String pwd) {
        boolean b = false;
        //创建User对象
        u.setUserID(userId);
        u.setPasswd(pwd);
        //连接到服务端,发送u对象
        try {
            socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
            //得到ObjectOutputStream对象
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(u);//发送User对象
​
            //读取从服务端回复的Message对象
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            Message ms = (Message) ois.readObject();
​
            if (ms.getMesType().equals(MessageType.MESSAGE_LOGIN_SUCCEED)){//登录成功
​
                b = true;
                //创建一个和服务器端保持通信的线程 --> 创建一个类 ClientConnectServerThread
                ClientConncetServerThread clientConncetServerThread = new ClientConncetServerThread(socket);
                //启动客户端的线程
                clientConncetServerThread.start();
                //这里为了后面客户端的扩展,我们将线程放入到集合管理
                ManageClientConnectServerThread.addClientConnectServerThread(userId, clientConncetServerThread);
​
            }else {
                //如果登陆失败,我们就不能启动和服务器通信的线程,关闭Socket
                socket.close();
            }
​
        } catch (Exception e){
            e.printStackTrace();
        }
        return b;
    }
}

QQClient.view包

===============//QQView//===============
public class QQView {
    private boolean loop = true;//控制是否显示菜单
    private String key = "";//接收用户的键盘输入
    private UserClientService userClientService = new UserClientService();//对象是用于登录服务器/注册用户
​
    public static void main(String[] args) {
        new QQView().mainMenu();
        System.out.println("客户端退出系统...");
    }
    //显示主菜单
    private void mainMenu(){
        while (loop){
            System.out.println("===========欢迎登录网络通信系统==========");
            System.out.println("\t\t 1 登陆系统");
            System.out.println("\t\t 9 退出系统");
            System.out.print("请输入你的选择:");
​
            key = utils.readString(1);
​
            //根据用户的输入,来处理不同的逻辑
            switch (key){
                case "1":
                    System.out.print("请输入用户号:");
                    String userID = utils.readString(50);
                    System.out.print("请输入密  码:");
                    String pwd = utils.readString(50);
                    //需要到服务端验证该用户是否合法
                    //这里有很多代码,所以在这里编写一个UserClientService
                    if (userClientService.checkUser(userID, pwd)){
                        System.out.println("===========欢迎(用户"+ userID +"登陆成功)==========");
                        //进入二级菜单
                        while (loop){
                            System.out.println("\n===========网络通信二级菜单(用户"+ userID +")==========");
                            System.out.println("\t\t 1 显示在线用户列表");
                            System.out.println("\t\t 2 群发消息");
                            System.out.println("\t\t 3 私聊消息");
                            System.out.println("\t\t 4 发送文件");
                            System.out.println("\t\t 9 退出系统");
                            System.out.println("请输入你的选择:");
                            key = utils.readString(1);
                            switch (key){
                                case "1":
                                    System.out.println("\t\t 1 显示在线用户列表");
                                    break;
                                case "2":
                                    System.out.println("\t\t 2 群发消息");
                                    break;
                                case "3":
                                    System.out.println("\t\t 3 私聊消息");
                                    break;
                                case "4":
                                    System.out.println("\t\t 4 发送文件");
                                    break;
                                case "9":
                                    loop = false;
                                    break;
                            }
​
                        }
                    }else {//登录服务器失败
                        System.out.println("==========登陆服务器失败==========");
                    }
                    break;
                case "9":
                    loop = false;
                    break;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值