1、JAVA程序设计多人聊天室 1 设计目标Java 编程语言是个简单、面向对象、分布式、解释性、健壮、安全和系统无关、可移植、高性能、多线程和静态语言。此次课程设计意在应用JAVA编程语言中网络通信,多线程,数据库编程,图形界面编程等技术实现一个基础多人在线网络聊天室。并以此巩固JAVA基础知识,体见面向对象设计方法。2 平台要求2.1 使用:搭载JAVA运行环境平台即可。2.2 开发环境:Windows10 64bit JDK 1.8Eclipse 4.4Window Builder3 需求分析管理员:开启服务器,关闭服务器,强制用户退出,聊天房间增添改查。用户:GUI,注册,登陆,聊天等。用
2、例图:4 概要设计4.1 服务器设计将用户端请求抽象化,每种请求服务器全部会产生一个特定类对象去处理它。服务器负责接收用户端请求,依据请求内容完成指定工作。为提升效率,采取多线程结合线程池设计技术,对于每个请求在线程池内得到一个线程去处理请求。图3-1所表示。4.2 用户端设计5图 41服务器概要图聊天室中一个事物过程基础步骤是:用户产生动作,用户端发送消息,服务器接收并处理,服务器返回处理结果,GUI依据结果进行显示更新。用户端只在GUI中采取多线程设计。而对服务器回应接收全部是单线程因为只有一个服务器为自己服务,且在接收数据过程中连接是不可断开。用户端设计图3-2所表示。一次事物步骤中步骤
3、编号在图中给出。437612图 42用户端概要图5 具体设计5.1 服务器具体设计服务器要完成任务是接收用户请求并在自己维护数据结构上进行对应处理最终将处理结果返回给用户端。具体包含到多线程,数据库,网络通信几项技术,同时为了实时依据请求产生特定类对象使用了反例技术。5.1.1 总体概览服务器端入口类为ServerMain。聊天室服务器端代码可分为以下八个部分。除最终两个部分外其它部分为串行实施。在接听后,创建线程会并发处理用户请求。因为各个处理并发特点,使得服务器响应不会应为某个而用户阻塞,提升了效率。图 51聊天室服务器代码布局服务器将用户操作抽象为不一样工作类,在接收到请求后依据消息协议
4、在目前实现工作类名列表中找到类名(经过下标在CommandList类中List commandsList属性中得到),经过反例技术直接生成类对象。各个类对象负责具体工作,她们全部继承ServerWorkClass。而ServerWorkClass继承自WorlClass因为用户端对服务器回复也应该有特定类去处理它。现在实现类有以下五种。当要添加新功效时只需向commandsList属性静态添加索引。深入,也可在以后加入新机制实现动态添加功效。表 52工作类名及其工作内容类名服务器端动作HouseRelative处理用户进入、离开房间请求Login处理用户上线、下线请求Messages处理用户消
5、息发送请求UserDelAdd处理用户注册请求UserInfo处理用户用户信息查询设置请求服务器中包含到类图以下所表示:5.1.2 协议约定及实现因为要考虑用户端各个请求需要完成不一样操作,需要依据数据来内容来做特定工作,本聊天室将通信协议定义以下:userID:服务器经过此ID确定消息是由哪个用户发出。authorization code:服务器对用户身份进行认证域,每次在接收用户请求后全部会更新一个随机数,而且将内容返回,而用户在请求服务器时必需使用最新验证码不然不会得到服务器响应。这预防了非法用户不正当操作。command:表示用户请求类型其值为具体操作工作类在commandsList中
6、下标,服务器经过此下标找到类名产生类对象。到这里为止工作全部是由一个CommandHandler类对象来完成,它实现了Runnable接口,在Accepter类对象接收到消息后产生一个线程来实施对消息下一步处理,其关键工作就是经过WorkingClassFactory使用反例技术产生具体工作类,以后调用工作类doJob()方法完成任务。command2:一个具体工作类是对一类操作抽象,如和房间相关操作可能包含进房间和出房间,而具体内容就是依据command2来标示。从这里开始工作已经进入到了WorkingClass代码区域。result:是服务器向用户端通知请求是否正常完成字段。以后就是具体消
7、息定义区域。首先一个MessageAmount来表示消息个数,而以后每条消息全部有一个int域来表示其长度。为了支持汉字,采取字符数组而不是字节数组。服务器和用户端全部将协议下具体报文封装在了PacketUnit类中,其关键提供了一个经过输入流来构建本身结构方法和重写了toString方法方便发送时序列化。PacketUnit产生源头是GUI监听处理函数。由特定部位按钮或组件调用PackUnitGenerator类特定静态方法产生特定对象。5.1.3 初始化数据库数据库采取JAVA数据库JDBC技术。通常步骤为加载特定数据库驱动,产生建立连接URL,依据URL连接数据库,在连接上创建state
8、ment类对象进行查询和更新任务发送。和数据库相关全部工作全部由DataBaseServer类来完成。因为考虑到聊天室中大部分操作不需要数据库,而且全程一个连接可能在并发过程中会造成潜在错误,在初始化中只进行了驱动加载。以后需要查询或更新数据库时经过创建DataBaseServer类对象来创建新连接,以对象为单位向数据库发送查询请求。DataBaseServer关键提供以下多个方法:public static void init();完成数据库驱动加载,而且因为静态方法第一次调用,获取服务器连接DataBaseServer静态属性URL也会在此时生成。public DataBaseServer
9、();DataBaseServer结构函数,每次调用全部会创建一条向MYSQL数据库连接。public int updateQuery(String job);向已连接数据库发送一个更新请求,参数为SQL更新语句。public ResultSet getResult(String job);向已连接数据库发送一个查询请求,参数为SQL查询语句。而且返回一个ResultSet结果,是一个包含了查询结果对象。具体代码在DataBaseServer.java文件内。数据库采取MySQL数据库,使用到了两张表,定义以下:userinfo表:表项类型uidintnamevarcharpasswordva
10、rchargendercharteleareachartelephonecharnicknamevarcharbirthyearintbirthmonthintbirthdayinthomelandvarcharinfovarcharhouseinfo表:表项类型hidintshidinthousenamevarcharouidintcreateyearintcreatemonthintcreatedayinthouseinfovarbinary5.1.4 初始化用户信息用户信息不仅是服务器对用户端抽象,也是服务器内部对用户进行管理最基础类。在服务器中以User类来表示用户。其有用户基础个人信
11、息,和用户所在用户端IP和端口(在Login过程后初始化),和用户目前所在房间列表(方便用户名等信息更新时立即通知全部看得到此用户用户)。属性:类型属性:类型homeLand : Stringuid : int info : StringuserName : String authCode : intpassword : String ipAddress : InetAddressgender : char port : inttelearea : StringipAddressEvil : InetAddresstelephone : StringportEvil : intnickname
12、 : String currentHouse : ListbirthYear: int ownHouse : ListbirthMonth : intbirthDay :int总体上,服务器在初始化时从数据库中直接读取全部用户,而且将她们存放于线下用户userAll表中(这里有一个基础约定:服务器开启时是没有用户在线),而在线用户则存放在另一个userCul表中,这两个表在服务器中表示了目前全部用户集合。而这两个表维护归一个叫做UserFactory类来管理,它负责向外界提供User对象采取了工厂设计模式,而且采取了单例模式,因为一个服务器只需一个工厂进行管理。用户初始化步骤以下:UserFa
13、ctory对外提供以下多个方法:public User getByUid(int uid);经过用户编号取得User类对象。public User getByName(String name);经过用户名取得User类对象。public User createUser(String messages);创建一个用户而且将其写入数据库,同时存入userAll。public User updateUser(String messages,User userTmp);更新一个用户信息,将其写入到数据库中。用户名改变造成用户端和服务器不一致由UserInfo类处理,通常情况下此方法也只由UserInf
14、o类对象调用。public void loginAUser(User utm);使一个用户由线下状态转换为线上状态。即从userAll表转移到userCul表。public void logoffAUser(User utm);和loginAUser相反。public boolean isOnline(int uid);检验一个用户是否在线。public boolean isExists(int uid);经过UID检验指定用户是否存在。public boolean isExists(String checkName);经过用户名检验指定用户是否存在。public List getUserCu
15、r();获取全部在线用户。具体代码在UserFactory.java内。5.1.5 初始化房间信息房间是用户间通信场所,通信不可能从一个房间到另一个房间。在服务器中房间用House类表示。为此,房间关键维护一个房间内用户表,方便某个用户发送消息时使服务器知道该把消息发送给谁。房间信息初始化类比用户信息初始化,也使用了工厂模式和单例技术,只是少了在线不在线这个概念。House工厂类为HouseFactory。其向外提供了经过HID或房间名来获取房间对象方法。不再赘述。5.1.6 设置当地发送端Socket为了实现异步通信,在通信过程中用户端和服务器总共需要四个Socket,分别用于服务器接收,服
16、务器发送,用户端接收,用户端发送。必需先设置发送端信息,后设置接收端信息以预防接收到请求处理完而无法发送造成数据不一致问题。服务器在这里设置设置服务器发送端Socket。经过ServerMain类调用Sender.init()来实现。而服务器发送任务完全交给Sender类。它关键提供一个send方法,参数是报文信息和用户,经过将报文信息字节化,获取用户接收Socket得到发送地址和发送内容,从而实施发送过程。5.1.7 监听监听工作由Accepter类完成,它实现Runnable接口,在ServerMain准备好了全部内部数据后会调用ServerMain.startAcceoter方法来设置A
17、ccepter监听当地端口,而且启用一个新线程来监听。Accepterrun方法内创建了一个线程池,以后进入一个无限循环,内部工作为监听端口,获取输入流,产生PacketUnit,产生一个Commandhandler并包装为Thread对象后开启新线程。5.1.8 事物处理事务处理由WorkingClass多个子类具体实施。WorkingClass有一个PacketUnit类属性因为WorkingClass工作是围绕接收到数据展开,全部WorkingClass子类全部应该有此组员,此组员在CommandHandler类内部产生WorkingClass时将其赋值。ServerWorkingCla
18、ss子类全部处于服务器内,关键工作就是依据请求改变服务器数据结构属于整个步骤中第四步(见图xxx)。有一个属性User myUser,用于通知服务器现在服务用户方便对服务器维护数据进行更新。ClientWorkingClass子类全部处于用户端内,工作是依据服务器反馈告诉GUI做合适显示。负责整个步骤中第七步。各子类工作逻辑详见代码。这里简单列出步骤图。Login:协议:步骤:注意:因为第一次登陆是用户端无法知道UID所以myUser属性只能经过消息中用户名取得。返回消息时会设置登陆成功用户UID由用户端维持。HouseRelative:getInHouse:LeaveHouse:Messag
19、es:UserDelAddUserInfo 5.2 用户端具体设计5.2.1 总体概览用户端关键利用到了GUI和网络通信技术。包含到类之间关系以下:用户端实施任务基础步骤以下:5.2.2 登录界面Login按钮监听器会调用PackUnitGenerator来产生一个登录请求数据包,内容见5.1.8登陆部分。以后除了接收线程还在等候服务器回复外不再进行任何动作。接收到回复后会依据消息产生对应界面。 只有当能够登录时Next按钮才能点击,点击后,服务器就会登录此用户。同时这个Next监听器还会产生一条进入房间Hall请求,从而确保了每个用户在登录成功后会进入Hall房间。而其它房间需要用户手动进入
20、。5.2.3 注册界面如上图所表示。Submit按钮会检验输入是否正当,不然会提醒对应输入信息错误情况,Cancel会销毁这个对话框,图。 若输入正当会依据输入产生一个注册数据包发往服务器。但还会碰到如用户名已存在情况。这是注册也是失败。5.2.4 主界面主界面上全部按钮功效均已实现。因为需要支持多房间,在消息显示区域上方有一个Entered House下拉菜单,里面每一项对应着一个消息显示区域和右下方一个Current User列表。分别是目前房间消息和目前房间内用户。右上方All House列表中每一项代表一个房间,双击它。若已进入房间则只是更改Entered House下拉菜单目前选择项
21、。若没有进入过该房间则会产生一个进入该房间请求。等到服务器返回消息后由HouseRelative工作类在EnteredHouse下拉菜单中创建一个条目,同时创建一个该房间消息显示区域和目前房间内用户列表。这些消息全部能够从服务器返回消息中得到。5.2.5 用户消息显示界面在聊天室中全部用户全部能够查看自己或她人资料,而且对自己资料有更改权。只需点击MyDetail按钮或双击Current User列表中用户名即可查看消息。6 测试加入房间,离开房间均能在其它用户端正常显示。消息中英文发送显示正常,全部同房间内人全部能收到。用户信息显示正确工作。见5.2.5节。7 优缺点分析7.1 优点1、 服
22、务器采取多线程应对用户端请求而且结合线程池技术。使得服务器并发量较大。2、 服务器采取将数据协议规范化,使得任务处理步骤清楚。3、 服务器将对同请求产生特定类去处理,使得各个工作之间相互分离而且使得扩展愈加轻易。4、 服务器将数据大部分存放在内存中降低了对数据库访问。5、 用户端采取了接收信息对GUI进行处理模型,使发送请求和得到响应之间异步进行从而使得交互性愈加好。7.2 缺点1、 构建工作类模型及其框架实现花费大量代码和时间。即使扩展性到了提升,可是因为时间关系只能实现少数多个功效。用户注销,好友功效,文件传输功效,私聊功效这些全部是工程计划中一部分,全部需要实现。2、 GUI美观性较差。
23、8 总结经过一段时间努力我们小组实现了这个简单JAVA聊天室系。从数据库支持下注册用户信息更改功效,到多线程网络通信支持下多房间多人聊天功效,到GUI支持下交互界面,我们实现了对聊天功效基础抽象和实现。因为刚刚接触JAVA语言尤其是GUI编程,我们聊天室显得有些简陋,因为时间关系我们也没有去更细心地去修改界面。但经过这个工程学习,我们掌握了多项JAVA编程技术。其中数据库,多线程,网络通信更是对我们以后工作生涯有很大启发和帮助。我们现在已不仅限于只能编出一个在控制台下输入输出字符命令行程序了。这极大地丰富了我们编程经历。同时我们学到了设计需要团体精神。xxx同学完成了聊天室中具体技术总结和介绍(线程池、数据库、网络通信等具体技术)。服务器和用户端具体工作类中和房间相关、聊天消息相关类实现。同时对通信做出了很大优化,如字节数组到字符数组迁移使得聊天室支持汉字和其它文字。UDP到TCP迁移处理了项目早期频发丢包问题。xxx同学完成了对服务器建模、GUI实现、和其它工作类实现。