java学习之即时通信项目实战

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java学习之即时通信项目实战相关的知识,希望对你有一定的参考价值。

 项目总结:这次项目主要是根据视频来的,结果跟到一半感觉跟不上,慢慢自己有了自己的想法,决定自己先不看学习视频,自己先试着写。

  总结写前面,算是写的第一个项目吧。项目中遇到几点问题,首先Scoket对象创建后,服务器端和客户端不能同时创建输入流,否者会引起堵塞。

  然后,读入流应该重新创建个线程做等待写入服务,因为读入流会引起当前线程进入阻塞状态。

     还有一个用户线程对应一个服务线程,不是多个用户线程对应一个服务线程。

     对对象的操作应该由那个对象本身提供操作方法,比如操作UI界面的变化应该由界面本身提拱。

  最后最重要的是写代码之前应该先画个流程图,写代码时参数乱传的,哪里需要就调参数过来。导致思路不清.

首先是需求分析:

  本次项目是模拟及时通信中最基本的功能,类似QQ的应用.

  项目分为:

   (1)服务器端:

    服务器端主要负责用户管理,消息转发功能

   (2) 客户端:

    客户端主要负责用户间的消息发送

详细设计

服务器端

  1、登录服务器后,进行客户端的监听,如有客户端连接,启动用户服务线程,与客户端进行交互。

  2、如客户端向所有人发送消息,服务器将向所有在线用户广播该消息。

      3、如客户端向指定人发送消息,服务器将查找接收人用户线程后转发消息。

      4、用户登录后,向所有人更新用户列表。

客户端:

1、用户登录功能。

2、登录后用户可以看到在线用户列表

3 、向指定人发送消息

4、向所有人发送消息

代码的实现

首先,先构建界面图形出来

 

技术分享

上面左边是用户界面(服务器界面和用户界面一样),右边是登录界面

由于全用手写代码比较麻烦,我用了可视化UI插件;

画出来如下图

技术分享技术分享

界面做出来了,然后构建对象模型,

这里主要需要信息对象,和用户对象;

信息对象又分,登录信息,发送信息和退出信息。这里我把登录信息单独用一个对象构建,因为保存了帐号密码,以后好增加登录验证功能。

然后就是逻辑功能的实现了。

这里我发现看似简单的功能,实现起来还是有点麻烦的。学会了一点就是要模块化。不然自己很容易搞迷糊。

直接上代码:

客户端代码

技术分享
  1 package com.gh.Client;
  2 
  3 import java.awt.Toolkit;
  4 
  5 public class ClientFrame {
  6 
  7     private JFrame Clientframe;
  8     private JTextField textField;
  9     private String username;
 10     private JTextArea textArea = null;
 11     private JList<String> list = null;
 12     private DefaultListModel<String> model = null;
 13     private UserService us;
 14 
 15     // 初始化用户列表
 16     public void InitUserList() {
 17         model = new DefaultListModel<String>();
 18         model.addElement("所有人");
 19         list.setModel(model);
 20     }
 21 
 22     // 添加用户到在线列表
 23     public void AddUserToList(String username) {
 24         // 拆了东墙补西墙。。。之前添加的要全删了,再添加一次
 25         model.removeAllElements();
 26         model.addElement("所有人");
 27         String[] str = username.split(",");
 28         for (String s : str) {
 29             model.addElement(s);
 30         }
 31         //list.setModel(model);
 32     }
 33 
 34     public void updateText(String text) {
 35         StringBuffer sb = new StringBuffer();
 36         sb.append(textArea.getText()).append(DateUtil.getTime() + "\n").append(text).append("\n");
 37         textArea.setText(sb.toString());
 38     }
 39     public void DelUser(String username){
 40         model.removeElement(username);
 41     }
 42 
 43     /**
 44      * Create the application.
 45      */
 46     public ClientFrame(String username,UserService us) {
 47         this.username = username;
 48         this.us=us;
 49         initialize();
 50         // 初始化用户列表
 51         InitUserList();
 52     }
 53 
 54     /**
 55      * Initialize the contents of the frame.
 56      */
 57     private void initialize() {
 58         Clientframe = new JFrame();
 59         Clientframe.addWindowListener(new WindowAdapter() {
 60             @Override
 61             public void windowClosing(WindowEvent e) {
 62                 Info info=new Info();
 63                 info.setFromUser(username);
 64                 info.setInfoType(EnumInfoType.EXIT);
 65                 us.send(info);
 66                 us.setFlag(false);
 67                 Clientframe.dispose();
 68             }
 69         });
 70         Clientframe.setVisible(true);
 71         Clientframe
 72                 .setIconImage(Toolkit.getDefaultToolkit().getImage(ClientFrame.class.getResource("/com/gh/res/1.png")));
 73         Clientframe.setTitle("\u804A\u804A-\u5BA2\u6237\u7AEF");
 74         Toolkit tk = Toolkit.getDefaultToolkit();
 75         Dimension d = tk.getScreenSize();
 76         int x = (int) (d.getWidth() - 534) / 2;
 77         int y = (int) (d.getHeight() - 383) / 2;
 78         Clientframe.setBounds(x, y, 534, 383);
 79         Clientframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 80         Clientframe.getContentPane().setLayout(new BorderLayout(0, 0));
 81 
 82         JLabel label = new JLabel("当前用户是:" + username);
 83         Clientframe.getContentPane().add(label, BorderLayout.NORTH);
 84 
 85         JPanel jpanel = new JPanel();
 86         Clientframe.getContentPane().add(jpanel, BorderLayout.EAST);
 87         jpanel.setLayout(new BorderLayout(0, 0));
 88 
 89         JLabel lblNewLabel = new JLabel("--\u5728\u7EBF\u7528\u6237\u5217\u8868--");
 90         jpanel.add(lblNewLabel, BorderLayout.NORTH);
 91 
 92         list = new JList<String>();
 93         jpanel.add(list, BorderLayout.CENTER);
 94 
 95         JScrollPane scrollPane = new JScrollPane();
 96         Clientframe.getContentPane().add(scrollPane, BorderLayout.CENTER);
 97 
 98         textArea = new JTextArea();
 99         scrollPane.setViewportView(textArea);
100 
101         JPanel panel = new JPanel();
102         Clientframe.getContentPane().add(panel, BorderLayout.SOUTH);
103         panel.setLayout(new BorderLayout(0, 0));
104 
105         JLabel lblNewLabel_1 = new JLabel("\u8BF7\u8F93\u5165\uFF1A");
106         panel.add(lblNewLabel_1, BorderLayout.WEST);
107 
108         textField = new JTextField();
109         panel.add(textField, BorderLayout.CENTER);
110         textField.setColumns(10);
111 
112         JButton button = new JButton("\u53D1\u9001");
113         button.addActionListener(new ActionListener() {
114             public void actionPerformed(ActionEvent e) {
115                 // 获取发送信息
116                 String sendContent = textField.getText().trim();
117                 // 获取发送对象
118                 Info info = new Info();
119                 info.setFromUser(username);
120                 info.setToUser((String) list.getSelectedValue());
121                 info.setContent(sendContent);
122                 info.setInfoType(EnumInfoType.SEND_INFO);
123                 System.out.println(info.getToUser());
124                 // 首先判断发送对象是否为空
125                 if ("".equals(info.getToUser()) || info.getToUser() == null) {
126                     JOptionPane.showMessageDialog(Clientframe, "请选择发送对象");
127                     return;
128                 } else if (info.getToUser().equals(username)) {
129                     JOptionPane.showMessageDialog(Clientframe, "不能对自己发送");
130                     return;
131                 } else if (info.getContent().equals("") || info.getContent() == null) {
132                     JOptionPane.showMessageDialog(Clientframe, "内容不能为空");
133                     return;
134                 } else
135                     us.send(info);
136                 textField.setText("");
137             }
138         });
139         panel.add(button, BorderLayout.EAST);
140     }
141 
142 }
ClientFrame
技术分享
  1 package com.gh.Client;
  2 
  3 import java.awt.Dimension;
  4 
  5 @SuppressWarnings("unused")
  6 public class LoginFrame {
  7 
  8     private JFrame frame;
  9     private JTextField id;
 10     private JPasswordField pwd;
 11 
 12 
 13     /**
 14      * Launch the application.
 15      */
 16     public static void main(String[] args) {
 17         EventQueue.invokeLater(new Runnable() {
 18             public void run() {
 19                 try {
 20                     LoginFrame window = new LoginFrame();
 21                     window.frame.setVisible(true);
 22                     UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
 23                 } catch (Exception e) {
 24                     e.printStackTrace();
 25                 }
 26             }
 27         });
 28     }
 29 
 30     /**
 31      * Create the application.
 32      */
 33     public LoginFrame() {
 34         initialize();
 35     }
 36 
 37     /**
 38      * Initialize the contents of the frame.
 39      */
 40     private void initialize() {
 41         frame =  new JFrame();
 42         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 43         frame.setVisible(true);
 44         frame.setIconImage(Toolkit.getDefaultToolkit().getImage(LoginFrame.class.getResource("/com/gh/res/1.png")));
 45         Toolkit tk=Toolkit.getDefaultToolkit();
 46         Dimension d=tk.getScreenSize();
 47         int x=(int)(d.getWidth()-379)/2;
 48         int y=(int)(d.getHeight()-171)/2;
 49         frame.setResizable(false);
 50         frame.setTitle("\u767B\u5F55");
 51         frame.setBounds(x, y, 379, 171);
 52         frame.getContentPane().setLayout(new GridLayout(3, 1, 20, 5));
 53         
 54         JPanel panel = new JPanel();
 55         frame.getContentPane().add(panel);
 56         FlowLayout fl_panel = new FlowLayout(FlowLayout.CENTER, 5, 10);
 57         fl_panel.setAlignOnBaseline(true);
 58         panel.setLayout(fl_panel);
 59         
 60         JLabel label = new JLabel("\u7528\u6237\u5E10\u53F7\uFF1A");
 61         label.setFont(new Font("微软雅黑", Font.PLAIN, 15));
 62         panel.add(label);
 63         
 64         id = new JTextField();
 65         panel.add(id);
 66         id.setColumns(15);
 67         
 68         
 69         JPanel panel_1 = new JPanel();
 70         FlowLayout flowLayout = (FlowLayout) panel_1.getLayout();
 71         flowLayout.setAlignOnBaseline(true);
 72         flowLayout.setVgap(10);
 73         frame.getContentPane().add(panel_1);
 74         
 75         JLabel label_1 = new JLabel("\u7528\u6237\u5BC6\u7801\uFF1A");
 76         label_1.setFont(new Font("微软雅黑", Font.PLAIN, 15));
 77         panel_1.add(label_1);
 78         
 79         pwd = new JPasswordField();
 80         pwd.setColumns(15);
 81         panel_1.add(pwd);
 82         
 83         JPanel panel_2 = new JPanel();
 84         FlowLayout flowLayout_1 = (FlowLayout) panel_2.getLayout();
 85         flowLayout_1.setVgap(6);
 86         frame.getContentPane().add(panel_2);
 87         
 88         JButton button = new JButton("\u767B\u5F55");
 89         button.addActionListener(new ActionListener() {
 90             public void actionPerformed(ActionEvent arg0) {
 91                 String username=id.getText().trim();
 92                 String password=new String(pwd.getPassword());
 93                 if("".equals(username)||username==null||"".equals(password)||password==null){
 94                     JOptionPane.showMessageDialog(frame, "用户名和密码不能为空");
 95                     return;
 96                 }
 97                 new UserService().login(username, password,frame);
 98             }
 99         });
100         button.setFont(new Font("微软雅黑", Font.PLAIN, 15));
101         panel_2.add(button);
102         
103         JButton button_1 = new JButton("\u9000\u51FA");
104         button_1.addActionListener(new ActionListener() {
105             public void actionPerformed(ActionEvent e) {
106                 int v=JOptionPane.showConfirmDialog(frame, "真的要退出吗", "退出", JOptionPane.YES_NO_OPTION);
107                 if(v==JOptionPane.YES_OPTION)System.exit(0);
108             }
109         });
110         button_1.setFont(new Font("微软雅黑", Font.PLAIN, 15));
111         panel_2.add(button_1);
112     }
113 
114     
115 }
LoginFrame
技术分享
 1 package com.gh.Client;
 2 
 3 import java.io.IOException;
 4 import java.io.ObjectInputStream;
 5 import java.io.ObjectOutputStream;
 6 import java.net.Socket;
 7 
 8 import javax.swing.JFrame;
 9 import javax.swing.JOptionPane;
10 
11 import com.gh.model.Info;
12 import com.gh.model.LoginInfo;
13 
14 public class UserService {
15     private LoginInfo logininfo = null;
16     private ClientFrame clientframe = null;
17     private boolean flag = true;
18     private Info getInfo = null;
19     public boolean isFlag() {
20         return flag;
21     }
22     public void setFlag(boolean flag) {
23         this.flag = flag;
24     }
25     private ObjectOutputStream bw;
26     private ObjectInputStream br;
27     public void login(final String username, final String password, final JFrame frame) {
28         //接收消息线程
29         Thread t=new Thread(new Runnable() {
30             @Override
31             public void run() {
32                 try {
33                     Socket sk = new Socket("192.168.1.102", 8000);
34                     //这里被堵了好久,必须要先创建bw再创建br,因为scoket不许客户端和服务端同时创建输入流否者会堵塞Scoket通道
35                     bw =new ObjectOutputStream(sk.getOutputStream());
36                     br = new ObjectInputStream(sk.getInputStream());
37                     logininfo = new LoginInfo(username, password);
38                     bw.writeObject(logininfo);//向服务器发送登录信息
39                     bw.flush();
40                     //从服务接收登录信息
41                     LoginInfo objflag = (LoginInfo) br.readObject();
42                     if (objflag.isFlag()) {// 如果可以登录
43                         // 创建聊天界面
44                         clientframe = new ClientFrame(logininfo.getName(),UserService.this);
45                         // 聊天界面显示欢迎信息
46                         clientframe.updateText("服务器:欢迎登录!");
47                         frame.dispose();
48                         // 等待接收消息 
49                         while (isFlag()) {
50                             getInfo = new Info();
51                             getInfo = (Info) br.readObject();
52                             switch (getInfo.getInfoType()) {
53                             case SEND_INFO:
54                                 clientframe.updateText("用户:"+getInfo.getFromUser()+"说:"+getInfo.getContent());
55                                 break;
56                             case ADD_USER:
57                                 clientframe.AddUserToList(getInfo.getContent());
58                                 break;
59                             case EXIT:
60                                 clientframe.DelUser(getInfo.getFromUser());
61                                 clientframe.updateText("服务器:用户"+getInfo.getFromUser()+"下线了");
62                                 break;
63                             default:
64                                 break;
65                             }
66 
67                         }
68                     } else {
69                         JOptionPane.showMessageDialog(frame, "用户名或密码错误");
70                     }
71                 } catch (Exception e) {
72                     JOptionPane.showMessageDialog(frame, "服务器连接异常");
73                      //e.printStackTrace();
74                 }
75             }
76         });
77         t.start();
78     }
79     //发送消息线程
80     public void send(Info info){
81         try {
82             bw.writeObject(info);
83             bw.flush();
84         } catch (IOException e) {
85             e.printStackTrace();
86         }
87     }
88 }
UserService

服务端代码

技术分享
  1 package com.gh.Sever;
  2 
  3 import java.awt.EventQueue;
  4 
  5 public class ServerFrame {
  6 
  7     private JFrame Severframe;
  8     private JTextField textField;
  9     private JTextArea textArea = null;
 10     private DefaultListModel<String> model=null;
 11     private JList<String> list=null;
 12     /**
 13      * Launch the application.
 14      */
 15     public static void main(String[] args) {
 16         EventQueue.invokeLater(new Runnable() {
 17             public void run() {
 18                 try {
 19                     ServerFrame window = new ServerFrame();
 20                     window.Severframe.setVisible(true);
 21                     // 设置UI风格为系统默认的风格
 22                     //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
 23                 } catch (Exception e) {
 24                     e.printStackTrace();
 25                 }
 26             }
 27         });
 28 
 29     }
 30     //初始化用户列表
 31     public void InitUserList(){
 32         model=new DefaultListModel<String>();
 33         model.addElement("所有人");
 34         list.setModel(model);
 35     }
 36     //添加用户到在线列表
 37     public void AddUserToList(String username){
 38         model.addElement(username);
 39         list.setModel(model);
 40     }
 41     public void updateText(String text) {
 42         StringBuffer sb = new StringBuffer();
 43         sb.append(textArea.getText()).append("\n").append(DateUtil.getTime()+"--")
 44             .append(text);
 45         textArea.setText(sb.toString());
 46     }
 47     public void DelUser(String username){
 48         model.removeElement(username);
 49     }
 50     /**
 51      * Create the application.
 52      */
 53     public ServerFrame() {
 54         initialize();
 55         // 启动服务
 56         startSever();
 57         //初始化用户列表
 58         InitUserList();
 59     }
 60 
 61     private void startSever() {
 62         textArea.setText("服务器已经启动,正在监听8000端口...");
 63         new Thread(new Runnable() {
 64             @Override
 65             public void run() {
 66                 new ServerService(ServerFrame.this).startSever();
 67             }
 68         }).start();
 69     }
 70 
 71     /**
 72      * Initialize the contents of the frame.
 73      */
 74     private void initialize() {
 75         Severframe = new JFrame();
 76         Severframe
 77                 .setIconImage(Toolkit.getDefaultToolkit().getImage(ServerFrame.class.getResource("/com/gh/res/1.png")));
 78         Severframe.setTitle("\u804A\u804A-\u670D\u52A1\u7AEF");
 79         Toolkit tk = Toolkit.getDefaultToolkit();
 80         Dimension d = tk.getScreenSize();
 81         int x = (int) (d.getWidth() - 534) / 2;
 82         int y = (int) (d.getHeight() - 383) / 2;
 83         Severframe.setBounds(x, y, 534, 383);
 84         Severframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 85         Severframe.getContentPane().setLayout(new BorderLayout(0, 0));
 86 
 87         JLabel label = new JLabel("\u670D\u52A1\u5668\u7AEF");
 88         Severframe.getContentPane().add(label, BorderLayout.NORTH);
 89 
 90         JPanel jpanel = new JPanel();
 91         Severframe.getContentPane().add(jpanel, BorderLayout.EAST);
 92         jpanel.setLayout(new BorderLayout(0, 0));
 93 
 94         JLabel lblNewLabel = new JLabel("--\u5728\u7EBF\u7528\u6237\u5217\u8868--");
 95         jpanel.add(lblNewLabel, BorderLayout.NORTH);
 96 
 97         list = new JList<String>();
 98         jpanel.add(list, BorderLayout.CENTER);
 99 
100         JScrollPane scrollPane = new JScrollPane();
101         Severframe.getContentPane().add(scrollPane, BorderLayout.CENTER);
102 
103         textArea = new JTextArea();
104         scrollPane.setViewportView(textArea);
105 
106         JPanel panel = new JPanel();
107         Severframe.getContentPane().add(panel, BorderLayout.SOUTH);
108         panel.setLayout(new BorderLayout(0, 0));
109 
110         JLabel lblNewLabel_1 = 以上是关于java学习之即时通信项目实战的主要内容,如果未能解决你的问题,请参考以下文章

实战学习开源项目学习之Celery

实战学习开源项目学习之FastDFS部署

Webservice学习之——即时发布与定制发布

分享《深度学习之TensorFlow:入门原理与进阶实战》PDF+源代码

java网络编程学习之——构建基于多线程的网络通信模型1

分享《深度学习之TensorFlow:入门原理与进阶实战》PDF+源代码