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对象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();}}
四:使用方法:
- 开启ServerSocketTest类(打开服务器)
- 开启signUp类,注册,登录,连接,开始聊天(可以多开几个实现群聊)
五:项目github地址
https://github.com/Chaos1874/javaTalk
java聊天室群聊及私聊实现!相关推荐
- TCP多人聊天程序Java实现(群聊,私聊,在线用户,踢出用户)
本程序在程序 https://blog.csdn.net/joffy/article/details/18079331 的基础是上添加了私聊,踢出用户两个功能. 由客户端和服务器端构成程序,程序借助J ...
- Java WebSocket实现网络聊天室(群聊+私聊)
WebChat聊天室 2018.02.26 源码地址早就贴了呀, 留邮箱不如自己下载 项目地址: https://github.com/Amayadream/WebChat 2017.01.11更新 ...
- java仿QQ聊天室群聊(快速写一个简易QQ)
[mie haha的博客]转载请注明出处(万分感谢!): https://blog.csdn.net/qq_40315080/article/details/83052689 用java写聊天室实现群 ...
- java仿qq群聊_[转载]仿QQ聊天室群聊的练习心得
javase的学习即将告一段落,作为最后的一个项目练习,仿聊天室的程序编写让我很是头疼了一阵子.说起来还是自己java基础不牢的缘故导致的,虽然整体框架都已经很清晰了但是实际编写过程中却依然磕磕绊绊, ...
- BIO聊天室(群聊+私聊)
功能:群聊+私发+上线提醒+下线提醒+查询在线用户 文件 Utils FinalValue Message Server Client Receive Send Utils package morem ...
- 当年的聊天室,今天的我(java实现聊天室群聊功能)
预备小知识连接: 小小聊天室,慢慢的回忆啊!(TCP 通信实现) 先看效果 主要可以分为三个层:服务端层,客户端层,还有就是工具层: 服务断层:包括接收数据,以及转发数据(数据输出输入流): 客户端层 ...
- PHP+AJAX高性能聊天室(群聊+私聊)
无需服务端 Anlin_chat 一个多功能免费开源的网页聊天室,基于php+mysql+js运行 无需服务端,高效+极快的运行速度 (超高安全性)支持分类帖子推送兼容QQ内置,微信内置,Firefo ...
- Netty中实现多客户端连接与通信-以实现聊天室群聊功能为例(附代码下载)
场景 Netty的Socket编程详解-搭建服务端与客户端并进行数据传输: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1086 ...
- springboot和netty整合的聊天室--群聊
一.创建项目 file-new-project-spring initializr-next 然后 添加这两个依赖 二.代码 DemoApplication package com.example.d ...
- Netty+Android搭建一个简易聊天室(实现群聊和私聊)
零,前言 JRBM项目中无论是好友私聊,公开聊天室,还是比赛平台都需要用到长连接,之前没有接触过网络通信等知识,更别说框架了,因此直接上手netty确实有些困难,在前期主要是在b站上看(https:/ ...
最新文章
- select weui 动态加载数据_weui中的picker使用js进行动态绑定数据问题
- Node.js 博客实例(三)添加文件上传功能
- 小程序 input自动换行_直播 | 最实用的微信小程序自动化测试技术独家揭秘
- 工业交换机的定义和应用
- 全栈深度学习第3期: 怎样科学管理实验数据?
- ROS(kinetic)安装中的一些问题(已解决)
- B站疯传!堪称最强!一整套架构实战资料,白拿不谢!
- UVALive5379 UVA270 Lining Up【输入输出+水题】
- autosar架构详细介绍_干货|非常详细的 Ceph 介绍、原理、架构
- 大一c语言要学什么,c语言学习计划
- Excel在spring cloud项目中乱码
- php制作相册mp4,相册视频制作软件免费版
- 单片机A/D采样的原理
- android 开发者模式进入
- 解析ipa生成plist文件
- bmob php支付,个人开发者也能盈利!Bmob支付SDK使用实例
- 雨听 | 英语学习笔记(八)~作文范文:公务员考试的热潮
- 淘宝商品SKU接口、desc信息、淘宝商品详情API
- 磁饱和的产生原因和影响;磁化强度H和磁感应强度B
- 信息论的应用例子:数据压缩与信息熵、为什么K线这种技术指标没用了?