第一章基于JAVA的聊天室设计与实现一、设计目的:信息技术的高速发展给人类生产,生活带来了广泛而深远的影响。
“上网冲浪”“数码相机”“PDA”、“彩屏手机”、“蓝牙技术”等新产品,新概念层出不穷,不断冲击着人们的视听。
这些高科技成果为人们带来便捷、快乐的同时,也促进了人机交互技术的发展。
人机交互是关于设计、评价和实现供人们使用的交互式计算机系统,并围绕相关的主要现象进行研究的科学。
它主要研究人与计算机之间的信息交换,涉及计算机科学,心理学,认知科学等诸多学科,是信息技术的一个重要组成部分,并将继续对信息技术的发展产生巨大影响。
聊天室是一项应用广泛,并且实用性强的一个非常典型的人机交互系统。
在信息世界里,聊天工具的使用是非常频繁的,如MSN、QQ、校内通,之类的聊天工具许多人都正在使用。
此次设计的聊天室系统虽然其功能简单,但是在开发技术和过程中,能够充分学习和使用JAVA的技术,进一步培养学生面向对象程序设计的思想,加深对面向对象程序设计四大特性的理解。
第二章功能介绍1.需求分析人们日常生活中越来越多地使用聊天室这项应用来为自己的工作和学习服务。
一个操作简单,界面友好、运行稳定的聊天室对于小型局域网的用户可以起到很好的交流作用。
所谓聊天室就是一个可以让许多用户同时互相通信的网上园地,个人用户可以通过聊天室将自己融入整个主流社会中。
根据目前使用聊天室的用户需求显示,用户对于聊天室主要有以下几点要求:(1). 与聊天室成员一起聊天,可以与聊天室成员私聊(3). 可以改变聊天内容风格,用户注册(含头像)、登录(4). 服务器,服务器过滤非法内容。
(5). 服务器发送通知,保存服务器日志,保存用户聊天信息。
该简易聊天室是为许多喜爱聊天的用户开发设计的,和许多大型的网络聊天室相比该小聊天室功能比较简单,但能实现基本的聊天功能,点对多、点对点聊天和基本的用户功能,登录、查看在线用户等。
2、软件功能描述(1)、用户设置:用户自定义自己的登录名,成功设置后,服务端能接收到新设置的用户名;(2)、登录功能:在服务端开启的情况下,用户可以以自己自定义或者默认的登录名和登录地址端口登录到客户端,并能在服务器端显示登录状态;(3)、公聊:用户可以与“所有人”聊天,在线用户可正常接收并正确显示公聊消(4)、私聊:用在线用户和其他用户聊天。
记录对于聊天室的其他用户是不可见的。
(5)、聊天心情:用户在聊天的过程中可以选择相应的心情来表达自己的情感。
(6)、系统消息:服务端运行,为每一个用户都能接收服务器端发送的信息提示信息。
(7)、用户的状态.每一个客户端用户都可以实时看到目前其他在线用户的状态。
(8)、用户剔除:用户可以被系统剔除,并重新登记登录名和地址。
(9)、用户退出:用户可以在正常情况下退出聊天室。
(10)、服务端控制:服务端开启的情况下,用户才能登陆成功和聊天;用户设置的地址端口也必须与服务端的侦听端口一致,否则不能登录。
第三章 主要模块描述及流程图1.模块描述本聊天室分为聊天室服务端和聊天室客户端,服务端与客户端之间通过套接口Socket(TCP)连接。
在java 中使用套接口相当简单,Java API 为处理套接口的通信提供了一个类.Socket.,使得编写网络应用程序相对容易.服务器采用多线程以满足多用户的请求,通过JDBC 与后台数据库连接,并通过创建一个AppSocket 对象来监听来自客户的连接请求,默认IP 地址为:127.0.0.1默认端口为8888。
(1) 聊天室服务端模块图:聊天室服务端模块图 4-1-1 端口服务:输入要侦听的端口,默认为8888。
启动服务:启动服务器,并开始在设置的端口中侦听,客户端用户可以登录并聊天。
停止服务:关闭服务器,侦听结束。
客户端用户不能再聊天。
发送系统消息:服务器端给所有人或者个别用户发送消息。
消息显示:可以显示所有用户的聊天记录,和上线、下线信息。
退出服务器:退出程序,并停止服务。
(2)聊天室客户端4-1-2用户设置:用户可以设置自己的用户名进行聊天。
连接设置:用户可以设置自己的服务器的IP,端口号,默认地址为:127.0.0.1:8888。
用户登录:只能在聊天室服务端已开启的情况下,用户才能登录,用户登录之后才能开始聊天,登录后不能再修改用户设置和连接设置。
用户注销:退出聊天,可以继续修改用户设置和连接设置。
发送和接收聊天信息:用户可以给所有人或者个别用户发送信息,并能看到其他用户发送给自己或所有人的消息。
退出:关闭所有聊天并退出客户端。
2.流程图流程图4-1-33.主要类UML关系图:1、聊天室服务器端设计:聊天室服务端主要包括4个文件,它们的功能如下:(1)AppServer .java 服务器端进行监听客户端进行服务器的启动,以及端客户进行处理用户退出。
(2)ServerFrame 为服务器端管理界面,负责用户帐号信息保存和用户在线的状态和相关服务器端口的信息以及访问的方式。
(3)serverChat.java 负责对用户信息的处理包括公聊和私聊的信息的发送以及将聊天信息的序列化对象填加到保存聊天信息的记事本中。
(4)serverMessage.java该类是实现服务器端的消息的收发的类。
该类分别定义了向某用户及所有人发送消息的方法,发送的消息会显示在主界面类的界面上。
(5)Register.java处理用户注册, 用户登录,进行选择自己喜欢的头像和注册相应的信息聊天室客户端主要包括6个文件,其主要功能如下:(1).ChatClient.java 为客户端程序启动类,负责客户端的启动和退出。
(2).Login.java 为客户端程序登录界面,负责用户帐号信息的验证与反馈。
(3).Register.java 为客户端程序注册界面,负责用户帐号信息的注册验证与反馈。
(4).ChatRoom.java 为客户端程序聊天室主界面,负责接收、发送聊天内容与服务器端的Connection.java 亲密合作。
(5).Windowclose 为ChatRoom.java的内部类,负责监听聊天室界面的操作,当用户退出时返回给服务器信息。
(6).Clock.java 为客户端程序的一个小程序,实现的一个石英钟功能。
六.主要程序代码清单和界面展示:1.服务器的启动画面以及相应的代码:public class AppServer extends Thread {private ServerSocket serverSocket;private ServerFrame sFrame;private static Vector userOnline = new Vector(1, 1)private static Vector v = new Vector(1, 1);创建服务器启动服务监听8888端口public AppServer() {sFrame = new ServerFrame();try {serverSocket = new ServerSocket(8888);// 获取服务器的主机名和IP地址InetAddress address = InetAddress.getLocalHost();sFrame.txtServerName.setText(address.getHostName());sFrame.txtIP.setText(address.getHostAddress());sFrame.txtPort.setText("8888");} catch (IOException e) {fail(e, "不能启动服务!");}sFrame.txtStatus.setText("已启动...");this.start(); // 启动线程}public static void fail(Exception e, String str) {System.out.println(str + " 。
" + e);}//监听客户的请求,当有用户请求时创建 Connection线程//public void run() {try {while (true) {// 监听并接受客户的请求Socket client = serverSocket.accept();new Connection(sFrame, client, userOnline, v); // 支持多线程// System.out.println("userLength:"+userLength)}} catch (IOException e) {fail(e, "不能监听!");}}//启动服务器//public static void main(String args[]) {new AppServer();}}2.客户端管理界面如下:服务器端图 6-1-13.用户的注册信息主要如下代码:public class Register extends JFrame implements ActionListener {private JComboBox comboBox;private static final long serialVersionUID = 9019746127517522180L;JPanel pnlRegister;JLabel lblUserName,lblGender,lblAge;JLabel lblPassword,lblConfirmPass,lblEmail,logoPosition;JTextField txtUserName,txtAge,txtEmail;JPasswordField pwdUserPassword,pwdConfirmPass;JRadioButton rbtnMale,rbtnFemale;ButtonGroup btngGender;JButton btnOk,btnCancel,btnClear;String strServerIp;final JLabel headLabel = new JLabel();//用于将窗口用于定位Dimension scrnsize;Toolkit toolkit=Toolkit.getDefaultToolkit(); //构造方法public Register(String ip){super("[HappyChat]聊天室注册窗口");strServerIp=ip;pnlRegister=new JPanel();this.getContentPane().add(pnlRegister);lblUserName=new JLabel("用户名:");lblGender=new JLabel("性别:");lblAge=new JLabel("年龄:");lblPassword=new JLabel("密码:");lblConfirmPass=new JLabel("确认密码:");lblEmail=new JLabel("电子邮件:");txtUserName=new JTextField(30);txtEmail=new JTextField(30);txtAge=new JTextField(10);pwdUserPassword=new JPasswordField(30);pwdConfirmPass=new JPasswordField(30);rbtnMale=new JRadioButton("男",true);rbtnFemale=new JRadioButton("女");btngGender=new ButtonGroup();btnOk=new JButton("确定(O)");btnOk.setMnemonic('O');btnOk.setToolTipText("保存注册信息");btnCancel=new JButton("返回(B)");btnCancel.setMnemonic('B');btnCancel.setToolTipText("返回登录窗口");btnClear=new JButton("清空(L)");btnClear.setMnemonic('L');btnClear.setToolTipText("清空注册信息");try{//连接到服务器Socket toServer;toServer = new Socket(strServerIp,8888);ObjectOutputStream streamToServer=new ObjectOutputStream (toServer.getOutputStream());//写客户详细资料到服务器socketstreamToServer.writeObject((Register_Customer)data);//读来自服务器socket的登陆状态BufferedReader fromServer=new BufferedReader(new InputStreamReader(toServer.getInputStream()));String status=fromServer.readLine();//显示成功消息JOptionPane op=new JOptionPane();op.showMessageDialog(null,status);if(status.equals(data.custName+"注册成功")){txtUserName.setText("");pwdUserPassword.setText("");pwdConfirmPass.setText("");txtAge.setText("");txtEmail.setText("");}//关闭流对象streamToServer.close();fromServer.close();}catch(InvalidClassException e1){JOptionPane.showMessageDialog(null,"类错误!");}catch(NotSerializableException e2){JOptionPane.showMessageDialog(null,"对象未序列化!");}catch(IOException e3){JOptionPane.showMessageDialog(null,"不能写入到指定服务器!");}} //方法register()结束public static void main(String args[]){new Register("127.0.0.1");}} //class Register 结束聊天注册窗口图6-1-24.聊天室登录主要代码:// Title: HappyChat聊天系统登录程序////Description: 根据指定的服务器地址、用户名和密码登录聊天服务器// public class Login extends JFrame implements ActionListenerprivate static final long serialVersionUID = -8965773902056088264Lprivate JPanel pnlLogin;private JButton btnLogin, btnRegister, btnExit;private JLabel lblServer, lblUserName, lblPassword, lblLogo; private JTextField txtUserName, txtServer;private JPasswordField pwdPassword;private String strServerIp;// 用于将窗口定位private Dimension scrnsize;private Toolkit toolkit = Toolkit.getDefaultToolkit()// 构造登陆窗体//public Login() {super("登录[HappyChat]聊天室");pnlLogin = new JPanel();this.getContentPane().add(pnlLogin);lblServer = new JLabel("服务器(S):");lblUserName = new JLabel("用户名(U):");lblPassword = new JLabel("密码(P):");txtServer = new JTextField(20);txtServer.setText("127.0.0.1");txtUserName = new JTextField(20);pwdPassword = new JPasswordField(20);btnLogin = new JButton("登录(L)");btnLogin.setToolTipText("登录到服务器");btnLogin.setMnemonic('L');btnRegister = new JButton("注册(R)");btnRegister.setToolTipText("注册新用户");btnRegister.setMnemonic('R');btnExit = new JButton("退出(X)");btnExit.setToolTipText("退出系统");btnExit.setMnemonic('X');// 设置登录窗口setResizable(false);setSize(340, 260);setVisible(true);scrnsize = toolkit.getScreenSize();setLocation(scrnsize.width / 2 - this.getWidth() / 2, scrnsize.height / 2 - this.getHeight() / 2);Image img = toolkit.getImage("images\\appico.jpg");= ae.getSource();if (source.equals(btnLogin)) {// 判断用户名和密码是否为空if (txtUserName.getText().equals("")|| pwdPassword.getText().equals("")) {JOptionPane op1 = new JOptionPane();op1.showMessageDialog(null, "用户名或密码不能为空");} else {strServerIp = txtServer.getText();login();}}if (source.equals(btnRegister)) {strServerIp = txtServer.getText();this.dispose();new Register(strServerIp);}if (source == btnExit) {System.exit(0);}} // actionPerformed()结束// 登录事件响应方法//@SuppressWarnings("deprecation")public void login() {// 接受客户的详细资料Customer data = new Customer();data.custName = txtUserName.getText();data.custPassword = pwdPassword.getText();try {// 连接到服务器Socket toServer;toServer = new Socket(strServerIp, 8888);ObjectOutputStream streamToServer = new ObjectOutputStream(toServer.getOutputStream());// 写客户详细资料到服务器socketstreamToServer.writeObject((Customer) data);// 读来自服务器socket的登录状态BufferedReader fromServer = new BufferedReader(new InputStreamReader(toServer.getInputStream()));String status = fromServer.readLine();if (status.equals("登录成功")) {new ChatRoom((String) data.custName, strServerIp);this.dispose();// 关闭流对象streamToServer.close();fromServer.close();toServer.close();} else {JOptionPane.showMessageDialog(null, status);// 关闭流对象streamToServer.close();fromServer.close();toServer.close();}} catch (ConnectException e1) {JOptionPane.showMessageDialog(null, "未能建立到指定服务器的连接!");} catch (InvalidClassException e2) {JOptionPane.showMessageDialog(null, "类错误!");} catch (NotSerializableException e3) {JOptionPane.showMessageDialog(null, "对象未序列化!");} catch (IOException e4) {JOptionPane.showMessageDialog(null, "不能写入到指定服务器!");}} // login()结束// 启动登陆窗体public static void main(String args[]) {new Login();}} // Class Login结束5.聊天室登录界面:6.聊天界面代码:public class ChatRoom extends Thread implements ActionListener {private JComboBox daXiaoComboBox;private JComboBox yangShiComboBox;private JComboBox zitiComboBox;private JComboBox emote;static JFrame frmChat;JPanel pnlChat;JButton btnCls, btnExit, btnSend, btnClear, btnSave, btnTimer; JLabel lblUserList, lblUserMessage, lblSendMessage, lblChatUser; JLabel lblUserTotal, lblCount, lblBack;JTextField txtMessage;java.awt.List lstUserList;TextArea taUserMessage;JComboBox cmbUser;JCheckBox chPrivateChat;String strServerIp, strLoginName;Thread thread;final JLabel headLabel = new JLabel();// 构造方法public ChatRoom(String name, String ip) {// Dialog d = new FontDialog();strServerIp = ip;strLoginName = name;frmChat = new JFrame("聊天室" + "[用户:" + name + "]");pnlChat = new JPanel();frmChat.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frmChat.getContentPane().add(pnlChat);Font fntDisp1 = new Font("宋体", Font.PLAIN, 12);String list[] = { "所有人" };btnCls = new JButton("清屏(C)");btnExit = new JButton("退出(X)");btnSend = new JButton("发送(N)");btnSave = new JButton("保存(S)");btnTimer = new JButton("时钟(T)");lblUserList = new JLabel("【在线用户列表】");lblUserMessage = new JLabel("【聊天信息】");lblSendMessage = new JLabel("聊天内容:");lblChatUser = new JLabel("你对:");lblUserTotal = new JLabel("在线人数:");lblCount = new JLabel("0");lstUserList = new java.awt.List();txtMessage = new JTextField(170);cmbUser = new JComboBox(list);// chenmincmbUser.addItemListener(new ItemListener() {public void itemStateChanged(ItemEvent arg0) { freshHead();}});chPrivateChat = new JCheckBox("私聊");taUserMessage = new TextArea("", 300, 200,TextArea.SCROLLBARS_VERTICAL_ONLY);// 只能向下滚动// taUserMessage.setText("aaaaaa汉字aaaa");taUserMessage.setForeground(new Color(0, 0, 0));taUserMessage.setEditable(false); // 不可写入emote.setModel(new DefaultComboBoxModel(new String[] { "表情", "微笑","甜笑", "惊喜", "嘻嘻", "扮酷", "嘿嘿", "傻笑", "好奇", "媚眼", "鬼脸", "陶醉","想想" }));emote.setBounds(141, 301, 60, 23);pnlChat.add(emote);zitiComboBox = new JComboBox();zitiComboBox.addItemListener(new ItemListener() {public void itemStateChanged(ItemEvent arg0) {freshFont();boolean isFirstLogin = true; // 判断是否刚登陆boolean isFound; // 判断是否找到用户Vector user_exit = new Vector();try {// Socket toServer;// toServer = new Socket(strServerIp, 8888);for (;;) {Socket toServer;toServer = new Socket(strServerIp, 8888);// 将信息发往服务器messobj = new Message();ObjectOutputStream streamtoserver = new ObjectOutputStream(toServer.getOutputStream());streamtoserver.writeObject((Message) messobj);// 收来自服务器的信息ObjectInputStream streamfromserver = new ObjectInputStream(toServer.getInputStream());messobj = (Message) streamfromserver.readObject();// //////刷新聊天信息列表//////////if (isFirstLogin) // 如果刚登陆{intMessageCounter = messobj.chat.size(); // 屏蔽该用户登陆前的聊天内容isFirstLogin = false;}if (strLoginName.equals(messobj.ti)) {// taUserMessage.append("ni bei ti");exitChatRoom();JOptionPane.showMessageDialog(null, strLoginName+ "你被管理员剔除!");}if (!serverMessage.equals(messobj.serverMessage)) {serverMessage = messobj.serverMessage;taUserMessage.append("[系统消息]:" + serverMessage+"\n");}// taUserMessage.setText("");for (int i = intMessageCounter; i < messobj.chat.size(); i++) {Chat temp = (Chat) messobj.chat.elementAt(i);// chenminString emote = temp.emote;if (emote.equals("表情")) {emote = "";} else {emote += "地";}String temp_message;if (temp.chatUser.equals(strLoginName)) {if (temp.chatToUser.equals(strLoginName)) {temp_message = "系统提示您:请不要自言自语!" + "\n";} else {if (!temp.whisper) // 不是悄悄话{temp_message = "【你】对【" + temp.chatToUser + "】"+ emote + "说:" + temp.chatMessage+ "\n";} else {temp_message = "【你】悄悄对【" + temp.chatToUser+ "】" + emote + "说:" + temp.chatMessage+ "\n";}}} else {基于JAVA的聊天室的设计与实现计算机072 周蔓 0708140822if (temp.chatToUser.equals(strLoginName)) {if (!temp.whisper) // 不是悄悄话{temp_message = "【" + temp.chatUser + "】对【你】"+ emote + "说:" + temp.chatMessage+ "\n";} else {temp_message = "【" + temp.chatUser + "】悄悄对【你】"+ emote + "说:" + temp.chatMessage+ "\n";}{temp_message = "【" + temp.chatUser + "】对【"+ temp.chatToUser + "】" + emote+ "说:" + temp.chatMessage + "\n";} else {temp_message = "";}} else {temp_message = "";}}}taUserMessage.append(temp_message);intMessageCounter++;}// //////刷新在线用户//////////lstUserList.clear();for (int i = 0; i < erOnLine.size(); i++) {String User = ((Customer) erOnLine.elementAt(i)).custName;lstUserList.addItem(User);}Integer a = new Integer(erOnLine.size());lblCount.setText(a.toString());// 显示用户进入聊天室的信息if (erOnLine.size() > intUserTotal) {// chenminString tempstr = ((Customer) erOnLine.elementAt(erOnLine.size() - 1)).custName;// String tempstr = erOnLine.elementAt(// erOnLine.size() - 1).toString();if (!tempstr.equals(strLoginName)) {taUserMessage.append("【" + tempstr + "】来了" + "\n");}}// 显示用户离开聊天室的信息if (erOnLine.size() < intUserTotal) {for (int b = 0; b < user_exit.size(); b++) {isFound = false;for (int c = 0; c < erOnLine.size(); c++) {String tempstr = ((Customer) user_exit.elementAt(b)).custName;if (tempstr.equals(((Customer) erOnLine.elementAt(c)).custName)) {isFound = true;break;}}if (!isFound) // 没有发现该用户{String tempstr = ((Customer) user_exit.elementAt(b)).custName;if (!tempstr.equals(strLoginName)) {taUserMessage.append("【" + tempstr + "】走了"+ "\n");}}}} catch (Exception e) {@SuppressWarnings("unused")JOptionPane jop = new JOptionPane();JOptionPane.showMessageDialog(null, "不能连接服务器!");e.printStackTrace();frmChat.dispose();// System.out.println();// System.out.println(e.getMessage());}} // run()结束private void exitChatRoom() {// TODO 自动生成方法存根exit();}try {Socket toServer = new Socket(strServerIp, 1001);// 向服务器发送信息ObjectOutputStream outObj = new ObjectOutputStream(toServer.getOutputStream());outObj.writeObject(exit);outObj.close();toServer.close();frmChat.dispose();// this.destroy();} catch (Exception e) {}} // exit()结束// "发送"按钮public void sendMessage() {Chat chatobj = new Chat();chatobj.chatUser = strLoginName;chatobj.chatMessage = txtMessage.getText();chatobj.chatToUser = String.valueOf(cmbUser.getSelectedItem());chatobj.whisper = chPrivateChat.isSelected() ? true : false;chatobj.emote = emote.getSelectedItem().toString();// 向服务器发送信息try {Socket toServer = new Socket(strServerIp, 8888);ObjectOutputStream outObj = new ObjectOutputStream(toServer.getOutputStream());outObj.writeObject(chatobj);txtMessage.setText(""); // 清空文本框outObj.close();toServer.close();} catch (Exception e) {}} // sendMessage()结束// "保存"按钮public void saveMessage() {try {FileOutputStream fileoutput = new FileOutputStream(this.strLoginName + "_message.txt", true);String temp = taUserMessage.getText();// System.out.println(temp);fileoutput.write(temp.getBytes());fileoutput.close();JOptionPane.showMessageDialog(null, "聊天记录保存在" + this.strLoginName+ "_message.txt");} catch (Exception e) {System.out.println(e);}}// 将所选用户添加到cmbUser中public void changeUser() {boolean key = true;String selected = lstUserList.getSelectedItem();// JOptionPane.showMessageDialog(null, selected);for (int i = 0; i < cmbUser.getItemCount(); i++) { if (selected.equals(cmbUser.getItemAt(i))) {key = false;break;}}if (key == true) {cmbUser.insertItemAt(selected, 0);}String head = getUserHead(lstUserList.getSelectedItem()); // JOptionPane.showMessageDialog(null, head);cmbUser.setSelectedItem(selected);// chenminheadLabel.setIcon(new ImageIcon("face//" + head + ".JPG")); } // changeUser()结束// chenminprotected void freshHead() {// TODO 自动生成方法存根String head = getUserHead(cmbUser.getSelectedItem().toString());// JOptionPane.showMessageDialog(null, head);// cmbUser.setSelectedItem(selected);// chenminheadLabel.setIcon(new ImageIcon("face//" + head + ".JPG"));}// chenminprivate String getUserHead(String selectedItem) {// TODO 自动生成方法存根String head = "oo";for (int i = 0; i < erOnLine.size(); i++) {String User = ((Customer) erOnLine.elementAt(i)).custName;head = ((Customer) erOnLine.elementAt(i)).custHead;// System.out.println(User+":"+head);if (User.equals(selectedItem)) {break;}// lstUserList.addItem(User);}return head;}public static void main(String args[]) {new ChatRoom("测试用户", "127.0.0.1");基于JAVA的聊天室的设计与实现计算机072 周蔓 0708140822 }}参考资料:Merlin Hughes Michael Shoffner《Java网络编程实例》清华大学出版社耿祥义张跃平《JA V A 2 实用教程》清华大学出版社张辉潭浩强《JA V A 程序设计》清华大学出版社30。