Java GUI编程——在线聊天室

2023-11-18

引言

综合应用Java的GUI编程和网络编程,实现一个能够支持多组用户同时使用的聊天室软件。该聊天室具有比较友好的GUI界面,并使用C/S模式,支持多个用户同时使用,用户可以自己选择加入或者创建房间,和房间内的其他用户互发信息(文字和图片)

主要功能

客户端的功能主要包括如下的功能:
  • 选择连上服务端
  • 显示当前房间列表(包括房间号和房间名称)
  • 选择房间进入
  • 多个用户在线群聊
  • 可以发送表情(用本地的,实际上发送只发送表情的代码)
  • 退出房间
  • 选择创建房间
  • 房间里没人(房主退出),导致房间解散
  • 显示系统提示消息
  • 显示用户消息
  • 构造标准的消息结构发送
  • 维护GUI所需的数据模型
服务端的功能主要包括:
  • 维护用户信息和房间信息
  • 处理用户发送来的消息选择转发或者回复处理结果
  • 构造标准的消息结构发送

架构

整个程序采用C/S设计架构,分为一个服务端和多个客户端。服务端开放一个端口给所有开客户端,客户端连接该端口并收发信息,服务端在内部维护客户端的组,并对每一个客户端都用一个子线程来收发信息

基本类的设计

 User类
package User;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * 
 * @author lannooo
 *
 */
public class User {
   
    private String name;
    private long id;
    private long roomId;
    private Socket socket;
    private BufferedReader br;
    private PrintWriter pw;

    /**
     * 
     * @param name: 设置user的姓名
     * @param id:设置user的id
     * @param socket:保存用户连接的socket
     * @throws IOException
     */
    public User(String name, long id, final Socket socket) throws IOException {
        this.name=name;
        this.id=id;
        this.socket=socket;
        this.br=new BufferedReader(new InputStreamReader(
                socket.getInputStream()));
        this.pw=new PrintWriter(socket.getOutputStream());

    }

    /**
     * 获得该用户的id
     * @return id
     */
    public long getId() {
        return id;
    }

    /**
     * 设置该用户的id
     * @param id 新的id
     */
    public void setId(long id) {
        this.id = id;
    }

    /**
     * 获得用户当前所在的房间号
     * @return roomId
     */
    public long getRoomId() {
        return roomId;
    }

    /**
     * 设置当前用户的所在的房间号
     * @param roomId
     */
    public void setRoomId(long roomId) {
        this.roomId = roomId;
    }

    /**
     * 设置当前用户在聊天室中的昵称
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 返回当前用户在房间中的昵称
     * @return
     */
    public String getName() {
        return name;
    }

    /**
     * 返回当前用户连接的socket实例
     * @return
     */
    public Socket getSocket() {
        return socket;
    }

    /**
     * 设置当前用户连接的socket
     * @param socket
     */
    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    /**
     * 获得该用户的消息读取辅助类BufferedReader实例
     * @return
     */
    public BufferedReader getBr() {
        return br;
    }

    /**
     * 设置 用户的消息读取辅助类
     * @param br
     */
    public void setBr(BufferedReader br) {
        this.br = br;
    }

    /**
     * 获得消息写入类实例
     * @return
     */
    public PrintWriter getPw() {
        return pw;
    }

    /**
     * 设置消息写入类实例
     * @param pw
     */
    public void setPw(PrintWriter pw) {
        this.pw = pw;
    }

    /**
     * 重写了用户类打印的函数
     */
    @Override
    public String toString() {
        return "#User"+id+"#"+name+"[#Room"+roomId+"#]<socket:"+socket+">";
    }
}
Room类
package Room;

import java.util.ArrayList;
import java.util.List;

import User.User;

/**
 * 
 * @author lannooo
 *
 */
public class Room {
   
    private String name;
    private long roomId;
    private ArrayList<User> list;
    private int totalUsers;

    /**
     * 获得房间的名字
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置房间的新名字
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获得房间的id号
     * @return
     */
    public long getRoomId() {
        return roomId;
    }

    /**
     * 设置房间的id
     * @param roomId
     */
    public void setRoomId(long roomId) {
        this.roomId = roomId;
    }

    /**
     * 向房间中加入一个新用户
     * @param user
     */
    public void addUser(User user) {
        if(!list.contains(user)){
            list.add(user);
            totalUsers++;
        }else{
            System.out.println("User is already in Room<"+name+">:"+user);
        }
    }

    /**
     * 从房间中删除一个用户
     * @param user
     * @return 目前该房间中的总用户数目
     */
    public int delUser(User user){
        if(list.contains(user)){
            list.remove(user);
            return --totalUsers;
        }else{
            System.out.println("User is not in Room<"+name+">:"+user);
            return totalUsers;
        }
    }

    /**
     * 获得当前房间的用户列表
     * @return
     */
    public ArrayList<User> getUsers(){
        return list;
    }

    /**
     * 获得当前房间的用户昵称的列表
     * @return
     */
    public String[] getUserNames(){
        String[] userList = new String[list.size()];
        int i=0;
        for(User each: list){
            userList[i++]=each.getName();
        }
        return userList;
    }

    /**
     * 使用房间的名称和id来new一个房间
     * @param name
     * @param roomId
     */
    public Room(String name, long roomId) {
        this.name=name;
        this.roomId=roomId;
        this.totalUsers=0;
        list = new ArrayList<>();
    }
}
RoomList类
package Room;

import java.awt.image.DirectColorModel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import User.User;

/**
 * 
 * @author lannooo
 *
 */
public class RoomList {
   
    private HashMap<Long, Room> map;
    private long unusedRoomId;
    public static long MAX_ROOMS = 9999;
    private int totalRooms;

    /**
     * 未使用的roomid从1算起,起始的房间总数为0
     */
    public RoomList(){
        map = new HashMap<>();
        unusedRoomId = 1;
        totalRooms = 0;
    }

    /**
     * 创建一个新的房间,使用未使用的房间号进行创建,如果没有可以使用的则就创建失败
     * @param name: 房间的名字
     * @return 创建的房间的id
     */
    public long createRoom(String name){
        if(totalRooms<MAX_ROOMS){
            if(name.length()==0){
                name = ""+unusedRoomId;
            }
            Room room = new Room(name, unusedRoomId);
            map.put(unusedRoomId, room);
            totalRooms++;
            return unusedRoomId++;
        }else{
            return -1;
        }
    }
    /**
     * 用户加入一个房间
     * @param user
     * @param roomID
     * @return
     */
    public boolean join(User user, long roomID){
        if(map.containsKey(roomID)){
            map.get(roomID).addUser(user);
            return true;
        }else{
            return false;
        }
    }

    /**
     * 用户退出他的房间
     * @param user
     * @param roomID
     * @return
     */
    public int esc(User user, long roomID){
        if(map.containsKey(roomID)){
            int number = map.get(roomID).delUser(user);
            /*如果这个房间剩下的人数为0,那么删除该房间*/
            if(number==0){
                map.remove(roomID);
                totalRooms--;
                return 0;
            }
            return 1;
        }else{
            return -1;
        }
    }
    /**
     * 列出所有房间的列表,返回一个二维数组,strings[i][0]放房间的id,string[i][1]放房间的name
     * @return
     */
    public String[][] listRooms(){
        String[][] strings = new String[totalRooms][2];
        int i=0;
        /*将map转化为set并使用迭代器来遍历*/
        Set<Entry<Long, Room>> set = map.entrySet();
        Iterator<Entry<Long, Room>> iterator = set.iterator();
        while(iterator.hasNext()){
            Map.Entry<Long, Room> entry = iterator.next();
            long key = entry.getKey();
            Room value = entry.getValue();
            strings[i][0]=""+key;
            strings[i][1]=value.getName();
        }
        return strings;
    }

    /**
     * 通过roomID来获得房间
     * @param roomID
     * @return
     */
    public Room getRoom(long roomID){
        if(map.containsKey(roomID)){
            return map.get(roomID);
        }
        else 
            return null;
    }
}

服务端

Server
package Server;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.json.*;

import Room.Room;
import Room.RoomList;
import User.User;
/**
 * 
 * @author lannooo
 *
 */
public class Server {
   
    private ArrayList<User> allUsers;
    private RoomList rooms;
    private int port;
    private ServerSocket ss;
    private long unusedUserID;
    public final long MAX_USERS = 999999;

    /**
     * 通过port号来构造服务器端对象
     * 维护一个总的用户列表和一个房间列表
     * @param port
     *
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java GUI编程——在线聊天室 的相关文章

随机推荐

  • Day.1 LeetCode刷题练习(最长公共前缀 C/C++两种解法)

    题目 例子 分析题目 主要目的 求出各个字符串的公共前缀 思路 本人解法 用所给实例来看 不难看出我们可以直接以竖着对应来查看是否是公共前缀 这样就有了一定的思路 然后接着想如何让他找到最长的公共前缀后就 停止下来呢 这样就能想到 从最短的
  • Win11共享打印机指定的网络名不可用?

    不知道大家在使用共享打印机的时候是否有遇到错误 共享打印机指定的网络名不可用 的情况 如果有的话 可以试试下面的解决办法 原因很明确 网络名称无法使用 有冲突 删除网络连接 重新建立即可 方法一 1 按键盘上的 Win X 组合键 或右键点
  • 审批流设计

    审批流系统 在日常企业中 经常涉及员工提交申请单 需要上级领导和多个节点审批通过 驳回 已完成申请单 实现目标 工单自定义模版 需支持用户自定义表单 拖拽式动态生成流转表单 打造低代码平台 降低了研发投入成本 提高整体人效 工单流程需支持用
  • element-ui el-upload 上传文件类型限制

    1
  • 双系统之删除Linux

    本文环境 win10 Ubuntu 先删除引导再操作卷 因为之前想学习Linux 所以就在win10上又安装了Ubuntu 现在不想搞了 再加上win10空间不太够用了 就想删除linux系统 话不多说 直接开始 删除Linux主要分为两部
  • 期望, 方差, 协方差,标准差

    期望 方差 协方差 标准差 期望 概率论中描述一个随机事件中的随机变量的平均值的大小可以用数学期望这个概念 数学期望的定义是实验中可能的结果的概率乘以其结果的总和 定义 设P x 是一个离散概率分布 自变量的取值范围为 x 1 x 2 x
  • 互联网+洗鞋店预约小程序新模式;

    互联网 洗鞋店预约小程序 1 线上线下业务的结合 传统的线下业务消费者到店可以向其推介线上的预约到家服务 让线下的消费者成为小程序内的会员 留存客户之后线上可直接触达 减少与消费者的距离 从等待客户到可以主动出击 有什么活动能第一时间推送到
  • WCF 自托管、无配置文件实现jsonp(跨域)的访问

    以下内容基于WCF4 0 本文将对比讨论配置文件方案和无配置文件方案的实现方式 WCF4 0加入了对RESTFU和标准终结点的支持 这为实现跨域提供了简单的方式 一 有配置文件的情况 首先我们先定义一个服务 ServiceContract
  • React styled-components (一) —— 基本使用

    https github com styled components styled components styled components 基本使用 介绍 优点 缺点 安装 引入 使用 基本用法 样式嵌套 介绍 styled compon
  • 三十六.用牛顿迭代法求输入的数的平方根

    欲求a的平方根 首先猜测一个值x1 a 2 也可以是随便其他什么值 作为其平方根 然后根据下面的迭代公式算出x2 再将x2代入公式右边算出x3 直到连续两次算出的xn和xn 1的差的绝对值小于某个值符号网名大全花样符号 即认为找到了足够精确
  • jQuery实现父窗口的问题

    因为先前遇到的问题 所以我考虑采用 IFRAME 来隔离不同的脚本 从而实现我需要的效果 在框架中 我用 JavaScript 获取 JSON 数据 组织成 HTML 代码 最后将其填充至上层文档的一个元素中 按照一般的写法 我们需要用到类
  • 微信接口开发报错invalid credential, access_token is invalid or not latest hint

    微信接口凭证access token一定要全局管理 我们的查酒后台集成了微信公众平台的客服API接口 不用登录微信公众号的后台就可以直接给用户发送消息 最近 运营的同事反馈 通过微信查酒 后台无法直接给用户推送微信消息了 起初 我也没在意
  • 揭秘:WhatsApp的注册策略

    WhatsApp账号的注册方式可以分为两种 实体卡注册和虚拟卡注册 实体卡注册是指使用个人手机卡完成注册 而虚拟卡注册则通过前面提到的对接平台来完成的 账号注册问题一直是导致WhatsApp账号永久封禁的主要原因 由于WhatsApp广泛为
  • HTML5口红西瓜见缝插针小游戏代码

    下载地址 口红西瓜HTML5见缝插针手机游戏代码 口红西瓜见缝插针手机游戏源代码 dd
  • Windows11如何正确修改电脑用户名——解决修改用户名之后无法找到文件路径,路径不存在问题——用Registry Workshop批量操作注册表

    c users 后面是中文会有什么影响 很多人在刚拿到电脑的时候 注册用户名的时候直接填的中文 对一名程序员来说 用户名是中文 有时候在程序运行的过程中会产生非常多的麻烦 解决办法 想要了解第三点的命令的可以看这里http t csdn c
  • RocketMQ-源码解读与调试

    源码环境搭建 源码拉取 RocketMQ的官方Git仓库地址 GitHub apache rocketmq Mirror of Apache RocketMQ 可以用git把项目clone下来或者直接下载代码包 也可以到RocketMQ的官
  • Java设计模式-结构型设计模式-适配器模式

    Java设计模式 结构型设计模式 适配器模式 从这一专栏开始将学习设计模式 上课学习和自己总结归纳的笔记将总结出来供大家参考 参考书籍 设计模式就该这样学 其他文章 Java设计模式 UML类图 Java设计模式 七大架构设计原则 开闭原则
  • 机器学习NLP参考文章

    本站整理了一些NLP的入门资料参考 建议初学者看看 需要复制链接在浏览器里打开 1 通过kaggle比赛学习机器学习文本分类方法https zhuanlan zhihu com p 34899693 utm medium social ut
  • 宋浩高等数学笔记(八)向量代数与空间解析几何

    本章知识点并不难理解 但是公式与名词属于非常多 记忆时需重点对待
  • Java GUI编程——在线聊天室

    引言 综合应用Java的GUI编程和网络编程 实现一个能够支持多组用户同时使用的聊天室软件 该聊天室具有比较友好的GUI界面 并使用C S模式 支持多个用户同时使用 用户可以自己选择加入或者创建房间 和房间内的其他用户互发信息 文字和图片