java聊天室群聊及私聊实现!

一:业务逻辑

  1. 连接数据库,实现注册登录账号的功能
  2. 使用serverSocket接收并发送消息实现服务器功能
  3. 客户端使用socket与服务器交互

二:类设计及代码结构

  1. MyMessage类:该类主要用于封装发送的消息内容
  2. ServerSocketTest类:服务器段实现类
  3. signup类:通过数据库实现登录注册
  4. 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对象ipprivate 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或端口号/需要打开的databaseprivate boolean tag = false;//判断账号密码是否正确public signup() {// TODO Auto-generated constructor stubthis.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 blocke2.printStackTrace();}signin.addActionListener(new ActionListener() {@Overridepublic 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 blocke1.printStackTrace();}}}});signup.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubString 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 blocke1.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;}@Overridepublic Object getElementAt(int arg0) {return list.get(arg0);}@Overridepublic 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() {@Overridepublic 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);//获得ipSimpleAttributeSet sas = new SimpleAttributeSet();//容器存储消息体StyleConstants.setFontSize(sas,24);//设置字体try {/*senDoc消息内容会自动从输入消息框获取(绑定更新,50行57行代码实现),这里只是在消息前面添加ip(类似用户名)*/sendDoc.insertString(0, ip, sas);} catch (BadLocationException e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();}}}});btnConnect.addActionListener(new ActionListener() {//连接服务器@Overridepublic 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() {//选区本地图片存入容器@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubJFileChooser 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 blocke1.printStackTrace();} catch (BadLocationException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}}});this.addWindowListener(new WindowAdapter() {@Overridepublic 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() {@Overridepublic void mouseClicked(MouseEvent e) {// TODO Auto-generated method stubsuper.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 blocke.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;}@Overridepublic 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 stubthis.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() {@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubString 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() {@Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stubJFileChooser 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 blocke1.printStackTrace();} catch (BadLocationException e1) {// TODO Auto-generated catch blocke1.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判等必须用equalssendMes(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;}@Overridepublic 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();}}

四:使用方法:

  1. 开启ServerSocketTest类(打开服务器)
  2. 开启signUp类,注册,登录,连接,开始聊天(可以多开几个实现群聊)
    五:项目github地址
    https://github.com/Chaos1874/javaTalk

java聊天室群聊及私聊实现!相关推荐

  1. TCP多人聊天程序Java实现(群聊,私聊,在线用户,踢出用户)

    本程序在程序 https://blog.csdn.net/joffy/article/details/18079331 的基础是上添加了私聊,踢出用户两个功能. 由客户端和服务器端构成程序,程序借助J ...

  2. Java WebSocket实现网络聊天室(群聊+私聊)

    WebChat聊天室 2018.02.26 源码地址早就贴了呀, 留邮箱不如自己下载 项目地址: https://github.com/Amayadream/WebChat 2017.01.11更新 ...

  3. java仿QQ聊天室群聊(快速写一个简易QQ)

    [mie haha的博客]转载请注明出处(万分感谢!): https://blog.csdn.net/qq_40315080/article/details/83052689 用java写聊天室实现群 ...

  4. java仿qq群聊_[转载]仿QQ聊天室群聊的练习心得

    javase的学习即将告一段落,作为最后的一个项目练习,仿聊天室的程序编写让我很是头疼了一阵子.说起来还是自己java基础不牢的缘故导致的,虽然整体框架都已经很清晰了但是实际编写过程中却依然磕磕绊绊, ...

  5. BIO聊天室(群聊+私聊)

    功能:群聊+私发+上线提醒+下线提醒+查询在线用户 文件 Utils FinalValue Message Server Client Receive Send Utils package morem ...

  6. 当年的聊天室,今天的我(java实现聊天室群聊功能)

    预备小知识连接: 小小聊天室,慢慢的回忆啊!(TCP 通信实现) 先看效果 主要可以分为三个层:服务端层,客户端层,还有就是工具层: 服务断层:包括接收数据,以及转发数据(数据输出输入流): 客户端层 ...

  7. PHP+AJAX高性能聊天室(群聊+私聊)

    无需服务端 Anlin_chat 一个多功能免费开源的网页聊天室,基于php+mysql+js运行 无需服务端,高效+极快的运行速度 (超高安全性)支持分类帖子推送兼容QQ内置,微信内置,Firefo ...

  8. Netty中实现多客户端连接与通信-以实现聊天室群聊功能为例(附代码下载)

    场景 Netty的Socket编程详解-搭建服务端与客户端并进行数据传输: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1086 ...

  9. springboot和netty整合的聊天室--群聊

    一.创建项目 file-new-project-spring initializr-next 然后 添加这两个依赖 二.代码 DemoApplication package com.example.d ...

  10. Netty+Android搭建一个简易聊天室(实现群聊和私聊)

    零,前言 JRBM项目中无论是好友私聊,公开聊天室,还是比赛平台都需要用到长连接,之前没有接触过网络通信等知识,更别说框架了,因此直接上手netty确实有些困难,在前期主要是在b站上看(https:/ ...

最新文章

  1. select weui 动态加载数据_weui中的picker使用js进行动态绑定数据问题
  2. Node.js 博客实例(三)添加文件上传功能
  3. 小程序 input自动换行_直播 | 最实用的微信小程序自动化测试技术独家揭秘
  4. 工业交换机的定义和应用
  5. 全栈深度学习第3期: 怎样科学管理实验数据?
  6. ROS(kinetic)安装中的一些问题(已解决)
  7. B站疯传!堪称最强!一整套架构实战资料,白拿不谢!
  8. UVALive5379 UVA270 Lining Up【输入输出+水题】
  9. autosar架构详细介绍_干货|非常详细的 Ceph 介绍、原理、架构
  10. 大一c语言要学什么,c语言学习计划
  11. Excel在spring cloud项目中乱码
  12. php制作相册mp4,相册视频制作软件免费版
  13. 单片机A/D采样的原理
  14. android 开发者模式进入
  15. 解析ipa生成plist文件
  16. bmob php支付,个人开发者也能盈利!Bmob支付SDK使用实例
  17. 雨听 | 英语学习笔记(八)~作文范文:公务员考试的热潮
  18. 淘宝商品SKU接口、desc信息、淘宝商品详情API
  19. 磁饱和的产生原因和影响;磁化强度H和磁感应强度B
  20. 信息论的应用例子:数据压缩与信息熵、为什么K线这种技术指标没用了?

热门文章

  1. 电脑安装双系统教程,电脑安装两个系统
  2. isSelected() 的使用
  3. 创业感悟:低调务实是创业者最可贵的精神
  4. MySQL使用JDBC高级操作和事务
  5. App提交审核被拒的原因汇总
  6. 系统创建定时执行任务bat批处理删除指定N天前文件夹的文件
  7. 公有云-主流公有云介绍
  8. 计算机毕业设计ssm基于网络安全维护的机房设备管理19rya系统+程序+源码+lw+远程部署
  9. SRE Google运维解密——第二章Goolgle的生成环境介绍
  10. 基于JavaWeb的C2C网上购物平台系统设计