《Java程序设计》课程设计报告简易聊天室系统.doc
华 北 科 技 学 院课程设计说明书班级: 信息与计算科学B091 学号: 姓名: 设计题目: 简易聊天室系统 设计时间: 2011.12.26 至 2011.12.30 指导教师: 评 语:_ _评阅成绩: 评阅教师: 目录1 引 言11.1课程设计选题11.2课程设计的目的11.3本选题的设计背景12.1 功能需求12.2 系统的开发运行环境22 总体设计23.1 系统体系结构设计23 详细设计与实现34.1 登录模块34.2 客户端注册界面模块54.3 客户端聊天模块84.4 服务器端模块104 小结和展望13参 考 文 献14附 录15使用说明书15源程序清单181 引 言1.1课程设计选题简易聊天室系统1.2课程设计的目的使学生巩固和加深以Java 语言为基础的面向对象编程技术理论知识的理解,提高实际动手编程能力的培养,掌握以Java为核心的应用软件开发方案,达到能独立阅读、编制和调试一定规模的Java程序的水平。1.3本选题的设计背景聊天是是网络中广泛应用的服务之一,特别是现在信息社会对聊天的依赖也越累越大,我们品是在生活中很多人都在用的QQ就是一种很好的聊天工具,它不仅只是聊天那么简单,其它的功能也非常强大。基于Java语言在网络编程中的广泛应用与我们基本每时每刻都在接触的聊天系统。我选择尝试对一简单的聊天系统进行开发。对本聊天系统开发的意义:网络聊天系统交流是系统的关键目的所在,能让我们在简单的语句中对复杂社会的了解;交流的过程中使得人与人之间距离彻底拉近,就像面对面的交谈彼此之间没有界限,没有差别,只有心与心的共振。它没有压抑,只有争论,就是心灵之间的一种平台。也是另一种交友的一种重要方式。缺少它你会感觉没什么,但是你一旦有了它你会发现它是那么的重要。需求分析在信息社中,信息是第一手资料,人们聊天也是信息的传播。曾经的会议及面谈已不再发挥主宰作用了,随着各种聊天工具的上市,大家都对聊天产生浓厚的兴趣,聊天系统的存在也有了很大价值。2.1 功能需求用户角度考察系统应具有哪些功能及非功能性需求。能实现用户注册、用户的登录、各客户端能连接起来,服务器能与客户端相连实现用户之间信息的发送与共享。2.2 系统的开发运行环境本系统开发平台: Java 本系统集成开发环境:MyEclipse本系统运行环境: windows 7 2 总体设计3.1 系统体系结构设计聊天系统客户端服务器用户登录用户注册建立连接监听客户用户数据操作聊天交互3 详细设计与实现4.1 登录模块1.功能设计(1)主要实现用户的登录与注册。2.界面设计图1 登录窗口3模块主要算法(1)事件的处理方法public void actionPerformed(ActionEvent e) Object source = e.getSource();/"确定"按钮 if(source = btnOk) btnOkClick();/"取消"按钮if(source = btnCancle) btnCancleClick();/“注册”按钮if(source = btnRegist) btnRegistClick();(2)单击btnOk按钮处理方法private void btnOkClick() String username = txtName.getText();String userpwd = new String(txtPwd.getPassword();if(username.equals("") JOptionPane.showMessageDialog(btnOk,"“用户名”不能为空","提示",JOptionPane.WARNING_MESSAGE);return;if(userpwd.equals("") JOptionPane.showMessageDialog(btnOk,"“密码”不能为空","提示",JOptionPane.WARNING_MESSAGE);return;if (userpwd.equals("haiersoft") /默认密码“haiersoft”/验证通过,隐藏登录窗口,显示聊天主窗口this.setVisible(false);/FrmMain frmMain = new FrmMain();JFrame frmMain = RongQi.getFrm("FrmMain");if (frmMain = null) frmMain = new FrmMain ();RongQi.putFrm("FrmMain", frmMain);/FrmMain frmMain = new FrmMain();frmMain.setVisible(true); else JOptionPane.showMessageDialog(btnOk,"错误的用户名或密码","提示",JOptionPane.WARNING_MESSAGE);4调试与测试 调试过程当中,遇到密码文本框设计没有和实际设计符合,最后通过同学的一起解决了这个问题;在处理“取消”的事件时出现一点小错误,经过反复调试及对程序的时间分析发现将“取消”这个事件的处理错写为“确定”按钮。4.2 客户端注册界面模块1.功能设计(1)有用户的用户名、昵称、密码、性别和头像的选择,用这些信息来实现用户的注册。2.界面设计图2 注册窗口3模块主要算法 (1)创建一个头像栅格布局指定的行数和列中。所有的部件都享有同等的布局的尺寸。JPanel pimg = new JPanel(new GridLayout(2,5);ButtonGroup bgimg = new ButtonGroup();for (int i = 0; i < ckbImage.length; i+) ckbImagei = new JRadioButton(String.valueOf(i + 1),new ImageIcon("images/"+(i + 1) + ".gif");ckbImagei.addItemListener(new ImageLIstener();bgimg.add(ckbImagei);pimg.add(ckbImagei);/头像读取(2)单击btnOk按钮处理的方法private void btnOkClick() String username = txtName.getText();String nickname = txtNickname.getText();String userpwd = new String(txtPwd.getPassword();String repwd = new String(txtRePwd.getPassword();int sex = 0;if (rbFemale.isSelected() sex = 1;if (username.equals("") JOptionPane.showMessageDialog(btnOk,"“用户名”不能为空","提示",JOptionPane.WARNING_MESSAGE);return;if(nickname.equals("") JOptionPane.showMessageDialog(btnOk,"“昵称”不能为空","提示",JOptionPane.WARNING_MESSAGE);return;if(userpwd.equals("") JOptionPane.showMessageDialog(btnOk,"“密码”不能为空","提示",JOptionPane.WARNING_MESSAGE);return;if (userpwd.length() < 6 | userpwd.length() > 10) JOptionPane.showMessageDialog(btnOk,"“密码”长度范围在610之间","提示",JOptionPane.WARNING_MESSAGE);return;if (repwd.equals("") JOptionPane.showMessageDialog(btnOk,"“确认密码”不能为空","提示",JOptionPane.WARNING_MESSAGE);return;if (!repwd.equals(userpwd) JOptionPane.showMessageDialog(btnOk,"“确认密码”和“密码”必须相同","提示",JOptionPane.WARNING_MESSAGE);return;if (userpwd.equals("haiersoft") JOptionPane.showMessageDialog(btnOk,"注册成功","提示",JOptionPane.WARNING_MESSAGE);/调用btnCancleClick()方法,清空信息btnCancleClick();else JOptionPane.showMessageDialog(btnOk,"注册失败","提示",JOptionPane.WARNING_MESSAGE);return;4调试与测试 在调试用户注册界面曾出现当选者用户头像时该头像就被隐藏了,但我对程序中多次的调试,这个问题都没有得到好的解决,最后我尝试将头像的大小改变这个问题就得得到圆满的解决。4.3 客户端聊天模块1.功能设计(1)界面分为3部分:中间部分显示所有聊天信息,右边显示所有在在线客户,底部用于信息的输入与发送。2.界面设计图3 聊天窗口3模块算法(或重要代码段)只要求给出1-2主要模块的算法(1) 从服务器获取聊天信息的线程,接受服务器发送信息的方法。class GetMsgFromServer extends Thread /private String strMsg = null;public GetMsgFromServer() super();public void run() tryreadMsg = new BufferedReader(new InputStreamReader(socketMsg.getInputStream();dostrMsg = readMsg.readLine();/在文本域显示聊天信息txtContent.append(strMsg + "n"); while (strMsg != null); catch(Exception e) e.printStackTrace();(2)事件发送的处理方法public void actionPerformed (ActionEvent e) Object source = e.getSource();if (source = btnSend) String str = txtSend.getText();if (!str.equals("") /网络通信错误printMsg.println(nickname + ":" + str);printMsg.flush();txtSend.setText("");4调试与测试 测试结果的分析与讨论,测试过程中遇到的主要问题及采取的解决措施。聊天室的设计是较为重要的部分,在先前简单的界面设计时较为简单,当通过在该类中添加实现对发送按钮监听时由于没有定义该类的方法连接使得发送按钮不能实现。对这个小问题的检查较为简单。4.4 服务器端模块1.功能设计(1)界面分为3部分:中间显示所有聊天信息,右边显示所有在线用户,底部用于发送系统信息。2.界面设计图4 服务器窗口3模块算法(1)接收客户发送聊天信息的线程class GetMessageThread extends Thread private String stringFromClient = null;private BufferedReader bufferedReaderFromClient;public GetMessageThread(BufferedReader buffer) throws Exception bufferedReaderFromClient = buffer;public void run() try do stringFromClient = bufferedReaderFromClient.readLine();msgList.addFirst(stringFromClient); while (!stringFromClient.toLowerCase().endsWith("bye");int index = bufferedReader.indexOf(bufferedReaderFromClient);bufferedReader.remove(index);printWriter.remove(index); catch (Exception e) e.printStackTrace();(2)向所有客户端发送消息的线程class SendMessageThread extends Thread public SendMessageThread() throws Exception super ();public void run() while (isRun) try String s = null;if (!msgList.isEmpty() s = (String) msgList.removeLast();txtContent.append(s + "n");for (int i = 0; i < printWriter.size(); i+) if (printWriter.get(i) != null) printWriter.get(i).println(s);printWriter.get(i).flush(); else sleep(100);/休眠 catch (Exception e) e.printStackTrace(); 4调试与测试 服务器的是聊天系统中很重要的部分,这个界面设计较为简单,挡在当中添加一些树组件及对客服端信息的发送时,问题接二连三的出现,很多都出现异常,主要是由于在定义语句不小心出现专业术语错误。特别是将字符流放字节流刘缓冲区当中是后由于吧new给忘记了,在结果的运行中,服务器总是接收不到客户端信息,这个问题占据了我大半天得时间才叫我给检查出来了。通过这句简单的话我深感细节决定成败。4 小结和展望对于本系统的实现,首先是构建一个聊天系统主要的框架,通过查找关于聊天系统的相关知识,建立一个聊天系统主要由服务器和客户端,用户的登录界面和注册界面,这是一个很简易的聊天系统。然后通过类的建立登录窗口类FrmLogin客户端窗口类Frmain、注册界面窗口类FrmRegist、服务器类ChatSever;由这些类运行出这几个主要的窗口类,在通过一个容器类RongQi来存储用户的信息,通过类Config读取相应的键对应信息。实现简单的窗口界面的输出。其次是通过在这些类当中添加事件处理,如用户名是否错误,密码是否在规定范围之内;客户端与服务器之间的信息传输实现,实现对按钮的监听实现系统中群消息的发送。最后,通过运行服务器和登录窗口,注册一个用户名实现用户与服务器的链接,就可进行在聊天室中聊天,实现聊天室功能。体会:在这个课程设计中让我体会到一个简单的聊天系统也不是那么好实现的,只是简单窗口的实现也要花费一天半时间,然后通过用户窗口之间添加对事件的处理监听器接口链接最终实现简单聊天系统。本系统能实现在客户端用户聊天窗口中显示用户名昵称和头像,服务器端口能看见当前用户在线状态并显示用户名和昵称。实现多个用户之间在线信息的发送;服务器能监测当前用户所发信息。是现简单的用户聊天功能。本系统有很多不足之处,再对用户消息的发送当中只能是在一个窗口实现,就都是在一个聊天室里面,没有私聊的实现,用户上线后显示的头像不是用户当前头像,是按上线顺序进行排列的,很难区分客服端窗口中谁是当前用户,对于用户下线时也存在区分不清;本人觉得在对用户信息的存储与应该建立一个数据库会更好。参 考 文 献1 邵峰晶, Java SE程序设计高级教程 M. 北京:电子工业出版, 2010.2 耿祥义,张跃平,基于Java大学实用教程 M. 电子工业出版社, 2011249-252.(宋体,小四号,1.5行距)附 录使用说明书1.打开Eclipse运行环境,打开文聊天系统的类ChatSever 点击下图箭头所指按钮运行服务器。图5 ChatSever 类窗口运行的服务器窗口如下图图6 运行服务器窗口2.在前面的基础之上在打开运行FrmLogin类,如下图图7 FrmLogin 类窗口运行窗口如下图8 聊天登录窗口3.可以进行用户注册是,点击“注册”按钮之后弹出如下注册窗口图9 注册窗口4.注册之后点击返回到登录界面登录用户上线,如下图便可进行聊天了如下“痞子蔡”的界面图10 聊天室状态窗口服务器界面如下图图11 服务器状态窗口源程序清单首先看看该系统类的组成如下图图12 聊天室系统类窗口(1)作为客户端登录窗口代码package com.kehuduan.聊天室;import java.awt.event.*;import javax.swing.*;import com.容器.聊天室.RongQi;/作为客户端登录窗口public class FrmLogin extends JFrame implements ActionListener private JPanel p;/面板private JLabel lblName, lblPwd;/姓名 密码 标签private JTextField txtName; /姓名 文本框private JPasswordField txtPwd;/ 密码框private JButton btnOk, btnCancle,btnRegist;/ "确定" "取消" "注册" 按钮public FrmLogin() super("聊天室登录");p = new JPanel();p.setLayout(null);lblName = new JLabel("用户名");lblPwd = new JLabel("密 码");txtName = new JTextField(20);txtPwd = new JPasswordField(20);txtPwd.setEchoChar('*');btnOk =new JButton("确定");btnCancle = new JButton("取消");btnRegist = new JButton("注册");lblName.setBounds(30, 30, 60, 25);txtName.setBounds(95, 30, 120, 25);/初始大小和位置lblPwd.setBounds(30,60,60,25);txtPwd.setBounds(95,60,120,25);btnOk.setBounds(30,90,60,25);btnCancle.setBounds(95,90,60,25);btnRegist.setBounds(160,90,60,25);btnOk.addActionListener(this);btnCancle.addActionListener(this);btnRegist.addActionListener(this);p.add(lblName);p.add(txtName);p.add(lblPwd);p.add(txtPwd);p.add(btnOk);p.add(btnCancle);p.add(btnRegist);this.add(p);this.setSize(250,170);this.setLocation(300, 300);/设置窗体不可改变大小this.setResizable(false);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);/事件处理方法public void actionPerformed(ActionEvent e) Object source = e.getSource();/"确定"按钮 if(source = btnOk) btnOkClick();/"取消"按钮if(source = btnCancle) btnCancleClick();/“注册”按钮if(source = btnRegist) btnRegistClick();/单击btnOk按钮处理方法private void btnOkClick() String username = txtName.getText();String userpwd = new String(txtPwd.getPassword();if(username.equals("") JOptionPane.showMessageDialog(btnOk,"“用户名”不能为空","提示",JOptionPane.WARNING_MESSAGE);return;if(userpwd.equals("") JOptionPane.showMessageDialog(btnOk,"“密码”不能为空","提示",JOptionPane.WARNING_MESSAGE);return;if (userpwd.equals("haiersoft") /默认密码“haiersoft”/验证通过,隐藏登录窗口,显示聊天主窗口this.setVisible(false);/FrmMain frmMain = new FrmMain();/frmMain.setVisible(true);JFrame frmMain = RongQi.getFrm("FrmMain");if (frmMain = null) frmMain = new FrmMain ();RongQi.putFrm("FrmMain", frmMain);/FrmMain frmMain = new FrmMain();frmMain.setVisible(true); else JOptionPane.showMessageDialog(btnOk,"错误的用户名或密码","提示",JOptionPane.WARNING_MESSAGE);/单击btnCancle按钮处理方法private void btnCancleClick() txtName.setText("");txtPwd.setText("");/*/隐藏当前窗体this.setVisible(false);FrmRegist frmRegist = new FrmRegist();/显示注册窗体frmRegist.setVisible(true);*/单击btnRegist按钮的处理方法private void btnRegistClick() /隐藏当前窗体this.setVisible(false);/FrmRegist frmRegist = new FrmRegist();/从容器中获取注册窗体JFrame frmRegist = RongQi.getFrm("FrmGegist");/如果为null,则创建注册窗体,并放入容器中if (frmRegist = null) frmRegist = new FrmRegist ();RongQi.putFrm("FrmRegist", frmRegist);/显示注册窗体frmRegist.setVisible(true);public static void main(String args) /加载了一个和系统一样风格的异常try UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName(); /加载系统风格 catch (Exception e) FrmLogin frmLogin = new FrmLogin();frmLogin.setVisible(true);RongQi.putFrm("FrmLogin", frmLogin);(2)客户端注册窗口代码package com.kehuduan.聊天室;/客户端注册窗口import java.awt.GridLayout;import java.awt.event.*;import javax.swing.*;import com.容器.聊天室.RongQi;public class FrmRegist extends JFrame implements ActionListener /继承窗体 监听接口private JPanel p;/标签 用户名 昵称 密码 确认密码 性别 头像private JLabel lblName, lblNickname, lblPwd, lblRepwd, lblSex, lblImage;private JTextField txtName, txtNickname;/ 姓名 昵称 文本框private JPasswordField txtPwd, txtRePwd;/密码框private JRadioButton rbMale, rbFemale;private JRadioButton ckbImage = new JRadioButton8;/用于头像选择private JButton btnOk, btnCancle, btnReturn;/确定 取消 返回 三个按钮/选中的头像private String checkedHeadImg = null;public FrmRegist() /构造方法super("用户注册");p = new JPanel(null);lblName = new JLabel("用户名:");lblNickname = new JLabel("昵 称:");lblPwd = new JLabel("密 码:");lblRepwd = new JLabel("确认密码:");lblSex = new JLabel("性 别:");lblImage = new JLabel("头 像:");txtName = new JTextField(20);txtNickname= new JTextField(20);txtPwd = new JPasswordField(20);txtRePwd= new JPasswordField(20);rbMale = new JRadioButton("男");rbMale.setSelected(true);/默认 性别为男rbFemale = new JRadioButton("女");/rbFemale.setSelected(true);JPanel pimg = new JPanel(new GridLayout(2,5);ButtonGroup bgimg = new ButtonGroup();for (int i = 0; i < ckbImage.length; i+) ckbImagei = new JRadioButton(String.valueOf(i + 1),new ImageIcon("images/"+(i + 1) + ".gif");ckbImagei.addItemListener(new ImageLIstener();/ckbImagei.addItemListener(new ImageListener();/此处有点问题 已解决bgimg.add(ckbImagei);pimg.add(ckbImagei);/头像读取btnOk = new JButton("确定");btnCancle = new JButton("取消");btnReturn = new JButton("返回");btnOk.addActionListener(this);btnCancle.addActionListener(this);btnReturn.addActionListener(this);/添加监听器ButtonGroup bgsex = new ButtonGroup();bgsex.add(rbMale);bgsex.add(rbFemale);/性别 数组lblName.setBounds(30,30,60,25);txtName.setBounds(95, 30, 200, 25);lblNickname.setBounds(30, 60, 60, 25);txtNickname.setBounds(95, 60, 200, 25);lblPwd.setBounds(30,90,60,25);txtPwd.setBounds(95,90,200,25);lblRepwd.setBounds(30,120,60,25);txtRePwd.setBounds(95,120,200,25);lblSex.setBounds(30,150,60,25);rbMale.setBounds(95, 150, 60, 25);rbFemale.setBounds(160, 150, 60, 25);lblImage.setBounds(30, 180, 60, 25);pimg.setBounds(95,18