黑马程序员技术交流社区

标题: 【上海校区】java聊天室群聊及私聊实现! [打印本页]

作者: 不二晨    时间: 2019-3-22 08:55
标题: 【上海校区】java聊天室群聊及私聊实现!
java聊天室群聊及私聊实现!

一:业务逻辑

连接数据库,实现注册登录账号的功能
使用serverSocket接收并发送消息实现服务器功能
客户端使用socket与服务器交互
二:类设计及代码结构

MyMessage类:该类主要用于封装发送的消息内容
ServerSocketTest类:服务器段实现类
signup类:通过数据库实现登录注册
SocketFrame:聊天主界面类
三:代码
Mymessage类代码:

package objtalk;

import java.io.Serializable;
import java.util.ArrayList;

import javax.swing.text.StyledDocument;

/*
* 该消息类分为两种
* 一种是实际消息内容
* 还有一种是当前群聊的成员信息
* */

public class MyMessage implements Serializable {// 序列化&&反序列化(用于被传输的对象)
        public static final long serialVersionUID = 1l;
        public static final int MES_TYPE_PLAIN = 1;//文本消息
        public static final int MES_TYPE_UPDATE_CLIENTLIST = 2;//更新用户列表消息

        private StyledDocument content ;//非文本消息(例如图片)
        private ArrayList<String> clientList;//当前群聊成员信息
        private int mesType = -1;
        private boolean ifmass=true;//判断是群聊消息还是私聊信息
        private String ip="null";//私发message对象ip
        private String usename = "null";

        public String getIp() {
                return ip;
        }

        public void setIp(String ip) {
                this.ip = ip;
        }

        public MyMessage(Boolean ifmass,int mesType) {
                this.ifmass=ifmass;
                this.mesType = mesType;
        }

        public int getMesType() {
                return mesType;
        }

        public void setMesType(int mesType) {
                this.mesType = mesType;
        }

        public StyledDocument getContent() {
                return content;
        }

        public void setContent(StyledDocument content) {
                this.content = content;
        }

        public ArrayList<String> getClientList() {
                return clientList;
        }

        public void setClientList(ArrayList<String> clientList) {
                this.clientList = clientList;
        }

        public boolean getisIfmass() {
                return ifmass;
        }

        public void setIfmass(boolean ifmass) {
                this.ifmass = ifmass;
        }
}

signup类代码:

package objtalk;

/*创建一张talk数据表
* 表结构为usename和password
* */


import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Statement;

public class signup extends JFrame{
        private JTextField usename = new JTextField();//文本输入框
        private JTextField password  = new JTextField();
        private JButton signup = new JButton("注册");//按钮
        private JButton signin = new JButton("登陆");
       
        //数据库信息
        private String user = "";
        private String pwd = "";
        private String url = "";//jdbc:myaql://ip或端口号/需要打开的database
       
        private boolean tag = false;//判断账号密码是否正确
        public signup() {
                        // TODO Auto-generated constructor stub
                this.setSize(300,400);
                this.setLocationRelativeTo(null);
                this.setDefaultCloseOperation(EXIT_ON_CLOSE);
                this.setLayout(null);
               
                this.add(usename);
                this.add(password);
                this.add(signin);
                this.add(signup);
               
                usename.setSize(100,30);
                password.setSize(100,30);
                signin.setSize(100,50);
                signup.setSize(100,50);
               
                usename.setLocation(100,100);
                password.setLocation(100,200);
                signin.setLocation(50,300);
                signup.setLocation(150,300);
               
               
                try {
                        Class.forName("com.mysql.jdbc.Driver");//开启数据库
                } catch (ClassNotFoundException e2) {
                        // TODO Auto-generated catch block
                        e2.printStackTrace();
                }
               
                signin.addActionListener(new ActionListener() {
                       
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                String useName = usename.getText().toString();
                                String passWord = password.getText().toString();
                                if(useName.isEmpty()||passWord.isEmpty()){
                                                JOptionPane.showMessageDialog(null, "请输入用户名或密码", "error",JOptionPane.ERROR_MESSAGE);
                                }
                                else{
                                        try {
                                                Connection con = (Connection) DriverManager.getConnection(url, user, pwd);//数据库连
                                                Statement stmt = (Statement) con.createStatement();//创建语句对象
                                                String sql = "select * from talk";//数据库语句
                                                ResultSet rs = (ResultSet) stmt.executeQuery(sql);//执行语句得到结果,以行的角度表现查询结果
                                                java.sql.ResultSetMetaData rsmd = rs.getMetaData();//结果以列的形式展现
                                                while(rs.next()){//按行逐个读取查询的内容,next()表示行的移动
                                                        if(rs.getString(1).equals(useName)&&rs.getString(2).equals(passWord)){
                                                                tag = true;
                                                        new SocketFrame().setVisible(true);//跳转到主界面
                                                        exits();//关闭当前界面
                                                        return;
                                                        }
                                                }
                                                if(tag==false){
                                                        JOptionPane.showMessageDialog(null, "账号密码错误!", "error",JOptionPane.ERROR_MESSAGE);
                                                }
                                } catch (SQLException e1) {
                                        // TODO Auto-generated catch block
                                        e1.printStackTrace();
                                }
                        }
                }
        });
               
                signup.addActionListener(new ActionListener() {
                       
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                // TODO Auto-generated method stub
                                String useName = usename.getText().toString();
                                String passWord = password.getText().toString();
                                if(useName.isEmpty()||passWord.isEmpty()){
                                        JOptionPane.showMessageDialog(null, "请输入用户名或密码", "error",JOptionPane.ERROR_MESSAGE);
                                }
                                else{
                                        Connection con;
                                        try {
                                                con = (Connection) DriverManager.getConnection(url, user, pwd);
                                                Statement stmt = (Statement) con.createStatement();
                                                String sql = "insert talk value('"+useName+"','"+passWord+"');";
                                                stmt.executeUpdate(sql);
                                                JOptionPane.showMessageDialog(null,"注册成功", "done",JOptionPane.ERROR_MESSAGE);
                                                //stmt.executeQuery(sql);//执行语句得到结果,以行的角度表现查询结果
                                        } catch (SQLException e1) {
                                                // TODO Auto-generated catch block
                                                e1.printStackTrace();
                                        }//数据库连接,Connection是接口不能用new
                                }
                        }
                });
        }
       
        public void exits() {
                this.setVisible(false);
        }
       
       
        public static void main(String[] args) {
                new signup().setVisible(true);
        }
}

SocktFrame类代码

package objtalk;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.channels.NonWritableChannelException;
import java.nio.channels.SelectableChannel;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.lang.model.element.Element;
import javax.swing.AbstractListModel;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.event.AncestorListener;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;


public class SocketFrame extends JFrame {
        private JTextPane jtpMes = new JTextPane();//消息框
        private StyledDocument contentDoc = jtpMes.getStyledDocument();//取出文本(),属性定义(sas的容器)
        private JScrollPane jspMes = new JScrollPane(jtpMes);//为消息框添加滑动框
        private JButton btnSend = new JButton("Send");
        private JButton btnConnect = new JButton("Connect");
        private JButton btnSelectimg = new JButton("img");
        private JTextPane jtpNewMes = new JTextPane();//消息框(可以显示图片和文字)
        private JScrollPane jspNewMes = new JScrollPane(jtpNewMes);//为群聊框添加滑动框
        private StyledDocument sendDoc = jtpNewMes.getStyledDocument();
        private JPanel panSend = new JPanel();
        JPanel btnPan = new JPanel();
        private Font font = new Font("宋体", Font.PLAIN, 20);
        private JList<String> listClient = new JList<>();
        private JScrollPane jspClientList = new JScrollPane(listClient);
        private Socket socket;
        private ObjectOutputStream out;
        private ReadThread reader;//读取消息线程

        public SocketFrame() {
                this.setSize(800, 600);
                this.setLocationRelativeTo(null);
                this.setDefaultCloseOperation(EXIT_ON_CLOSE);
                init();
                getContentPane().add(jspMes);
                getContentPane().add(panSend, BorderLayout.SOUTH);
                getContentPane().add(jspClientList, BorderLayout.EAST);

        }

        public void updateListClient(ArrayList list) {//跟新群聊用户信息
                listClient.setModel(new ClientListModel(list));
        }

        class ClientListModel extends AbstractListModel {//更新list信息
                ArrayList list;

                public ClientListModel(ArrayList list) {
                        super();
                        this.list = list;
                }

                @Override
                public Object getElementAt(int arg0) {
                        return list.get(arg0);
                }

                @Override
                public int getSize() {
                        return list.size();
                }
        }

        private void init() {
                panSend.setLayout(new BorderLayout());
                panSend.add(jspNewMes,BorderLayout.CENTER);
                panSend.add(btnPan,BorderLayout.EAST);
                btnPan.add(btnSend);
                btnPan.add(btnConnect);
                btnPan.add(btnSelectimg);
                jtpMes.setEditable(false);
                jtpMes.setFont(font);
                jtpNewMes.setFont(font);
                btnSend.addActionListener(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent arg0) {
                                String str = jtpNewMes.getText().trim();//得到文本
                                System.out.println(str);
                                if (str != null && str.length() > 0 && socket != null) {
                                        SocketAddress address = socket.getRemoteSocketAddress();//得到本地地址
                                        String ip = address.toString().substring(1,
                                        address.toString().indexOf(":") + 1);//获得ip
                                        SimpleAttributeSet sas = new SimpleAttributeSet();//容器存储消息体
                                        StyleConstants.setFontSize(sas,24);//设置字体
                                        try {
                                                /*senDoc消息内容会自动从输入消息框获取(绑定更新,50行57行代码实现),这里只是在消息前面添加ip(类似用户名)*/
                                                sendDoc.insertString(0, ip, sas);
                                               
                                        } catch (BadLocationException e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                        }
                                        MyMessage mes = new MyMessage(true,MyMessage.MES_TYPE_PLAIN);
                                        mes.setContent(sendDoc);
                                        sendMes(mes);//发送消息
                                        try {
                                                sendDoc.remove(0, sendDoc.getLength());//去除容器中的内容
                                        } catch (BadLocationException e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                        }
                                }
                        }
                });
                btnConnect.addActionListener(new ActionListener() {//连接服务器

                        @Override
                        public void actionPerformed(ActionEvent arg0) {
                                if(socket==null){
                                try {
                                        socket = new Socket("10.117.45.114", 12345);//具体ip自己设置
                                        reader = new ReadThread(socket);
                                        reader.start();
                                        out = new ObjectOutputStream(socket.getOutputStream());//创建消息输入流
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                                }
                        }
                });
               
                btnSelectimg.addActionListener(new ActionListener() {//选区本地图片存入容器
                       
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                // TODO Auto-generated method stub
                                JFileChooser fc = new JFileChooser("d:");//文件选择器
                                FileNameExtensionFilter filter = new FileNameExtensionFilter("JPG & GIF Image", "jpg","gif");//文件筛选器
                                fc.setFileFilter(filter);
                                int i = fc.showOpenDialog(SocketFrame.this);
                                if(i == JFileChooser.APPROVE_OPTION){
                                        try {
                                                Image img = ImageIO.read(fc.getSelectedFile());
                                                ImageIcon icon = new ImageIcon(img);
                                                SimpleAttributeSet sas = new SimpleAttributeSet();//容器
                                                StyleConstants.setIcon(sas, icon);//把图标放入sas容器
                                                sendDoc.insertString(sendDoc.getLength(), "icon", sas);//把sas插入文本格式,属性定义
                                        } catch (IOException e1) {
                                                // TODO Auto-generated catch block
                                                e1.printStackTrace();
                                        } catch (BadLocationException e1) {
                                                // TODO Auto-generated catch block
                                                e1.printStackTrace();
                                        }
                                }
                        }
                });
                this.addWindowListener(new WindowAdapter() {

                        @Override
                        public void windowClosing(WindowEvent arg0) {//关闭主界面后程序退出流关闭
                                if (out != null) {
                                        MyMessage mes = new MyMessage(true,MyMessage.MES_TYPE_PLAIN);
                                        //mes.setContent("quit");
                                        sendMes(mes);
                                        reader.stopRun();
                                }
                        }
                });
               
                listClient.addMouseListener(new MouseAdapter() {

                        @Override
                        public void mouseClicked(MouseEvent e) {
                                // TODO Auto-generated method stub
                                super.mouseClicked(e);
                                if(e.getClickCount()==2){//双击触发私聊
                                        new PrivateDialog(listClient.getSelectedValue().toString()).setVisible(true);
                                }
                        }
                       
                });
        }
       
        public void append(StyledDocument sd){
                int caretPosition = jtpMes.getStyledDocument().getLength();
                caretPosition+=sd.getLength();
                try {
                for(int i=0;i<sd.getLength();i++){
                        javax.swing.text.Element e = sd.getCharacterElement(i);
                        if(e.getName().equals("icon")){
                                contentDoc.insertString(contentDoc.getLength(), "icon", e.getAttributes());
                                i+=2;
                        }
                        else{
                                String s = sd.getText(i, 1);
                                contentDoc.insertString(contentDoc.getLength(), s, e.getAttributes());
                        }
                }
                        contentDoc.insertString(contentDoc.getLength(), "\n", null);
                } catch (BadLocationException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                jtpMes.setCaretPosition(caretPosition);
        }

        public void sendMes(MyMessage m) {
                if (out != null) {
                        try {
                                out.reset();//反复发送同一个内容不断改变的对象需要使用reset(此时为sendDoc)
                                out.writeObject(m);
                                out.flush();
                        } catch (IOException e) {
                                e.printStackTrace();
                        }
                }
        }

        class ReadThread extends Thread {
                Socket c;
                boolean flag = true;

                public ReadThread(Socket c) {
                        this.c = c;
                }

                @Override
                public void run() {
                        try {
                                ObjectInputStream in = new ObjectInputStream((c.getInputStream()));
                                MyMessage newMes = (MyMessage) in.readObject();
                                while (flag) {
                                        switch (newMes.getMesType()) {
                                        case MyMessage.MES_TYPE_PLAIN:
                                                append(newMes.getContent());//将得到的消息添加进聊天框
                                                break;
                                        case MyMessage.MES_TYPE_UPDATE_CLIENTLIST:
                                                updateListClient(newMes.getClientList());//更新聊天人信息
                                                break;
                                        }
                                        //将输入流和message对象初始化供下次使用
                                        in = new ObjectInputStream((c.getInputStream()));
                                        newMes = (MyMessage) in.readObject();
                                }
                        } catch (Exception e) {
                                e.printStackTrace();
                        }
                        }

                public void stopRun() {
                        flag = false;
                }
        }
       
        class PrivateDialog extends JDialog{//单独对话框
                private JTextPane jtpPriMes = new JTextPane();
                private JScrollPane jspPriMes = new JScrollPane(jtpPriMes);
                private JButton btnPriSend = new JButton("Send");
                private JButton btnselect = new JButton("select");
                private JPanel panFun = new JPanel();
                private String ip;
                public PrivateDialog(String ip) {
                        // TODO Auto-generated constructor stub
                        this.ip = ip;
                        this.setTitle(ip);
                        this.setSize(400, 300);
                        this.setLocationRelativeTo(null);
                        init();
                        this.add(panFun);
                }
                private void init() {
                        panFun.add(jtpPriMes);
                        panFun.add(btnPriSend);
                        panFun.add(btnselect);
                        btnPriSend.addActionListener(new ActionListener() {
                               
                                @Override
                                public void actionPerformed(ActionEvent e) {
                                        // TODO Auto-generated method stub
                                        String str  = jtpPriMes.getText().trim();
                                        if(str!=null&&str.length()>0&&socket!=null){
                                                MyMessage mes = new MyMessage(false,MyMessage.MES_TYPE_PLAIN);
                                                mes.setIp(ip);
                                                mes.setContent(jtpPriMes.getStyledDocument());
                                                sendMes(mes);
                                }
                        }
                        });
                       
                        btnselect.addActionListener(new ActionListener() {
                               
                                @Override
                                public void actionPerformed(ActionEvent e) {
                                        // TODO Auto-generated method stub
                                        JFileChooser fc = new JFileChooser("d:");
                                        FileNameExtensionFilter filter = new FileNameExtensionFilter("JPG & GIF Image", "jpg","gif");//文件筛选器
                                        fc.setFileFilter(filter);
                                        int i = fc.showOpenDialog(SocketFrame.this);
                                        if(i == JFileChooser.APPROVE_OPTION){
                                                try {
                                                        Image img = ImageIO.read(fc.getSelectedFile());
                                                        ImageIcon icon = new ImageIcon(img);
                                                        SimpleAttributeSet sas = new SimpleAttributeSet();//容器
                                                        StyleConstants.setIcon(sas, icon);//把图标放入sas容器
                                                        jtpPriMes.getStyledDocument().insertString(jtpPriMes.getStyledDocument().getLength(), "icon", sas);//把sas插入文本格式,属性定义
                                                } catch (IOException e1) {
                                                        // TODO Auto-generated catch block
                                                        e1.printStackTrace();
                                                } catch (BadLocationException e1) {
                                                        // TODO Auto-generated catch block
                                                        e1.printStackTrace();
                                                }
                                        }
                                }
                        });
                }
        }

}

ServerSocketTest代码

package objtalk;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;

import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

import org.omg.CORBA.SystemException;


public class ServerSocketTest {
        ServerSocket server;
        HashSet<Socket> clientSet = new HashSet<>();

        public ServerSocketTest() {
                try {
                        server = new ServerSocket(12345);
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }

        public void work() {
                int no = 0;//连接服务器的个数
                try {
                        while (true) {
                                Socket client = server.accept();
                                clientSet.add(client);
                                SendUpdateClientList();
                                no++;
                                new ClientThread(client, no).start();
                        }
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }

        public void SendUpdateClientList() {//发送用户变更的消息,用户退出和加入的监听
                        MyMessage mes = new MyMessage(true,MyMessage.MES_TYPE_UPDATE_CLIENTLIST);
                        mes.setClientList(getClientList());
                        massMes(mes);
        }

        public void massMes(MyMessage mes) {//群发消息
                Iterator<Socket> it = clientSet.iterator();
                while (it.hasNext()) {
                        sendMes(it.next(), mes);
                }
        }
       
        public void singleMes(MyMessage mes){//单发消息
                for(Socket s : clientSet){
                        if(s.getRemoteSocketAddress().toString().equals(mes.getIp())){//String判等必须用equals
                                sendMes(s, mes);
                                break;
                        }
                }
        }

        public void sendMes(Socket s, MyMessage mes) {
                ObjectOutputStream out;
                try {
                        out = new ObjectOutputStream(s.getOutputStream());
                        out.writeObject(mes);
                        out.flush();
                } catch (IOException e1) {
                        e1.printStackTrace();
                }
        }

        public ArrayList<String> getClientList() {
                ArrayList<String> list = null;
                if (clientSet.size() > 0) {
                        list = new ArrayList<String>();
                        Iterator<Socket> it = clientSet.iterator();
                        int index = 0;
                        while (it.hasNext()) {
                                list.add(it.next().getRemoteSocketAddress().toString());
                        }
                }
                return list;
        }

        class ClientThread extends Thread {
                Socket c;
                int no;

                public ClientThread(Socket c, int no) {
                        super();
                        this.c = c;
                        this.no = no;
                }

                @Override
                public void run() {
                        try (ObjectInputStream in = new ObjectInputStream((c.getInputStream()));) {
                                MyMessage newMes = (MyMessage) in.readObject();
                                while (newMes.getContent()!=null) {//不断接收发来的消息
                                        if(newMes.getisIfmass()==true){
                                        massMes(newMes);
                                        System.out.println(newMes.getContent().getText(0,newMes.getContent().getLength() ));
                                        }
                                        else{
                                                singleMes(newMes);
                                        }
                                        newMes = (MyMessage) in.readObject();
                                }
                        } catch (Exception e) {
                                e.printStackTrace();
                        } finally {
                                try {
                                        c.close();
                                } catch (IOException e) {
                                        e.printStackTrace();
                                }
                                clientSet.remove(c);//用户退出后
                                SendUpdateClientList();
                        }
                }
        }

        public static void main(String[] args) {
                new ServerSocketTest().work();
        }

}

四:使用方法:

开启ServerSocketTest类(打开服务器)
开启signUp类,注册,登录,连接,开始聊天(可以多开几个实现群聊)
五:项目github地址
https://github.com/Chaos1874/javaTalk
---------------------
【转载,仅作分享,侵删】
作者:Chaos1874
原文:https://blog.csdn.net/weixin_41467912/article/details/88605696
版权声明:本文为博主原创文章,转载请附上博文链接!


作者: 不二晨    时间: 2019-3-25 17:15
奈斯,感谢分享
作者: 1721121521    时间: 2019-3-26 10:12
当时我们老师就让我们做,现在想想惨不忍睹





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2