基于java的聊天系统的设计与实现

基于java的聊天系统的设计与实现

ID:14110586

大小:1.55 MB

页数:46页

时间:2018-07-26

上传者:jjuclb
基于java的聊天系统的设计与实现_第1页
基于java的聊天系统的设计与实现_第2页
基于java的聊天系统的设计与实现_第3页
基于java的聊天系统的设计与实现_第4页
基于java的聊天系统的设计与实现_第5页
资源描述:

《基于java的聊天系统的设计与实现》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库

**科技大学电信学院课程设计说明书设计题目:基于java的聊天系统设计与实现学院、系:计算机系专业班级:计算机2011-1班学生姓名:指导教师:成绩:2013年10月27日 基于JAVA的聊天系统的设计与实现摘要网络聊天工具已经作为一种重要的信息交流工具,受到越来越多的网民的青睐。目前,出现了很多非常不错的聊天工具,其中应用比较广泛的有Netmeeting、腾讯QQ、MSN-Messager等等。该系统开发主要包括一个网络聊天服务器程序和一个网络聊天客户程序两个方面。前者通过Socket套接字建立服务器,服务器能读取、转发客户端发来信息,并能刷新用户列表。后者通过与服务器建立连接,来进行客户端与客户端的信息交流。其中用到了局域网通信机制的原理,通过直接继承Thread类来建立多线程。开发中利用了计算机网络编程的基本理论知识,如TCP/IP协议、客户端/服务器端模式(Client/Server模式)、网络编程的设计方法等。在网络编程中对信息的读取、发送,是利用流来实现信息的交换,其中介绍了对实现一个系统的信息流的分析,包含了一些基本的软件工程的方法。经过分析这些情况,该聊天工具采用Eclipse为基本开发环境和java语言进行编写,首先可在短时间内建立系统应用原型,然后,对初始原型系统进行不断修正和改进,直到形成可行系统关键词:即时通讯系统B/SC/SMySQLSocketSwing 目录第1章引言11.1开发背景11.2开发目的和意义11.3论文研究内容2第2章即时通讯系统的相关研究32.1C/S开发模式32.2B/S开发模式32.3即时通讯原理42.4Javaweb、Struts2、AJAX、JavaScript应用技术42.5MySQL数据库应用技术42.6Socket通信技术42.7开发环境的搭建5第3章系统分析63.1系统基本功能描述63.2可行性分析63.3系统需求分析73.3.1功能分析7第4章系统设计94.1数据库设计94.2系统模块设计104.2.1聊天系统工作原理图104.2.2系统功能模块图:114.2.3系统用例图:114.2.4活动图:124.3系统类设计144.3.1Message类的设计144.2.2截图类的设计154.2.3聊天记录类的设计16 4.2.4服务器线程类设计17第5章系统实现185.1实现概况185.2注册模块185.2.1流程图185.2.2关键代码185.3登录模块205.3.1流程图205.3.2关键代码205.4聊天模块245.4.1流程图245.4.2关键代码245.5文件模块285.5.1流程图285.5.2关键代码285.6用户管理模块335.6.1流程图335.6.2关键代码335.7其他功能的实现365.7.1截图功能的实现365.7.2聊天记录功能的实现375.7.3服务端线程的实现385.8用户界面的设计38结语42 第1章引言1.1开发背景随着互联网的快速发展,网络聊天工具已经作为一种重要的信息交流工具,受到越来越多的网民的青睐。目前,出现了很多非常不错的聊天工具,其中应用比较广泛的有Netmeeting、腾讯QQ、MSN-Messager等等。无论是个人还是企业等组织机构,对沟通的需求也在不断发展,传统的电话、传真、邮件等沟通方式显然已无法满足当今人们工作和生活沟通的需要。随着软件、网络和通讯三大现代信息技术的发展,在沟通、协作方面有着更多方便、快捷、实时等优势的即时通讯,成为继电话、E-Mail之后又一个完全融入每个人生活的互联网工具。Java是一个由Sun公司开发而成的新一代编程语言。使用它可在各式各样不同种机器、不同种操作平台的网络环境中开发软件。不论你使用的是哪一种WWW浏览器,哪一种计算机,哪一种操作系统,只要WWW浏览器上面注明了“支持Java”,你就可以看到生动的主页。Java正在逐步成为Internet应用的主要开发语言。它彻底改变了应用软件的开发模式,带来了自PC机以来又一次技术革命,为迅速发展的信息世界增添了新的活力。1.2开发目的和意义网络通信在当今信息社会中起着不可或缺的作用,人们可以利用网络通信技术进行即时的信息交流。比如说QQ聊天工具,它就是利用网络通信技术开发的一款众所周知的网络聊天工具。通讯工具最初虽为聊天而诞生,但其作用早已超出了聊天的范畴,随着企业即时通讯工具的出现,即时信息在网络营销中将发挥更大的作用。目前,信息交流是互联网提供的主要内容,网络通信系统有多种实现方式,类似ICQ属于一种点对点的聊天系统;还有一种是基于Socket的集中式聊天系统,这种聊天系统需要登录统一的聊天服务器。考虑到要可以在局域网中应用,本系统使用的是第二种方法,经过设置,在局域网或internet上都可以使用。41 1.3研究内容1、即时通讯原理首先验证登陆,如果成功,则建立与服务端的socket连接,服务端新开启一个线程专门为它服务,将打包好的Message发送给服务器端,服务器端根据Message里面的信息,再将信息转发给其他用户。一个标准的C/S模式。2、Swing技术Swing是一个用于开发Java应用程序用户界面的开发工具包。它以抽象窗口工具包(AWT)为基础使跨平台应用程序可以使用任何可插拔的外观风格。用来实现客服端的界面设计。3、Javaweb和struts2技术采用B/S的结构实现服务器端,对用户和在线用户进行增删改查,和踢用户下线,以及开启服务器和关闭服务器。4、系统的构建客户端采用C/S结构,管理端采用B/S的结构,用Tomcat作为服务器,MySQL作为数据库,还使用到了WindowBuilder开源框架进行界面开发。41 第2章即时通讯系统的相关研究2.1C/S开发模式C/S结构的优点是能充分发挥客户端PC的处理能力,很多工作可以在客户端处理后再提交给服务器。对应的优点就是客户端响应速度快。缺点主要有以下几个:而随着互联网的飞速发展,移动办公和分布式办公越来越普及,这需要我们的系统具有扩展性。这种方式远程访问需要专门的技术,同时要对系统进行专门的设计来处理分布式的数据。客户端需要安装专用的客户端软件。首先涉及到安装的工作量,其次任何一台电脑出问题,如病毒、硬件损坏,都需要进行安装或维护。还有,系统软件升级时,每一台客户机需要重新安装,其维护和升级成本非常高。(大多数没法自动升级而需要人工升级)对客户端的操作系统一般也会有限制。可能适应于Windows98,但不能用于Windows2000或WindowsXP。或者不适用于微软新的操作系统等等,更不用说Linux、Unix等。2.2B/S开发模式 B/S结构(Browser/Server结构)结构即浏览器和服务器结构。它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO)。以目前的技术看,局域网建立B/S结构的网络应用,并通过Internet/Intranet模式下数据库应用,相对易于把握、成本也是较低的。它是一次性到位的开发,能实现不同的人员,从不同的地点,以不同的接入方式(比如LAN,WAN,Internet/Intranet等)访问和操作共同的数据库;它能有效地保护数据平台和管理访问权限,服务器数据库也很安全。特别是在JAVA这样的跨平台语言出现之后,B/S架构管理软件更是方便、速度快、效果优。41 2.3即时通讯原理登陆进入聊天软件后,即显示出好友列表,在线的显示亮头像,不在线的显示灰色头像。双击好友头像即会显示出聊天界面。在聊天页面上,有发送文字,发送截图,和发送文件的功能按钮。点击“发送”按钮之后,程序就会把输入的信息的种类,信息内容、本人的ID号、对方的ID号以及当前的时间等内容打包成一个Message对象通过Socket发送到服务器端。服务器接收到Message之后,按照协议进行解析和转发。这样,双方的即时通讯就实现了。2.4JavaWeb、struts2、Ajax、javascript应用技术通过这些技术,实现服务器的后台管理端,对用户和在线用户进行增删改查,和踢用户下线,以及开启服务器和关闭服务器。以及用户的注册,前台验证等等2.5MySQL数据库应用技术使用MySQL存储用户信息,采用JDBC技术对其进行增删改查。2.6Socket通信技术Socket程序的工作过程:1、建立Socket连接:在通信开始之前由通信双方确认身份,建立一条专用的虚拟连接通道。2、数据通信:利用虚拟连接通道传送数据信息进行通信。3、关闭:通信结束时,再将所建的虚拟连接拆除。具体如下:服务器41 图2-1socket通信2.7开发环境的搭建客户端采用C/S结构,管理端采用B/S的结构,用Tomcat作为服务器,MySQL作为数据库,还使用到了WindowBuilder开源框架进行界面开发。41 第3章系统分析3.1系统基本功能描述客户端可以实现注册,即时聊天,相互之间收发文件,发送截图,查看历史聊天记录等功能。收发消息时,可以实现离线接收。服务器端应当建立一个ServerSocket,并且不断进行侦听是否有客户端连接或者断开连接(包括判断没有响应的连接超时)。服务器端应当是一个信息发送中心,所有客户端的信息都传到服务器端,由服务器端根据要求分发信息。在后台管理系统,可以到对用户进行增删改查,查看在线用户,和踢用户下线3.2可行性分析本系统的可行性分析包括以下几个方面的内容:(1)技术可行性使用Swing和socket技术,可以很轻松地开发出实用、简便、高效的基于网络的即时通讯系统。因此技术上是可以实现的。(2)经济可行性计算机网络已经普及,因此在网络设备上不需要进行大的投入。本系统需要一个MySQL数据库服务器,由于并发使用人数比较少,tomcat可以作为web服务器,所以成本很低。(3)操作可行性只要一台以上计算机连接在同一个局域网内,本系统就可以安装使用,所以操作上完全不存在问题。如果要实现internet上通讯,只需要将服务器端运行在一个有固定IP的公网上就可以。综上所述,即时Java即时通讯系统是可行的。3.3系统需求分析3.3.1功能分析本系统要实现的功能如下:41 1)注册服务器收到用户的注册请求,便开始接受客户传递的信息,诸如客户的呢称,性别,籍贯,个人资料等,接受完毕后,便通过JDBC与后台数据库连接,然后向数据库添加记录,如果成功,便向客户返回其号码。客户收到服务器返回的信息后,便打开窗口登陆。2)登陆在客户端,用户输入其号码和密码,然后建立与服务器的连接,告诉服务器我要登录,服务器收到后,开始通过JDBC读取数据库,然后与用户输入的信息进行比对,如果成功,便打开主程序窗口。然后客户向服务器请求读取好友名单,服务器收到该请求,从数据库中取出好友列表,然后向客户端发送这些信息,客户收到后就在主窗口显示好友。3)聊天客户端首先发送消息到服务器端,服务器端根据发送人信息和接收者信息来转发。例如服务器接收到一个A发给B的消息,先判断B是否已经在线,如果在线就将信息发送过去。如果B不在线则把信息储存在服务器,等B上线了在发送给他。B接收到A发来的信息,如果是未建立对话窗口,则自动打开显示。4)发送截图客户端A点击截图按钮,将屏幕锁定,截取图片,将图片储存在byte[]数组中发送到服务器端。服务器端根据发送人信息和接收者信息来转发。B接收到A发来的截图信息,会根据byte[]构造图片,将图片显示出来。同样,如果是未建立对话窗口,则自动打开显示。5)发送文件客户端A点击发送文件按键,从本地选择文件,将文件在byte[]数组中分批次发送到服务器端。服务器端根据发送人信息和接收者信息来转发。B接收到A发来的文件信息,会根据文件发送的状态和byte[]构造文件。6)日志客户端发送和接收到的信息都会储存在文本文档中。默认储存在C盘下面,会以用户的登录账号为名。41 7)对用户的操作管理员通过B/S的系统对用户进行增加,修改,删除,查找等操作,对系统进行维护。8)在线用户的操作管理员通过B/S的系统对在线用户操作,可以踢用户下线。第4章系统设计4.1数据库设计本系统中所涉及的主要实体及其属性有:用户(用户账号,用户名,密码,个性签名,头像ID,年龄,性别)E-R模型如图所示。41 图4-1系统实体及其属性表4-1User字段名数据类型字段说明键引用备注accountint(6)IDPK主键(自动增一)namevarchar(20)用户名称非空passwordvarchar(20)用户密码非空signatureVarchar(255)签名profileIDint(2)头像IDageint(3)年龄sexsexchar(2)性别41 4.2系统模块设计4.2.1聊天系统工作原理图图4-2系统工作原理41 4.2.2系统功能模块图:图4-3系统模块4.2.3系统用例图:普通用户的用例图:图4-4普通用户用例图41 后台管理员的用例图:图4-5后台用户用例图4.2.4活动图:1)用户登陆活动图首先填写登陆信息,提交以后服务器会对用户名和密码进行验证。如果不正确,返回一个提示信息。如果登陆成功,就更新在线状态。通知所有好友自己已经上线。服务器再检查是否有他的离线消息,如果有这立即发送给用户。41 图4-6用户登录活动图2)发送消息活动图短消息发送以后,服务器端对应的监听线程会接收到一个数据包。此包中包含接收者的信息,如果接收者在线,数据包将会转发到接收者。如果不在线,存在服务器端,等它上线在发送。41 图4-7发送消息活动图4.3系统类设计4.3.1Message类的设计:客户端和服务器端通信时,发送的都是Message类的对象,因此Message类的设计很重要。41 表4-2Message属性名作用privateIntegermsgType;信息类型privateStringcontent;信息的文本内容privateIntegersenderAccount;发送者accountprivateIntegerreceiverAccount;接收者accountprivateStringtime;发送时间privateUsermyself;privateListfriends;自己本身对象,用与好友列表头好友列表privatetransientImageimg;图片对象(不传送)privatebyte[]imageByte;图片的内容privateStringfileName;文件名称privatebyte[]fileByte;文件的长度privateintlength;//文件长度,以KB为单位文件的内容privateintstate;文件传输的状态:0是不接受文件,1是接受文件,2请求发送文件,3文件传输中,4文件传送完成privateIntegermsgType消息的类型有这么几种:publicinterfaceMessageType{Integermessage_succeed=1;//表明是登陆成功Integermessage_login_fail=2;//表明登录失败Integermessage_comm_mes=3;//普通信息包Integermessage_get_onLineFriend=4;//要求在线好友的包Integermessage_ret_onLineFriend=5;//返回在线好友的包Integermessage_offline=6;//下线通知包Integermessage_img=7;//图片包Integermessage_file=8;//文件包}4.3.2截图类的设计:截图类的实现类为:classScreenshotextendsJFrameimplementsMouseListener,MouseMotionListener。41 图4-8Screenshot类截图类的核心是JDK中:Robot类中createScreenCapture(Rectangle screenRect)创建包含从屏幕中读取的像素的图像。先用截取全部屏幕的图片,然后显示出来,覆盖住整个屏幕。然后监听鼠标事件,再用createScreenCapture(Rectangle screenRect)方法截图。双击表示截图成功,右键表示取消截图。4.3.3聊天记录类的设计:记录日志的功能被封装在MessageRecord类中,所在包为com.im.client.record,在发送或接受到数据后,将其写入日志文件。图4-9MessageRecord类41 如果是图片则显示出,发送时间和图片大小。如果是文件则显示出请求发送时间,同意接收时间,接收完成时间,和文件大小。日志文件格式如下:图4-10记录文件4.3.4服务端线程的设计:服务器端的核心是对应客户的线程,每个socket对应一个线程,也就是每一个客户端都在服务器端有一个相应的线程。它负责转发客户端发来的消息。线程类为ClientThread:表4-3ClientThread类属性名作用publicvoidnotifyOnline()通知其他线程,自己上线了,让客户方更新头像publicvoidrun()线程的主题,转发消息publicvoidnotifyOffline(){通知其他线程,自己下线了,让客户方更新头像publicvoidsend(Objecto)发送消息publicObjectreceive()接收消息41 第5章系统实现5.1实现概况本系统可分为登录、聊天、文件、用户管理和注册五个功能模块。“登录”模块为用户提供登录界面,并在用户登录显示好友列表;“聊天”模块实现用户的即时传送信息,即多用户即时聊天,可以发送文字或者截图;“文件”模块主要实现一用户向另一用户发送文件,对方可以选择接受或者拒绝。聊天记录会以文本文档格式保存。“用户管理”模块即管理员对用户进行增删改查,和踢用户下线的操作。下面详细介绍各个模块的具体实现。5.2注册模块5.2.1流程图图5-1用户注册流程图5.2.2关键代码注册的前台页面是showDetail.jsp,后台是UserAction类,UserAction类中有方法:publicStringsaveOrUpdate(){us.saveOrUpdate(user);return"refresh";41 }saveOrUpdate则是用到了Userservice里面的方法:publicvoidsaveOrUpdate(Useru){System.out.println("u.getAccount()="+u.getAccount());if(u.getAccount()==null)ud.save(u);elseud.update(u);}DAO类中的方法:publicvoidsave(Useru){conn=getConnection();try{ps=conn.prepareStatement(SAVE);ps.setString(1,u.getName());ps.setString(2,u.getPassword());ps.setString(3,u.getSignature());ps.setInt(4,1);ps.setInt(5,u.getAge());ps.setString(6,u.getSex());ps.execute();}catch(SQLExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}finally{close();}}网页上显示用户的account图5-2用户注册信息41 5.3登录模块5.3.1流程图图5-3登录流程图5.3.2关键代码1)客户端代码登录事件是定义在classIMClientLoginextendsJFrame这个类的监听事件中。登录成功后,立即向服务器请求自己的好友列表。//登录事件login.addActionListener(newActionListener(){publicvoidactionPerformed(ActionEvente){//cus=newIMClientUserServer();//System.out.println(cus.getServer());Useru=newUser();u.setAccount(Integer.parseInt(account.getText().trim()));u.setPassword(newString(passwordField.getPassword()));//登陆成功41 if(cus.checkLogin(u)){//向服务器发送数据包,请求在线人得信息ClientConnToServerThreadt=Manager.THREAD;Messagem=newMessage();m.setMsgType(MessageType.message_get_onLineFriend);m.setSenderAccount(u.getAccount());try{t.send(m);}catch(IOExceptione1){e1.printStackTrace();}dispose();}elseJOptionPane.showMessageDialog(null,"用户名或密码错误","错误",JOptionPane.ERROR_MESSAGE);}});登录逻辑是在publicclassIMClientUserServer里面,认证成功者就会新建一个线程,专门负责接收服务器端发来的信息classClientConnToServerThreadextendsThread。publicbooleancheckLogin(Objecto){booleansuccess=false;Messagemsg=(Message)server.sendLoginInfo(o);//System.out.println(msg.getMsgType());//System.out.println(MessageType.message_succeed);if(msg.getMsgType().intValue()==MessageType.message_succeed.intValue()){success=true;Useru=(User)o;//将好友列表放到管理器中,进行上下线操作IMFriendListfl=newIMFriendList(msg.getMyself(),msg.getFriends());Manager.FRIEND_LIST=fl;//开启客户线程,接收服务器端的信息connThread=newClientConnToServerThread(server.getSocket());connThread.setSocket(server.getSocket());connThread.start();connThread.setName(u.getAccount()+"");Manager.THREAD=connThread;}returnsuccess;}客户端通过publicclassIMClientServer类与服务器通信41 publicObjectsendLoginInfo(Objecto){try{ObjectOutputStreamoos=newObjectOutputStream(socket.getOutputStream());oos.writeObject(o);ObjectInputStreamois=newObjectInputStream(socket.getInputStream());Messagems=(Message)ois.readObject();returnms;}catch(IOExceptione){e.printStackTrace();}catch(ClassNotFoundExceptione){e.printStackTrace();}returnnull;}这样按照MVC的模式设计,减小的系统耦合。2)服务端代码服务器端接收用户验证信息的代码被写在了一个线程publicclassServerThreadextendsThread中,这样服务器就可以不停的监听端口,接收来自不同客户端的请求,建立socket连接,也不会堵塞在主线程当中。从数据库中搜索用户,看是否存在publicbooleancheckLogin(Useru){Useruser=ud.findById(u.getAccount());if(user!=null){returnuser.getPassword().equals(u.getPassword());}returnfalse;}如果验证成功,查找是否有他的离线消息,有就发送给他。然后在服务器上专门开启一个针对当前用户的线程,并且吧线程放入管理类中,便于日后的管理。if(checkLogin(u)){//返回一个成功登陆的信息报Usermyself=ud.findById(u.getAccount());m.setMsgType(MessageType.message_succeed);m.setMyself(myself);m.setFriends(ud.findAll());//好友列表oos.writeObject(m);//为用户单独创建线程ClientThreadt=newClientThread(s);41 //查看是否有离线消息LinkedListlist=OffLineMsgManager.get(u.getAccount());if(list!=null){for(Messagemsg:list){t.send(msg);}list.clear();}//开启线程t.start();t.setName(u.getAccount()+"");//把用户线程放入管理类中ClientThreadManager.addClientThread(u.getAccount(),t);//通知其他的用户t.notifyOnline();System.out.println("成功");}else{m.setMsgType(3);oos.writeObject(m);System.out.println("失败");//关闭Sockets.close();}41 5.4聊天模块5.4.1流程图图5-4聊天流程图5.4.2关键代码1)客服端代码发送文字信息:客户端发送和显示信息的代码被封装在了IMChatextendsJFrameimplementsActionListener类中,其中发送文字信息的代码//点击的如果是发送buttonif(e.getSource()==confirmButton){Messagem=(Message)makePackage(MessageType.message_comm_mes,null);//发送sendMessage(m);//在自己的Ouput上显示showMessage(m,Color.BLACK);//清空输入input_textArea.setText("");41 }当用户点击发送按钮后,先把先把信息显示在自己的聊天窗口上,后方发送信息,自己发送的信息和接收到的信息用不同的颜色显示。显示文字信息,显示在JtextPane控件中SimpleAttributeSetattrset=newSimpleAttributeSet();StyleConstants.setForeground(attrset,c);Documentdocs=output_pane.getDocument();//利用getDocument()方法取得JTextPane的Document//一般信息if(m.getMsgType().intValue()==MessageType.message_comm_mes){Stringstr=m.getSenderAccount()+""+m.getTime()+" "+""+m.getContent()+" ";try{docs.insertString(docs.getLength(),str,attrset);//设置光标到末尾output_pane.setCaretPosition(docs.getLength());}catch(BadLocationExceptione){e.printStackTrace();}}发送图片信息:在发送图片信息的时候,先将图片转换成为byte[]数组,包装在信息包种发送出去,接收到图片信息时,从byte[]数组构建图片,显示出来。图片和byte[]之间相互转换的关键代码如下://将image转换成byte[]publicbyte[]imageToBytes(Imageimg){ByteArrayOutputStreambos=newByteArrayOutputStream();try{ImageIO.write((RenderedImage)img,"jpg",bos);}catch(IOExceptione){e.printStackTrace();}returnbos.toByteArray();}//将byte[]转换成imagepublicImagebytesToImage(byte[]b){try{41 returnImageIO.read(newByteArrayInputStream(b));}catch(IOExceptione){e.printStackTrace();}returnnull;}在JtextPane中显示图片的代码:if(m.getMsgType().intValue()==MessageType.message_img){//图片信息Stringstr=m.getSenderAccount()+""+m.getTime()+" ";try{//显示发送人和时间docs.insertString(docs.getLength(),str,attrset);//设置光标到末尾output_pane.setCaretPosition(docs.getLength());output_pane.insertIcon(newImageIcon(m.getImg()));docs.insertString(docs.getLength()," ",attrset);//设置光标到末尾output_pane.setCaretPosition(docs.getLength());}catch(BadLocationExceptione){e.printStackTrace();}}在客户端显示截图示例:41 图5-5聊天截图2)服务端代码服务端接收到客户端的信息后,只需要根据他的接收人,进行转发就可以。关键代码如下:Messagem=(Message)receive();//如果是普通信息if(m.getMsgType()==MessageType.message_comm_mes.intValue()){System.out.println(m.getSenderAccount()+"sendto"+m.getReceiverAccount()+"at"+m.getTime());IntegerreceiverAccount=m.getReceiverAccount();ClientThreadt=ClientThreadManager.getClientThread(receiverAccount);if(t==null){//不在线就暂时存储在服务器上OffLineMsgManager.putSingle(receiverAccount,m);}elset.send(m);41 }5.5文件模块5.5.1流程图图5-6发送文件流程图5.5.2关键代码1)客户端代码在客户端采用JfileChooser来浏览本地文件,点击浏览按钮后,会弹出对话框,让用户选择文件,然后将文件名,大小等信息封装在数据包里,发送出去。关键代码如下:@OverridepublicvoidmouseClicked(MouseEvente){fileDialog.setDialogTitle("选择文件");fileDialog.showOpenDialog(IMChat.this);//只能选中文件fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);41 f=fileDialog.getSelectedFile();//发送数据包,请求发送文件Messagem=newMessage();m.setMsgType(MessageType.message_file);m.setSenderAccount(ownerId);m.setReceiverAccount(Integer.parseInt(hideButton.getText()));SimpleDateFormats=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");//发送时间m.setTime(s.format(newjava.util.Date()));m.setFileName(f.getName());//文件名m.setState(2);//请求发送文件intlength=(int)(f.length()/1000);m.setLength(length);//文件大小sendMessage(m);}对方会显示提示信息:图5-7询问接收文件图如果对方同意接收则开启线程。因为文件可能比较大,所以不能一次性发送,只能用线程分批发送。线程关键代码如下:正常发送文件:图5-8文件传输图@Overridepublicvoidrun(){try{41 intnum;//bar.setStringPainted(true);JProgressBarbar=chat.getProgressBar();m.setMsgType(MessageType.message_file);m.setFileName(f.getName());BufferedInputStreambos=newBufferedInputStream(newFileInputStream(f));while((num=bos.read(b))!=-1){m.setFileByte(b);Manager.THREAD.send(m);intvalue=LENGTH/10000;bar.setValue(bar.getValue()+value);}bar.setVisible(false);//bar.setValue(0);//发送完毕SimpleDateFormats=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");m.setTime(s.format(newjava.util.Date()));m.setState(4);Manager.THREAD.send(m);//在窗口上显示发送成功chat.append(newColor(0,0,255),"文件"+f.getName()+"("+f.length()/1000000+"M)"+"发送成功"+" ");}catch(FileNotFoundExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}catch(IOExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}}发送完成后,双方的界面上都会显示成功信息:41 图5-9文件传输成功图客户端接收文件的逻辑:文件的传输状态被定义成了这几种:0是不接受文件,1是接受文件,2请求发送文件,3文件传输中,4文件传送完成客户端接收文件是可根据这些状态,进行操作,关键代码如下://请求发送包if(m.getState()==2){//对话框是否接收inti=JOptionPane.showConfirmDialog(chat,"确定接收"+m.getFileName()+"("+m.getLength()+"KB)","接收文件",JOptionPane.YES_NO_OPTION);Integersender=m.getReceiverAccount();Integergetter=m.getSenderAccount();m.setSenderAccount(sender);m.setReceiverAccount(getter);//同意就发送同意接收数据包if(i==JOptionPane.YES_OPTION){//打开保存文件对话框JFileChooserjfc=newJFileChooser("c:/");jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);intmod=jfc.showSaveDialog(chat);41 if(mod==JFileChooser.APPROVE_OPTION){//如果选择了路径Filef=jfc.getSelectedFile();f=newFile(f.getAbsolutePath()+"/"+m.getFileName());bos=newBufferedOutputStream(newFileOutputStream(f));m.setState(1);send(m);}else{//选择了取消或关闭对话框m.setState(0);send(m);}}else{m.setState(0);send(m);}}elseif(m.getState()==3){//正在传输包byteb[]=m.getFileByte();//设置进度条chat.getProgressBar().setVisible(true);chat.getProgressBar().setMaximum(m.getLength()/10);chat.getProgressBar().setMinimum(0);bos.write(b);}elseif(m.getState()==0){//不同意发送JOptionPane.showMessageDialog(chat,"对方拒绝接收文件","通知",JOptionPane.WARNING_MESSAGE);}elseif(m.getState()==1){//同意发送System.out.println("同意发送");chat.SendFile();}elseif(m.getState()==4){System.out.println(m.getFileName()+"传输完成");chat.getProgressBar().setVisible(false);chat.append(newColor(0,0,255),"文件"+m.getFileName()+"("+m.getLength()/1000+"M)"+"接收完成"+" ");}}}2)服务器端代码:41 服务端只负责转发,关键代码如下:elseif(m.getMsgType()==MessageType.message_file.intValue()){IntegerreceiverAccount=m.getReceiverAccount();ClientThreadt=ClientThreadManager.getClientThread(receiverAccount);t.send(m);}5.6用户管理模块5.6.1流程图图5-10web用户登录图5.6.2关键代码用户管理的前台页面是jsp页面,在页面中可以对用户进行增删改查。41 图5-11用户管理图关键代码如下:以页数列出用户publicListfindByLimit(intbegin,intnum){Listlist=newArrayList();conn=getConnection();try{ps=conn.prepareStatement(FIND_BY_Limit);ps.setInt(1,begin);ps.setInt(2,num);rs=ps.executeQuery();while(rs.next()){Useru=rowMapper(rs);list.add(u);}PreparedStatementp=conn.prepareStatement("selectcount(*)fromuser");rs=p.executeQuery();while(rs.next()){rowCount=rs.getInt(1);}}catch(SQLExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}finally{close();}returnlist;}删除用户:publicvoiddelete(Integeraccount){conn=getConnection();41 try{ps=conn.prepareStatement(DELETE);ps.setInt(1,account);ps.execute();System.out.println("deleteover");}catch(SQLExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}finally{close();}}踢用户下线的逻辑也很简单,关闭socket,将服务器端所对应的线程停止,并且从线程集合中删除改线程就可,关键代码如下:System.out.println("==========IOException==========");e.printStackTrace();//停止线程interrupt();System.out.println(getName()+"下线");//从线程集中删去本线程ClientThreadManager.removeClientThread(Integer.parseInt(getName()));//在线人数System.out.println("在线人数:"+ClientThreadManager.size());//发送数据包通知下线notifyOffline();用户被题下线后:图5-12用户下线图5.7其他功能的实现5.7.1截图功能的实现截图类的核心是JDK中:Robot类中createScreenCapture(Rectangle screenRect)41 创建包含从屏幕中读取的像素的图像。先用newRobot().createScreenCapture(newRectangle(Toolkit.getDefaultToolkit().getScreenSize()));截取全部屏幕的图片,然后显示出来,覆盖住整个屏幕。然后监听鼠标事件,再用createScreenCapture(Rectangle screenRect)方法截图.主要代码如下:publicvoidmouseDragged(MouseEvente){intw=width;inth=height;//System.out.println(x+""+y+""+width+""+height+"");width=e.getX()-x;height=e.getY()-y;w=(w>width?w:width);h=(h>height?h:height);//重绘的边界要比真实的稍微大点//只repaint一定区域,防止屏幕闪烁repaint(x,y,w+2,h+2);}如果点击了鼠标右键则取消截图,双击确定截图完成publicvoidmouseClicked(MouseEvente){//如果是鼠标右键的话if(e.getButton()==MouseEvent.BUTTON3){dispose();}if(e.getClickCount()==2){success();dispose();}}5.7.2聊天记录功能的实现如果是图片则显示出,发送时间和图片大小。如果是文件则显示出请求发送时间,同意接收时间,接收完成时间,和文件大小。主要代码如下:publicstaticvoidafterSend(Objecto){41 Messagemsg=(Message)o;try{Filef=newFile("c:/"+msg.getSenderAccount().toString()+".txt");if(!f.exists()){f.createNewFile();}BufferedWriterbw=newBufferedWriter(newFileWriter(f,true));if(msg.getMsgType().intValue()==MessageType.message_comm_mes){bw.write(msg.getTime()+"发送消息给"+msg.getReceiverAccount()+":"+" ");bw.write(msg.getContent()+" ");bw.write(" ");}elseif(msg.getMsgType().intValue()==MessageType.message_img){bw.write(msg.getTime()+"发送图片给"+msg.getReceiverAccount()+":"+" ");bw.write("图片大小:"+msg.getImageByte().length+"byte"+" ");bw.write(" ");}elseif(msg.getMsgType().intValue()==MessageType.message_file){if(msg.getState()==2){bw.write(msg.getTime()+"请求发送文件给"+msg.getReceiverAccount()+":"+" ");bw.write("文件名:"+msg.getFileName()+"文件大小:"+msg.getLength()+"KB"+" ");}if(msg.getState()==0){bw.write(msg.getTime()+"拒绝接受文件:"+msg.getFileName()+" ");}if(msg.getState()==1){bw.write(msg.getTime()+"你同意接受文件:"+msg.getFileName()+" ");}if(msg.getState()==4){bw.write(msg.getTime()+"发送给"+msg.getReceiverAccount()+"的文件:"+msg.getFileName()+"发送完成"+" ");bw.write(" ");}}bw.flush();bw.close();}catch(IOExceptione){41 //TODOAuto-generatedcatchblocke.printStackTrace();}}5.7.3服务端线程的实现在服务器上,截图信息和文件信息都是进行简单的转发:if(m.getMsgType()==MessageType.message_img.intValue()){IntegerreceiverAccount=m.getReceiverAccount();ClientThreadt=ClientThreadManager.getClientThread(receiverAccount);t.send(m);}转发文字信息时会判断用户是否在线:if(m.getMsgType()==MessageType.message_comm_mes.intValue()){System.out.println(m.getSenderAccount()+"sendto"+m.getReceiverAccount()+"at"+m.getTime());IntegerreceiverAccount=m.getReceiverAccount();ClientThreadt=ClientThreadManager.getClientThread(receiverAccount);if(t==null){//不在线就暂时存储在服务器上OffLineMsgManager.putSingle(receiverAccount,m);}elset.send(m);}5.8用户界面的设计5.8.1登陆界面登陆界面的实现比较简单,是Jlabel,JtextFeild,Jpanel等控件的集合41 图5-13用户登录界面5.8.2好友列表好友列表采用了绝对布局,用到了CardLayout和JscrollPane:图5-14好友列表界面好友列表展开后:41 图5-15好友列表展开界面5.8.3聊天界面双击好友头像后,就会显示出聊天界面:41 图5-16聊天界面41 结语本系统采用C/S和B/S模式,聊天室页面简洁,操作便捷,稳定可靠,性能优良。本系统可以实现通讯系统最基本的两个功能:一是双方能够互相收发信息,二是双方能够互传文件。后台还可以对用户进行管理。这次课程设计用到了,Swing,Socket,JSP,Struts2,AJAX,JDBC,Thread,JavaScript等各种技术,采用MySQL作为数据库,MyEclipse作为开发工具。基本上包含了大学所学习J2EE和J2SE的所有知识。在课程设计的过程中,加强了对多线程的理解和掌控。通过这次的课程设计,我充分体会到学习理论知识的重要性,但更加体会到动手实践的必要性。只有通过亲身的动手实践,才能发现并解决问题,才能真正领悟某一技术的精髓。我相信自己会在将来的软件设计、开发过程中更进一步地学习,不断提升自己的专业能力。41

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
大家都在看
近期热门
关闭