项目演示视频
项目下载地址:后端+Java+JAVA聊天系统源码+练习使用-Java文档类资源-优快云文库
也可以关注我之后私信我留个邮箱留言要哪个源码,我会把源码
免费发送到你的邮箱。
简介
这是自学java写的第二个小项目,已经实现了基本聊天需要的功能。程序有一个服务器端,多个客户端。账号是在服务器端的静态代码块里定义的,测试的时候写了3个账号。
/*
HashMap没有处理线程安全,因此在多线程情况下是不安全的
ConcurrentHashMap 处理的线程安全,即线程同步处理。在多线程情况下是安全的
*/
// 创建一个集合,存放多个用户,如果是这些用户登录,就认为是登录合法的
private static ConcurrentHashMap<String, User> validUsers = new ConcurrentHashMap<>();
// 在静态代码块中,初始化validUsers
static {
validUsers.put("唐僧", new User("唐僧", "1"));
validUsers.put("孙悟空", new User("孙悟空", "1"));
validUsers.put("100", new User("100", "1"));
}
用到的java技术
- 项目框架设计
- java面向对象编程
- 网络编程
- 多线程
- I/O流
- Mysql/这里是使用集合充当内存数据库
程序功能介绍
1.获取在线用户列表
//向服务器端请求在线用户列表
public void onlineFriendList() {
//发送一个Message 类型MESSAGE_GET_ONLINE_FRIEND
Message message = new Message();
message.setMesType(MessageType.MESSAGE_GET_ONLINE_FRIEND);
message.setSender(user.getUserId());
//发送给服务器端
try {
//从管理线程的集合中,通过userId, 得到这个线程对象
ClientConnectServerThread ccst =
ManageClientConnectServerThread.getClientConnectServerThread(user.getUserId());
Socket socket = ccst.getSocket();
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);//发送一个Message对象,向服务端要求在线用户列表
} catch (IOException e) {
e.printStackTrace();
}
}
客户端主要代码
// 判断客户端发来的是什么类型的消息,然后进行一系列的操作
if (message.getMesType().equals(MessageType.MESSAGE_GET_ONLINE_FRIEND)) {
System.out.println(message.getSender() + "要在线用户列表");
String onlineUser = ManageClientThreads.getOnlineUser();
//返回message
//构建一个Message对象,返回给客户端
Message message2 = new Message();
message2.setMesType(MessageType.MESSAGE_RET_ONLINE_FRIEND);
message2.setContent(onlineUser);
message2.setSender(message.getSender());
//返回给客户端
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message2);
}
服务器端主要代码
简单来说就是客户端封装一个消息类发送给服务端,然后服务端进行遍历在线用户集合返回给客户端的操作。
2.群发消息
public void sendMessageToAll(String content, String senderId) {
//构建message
Message message = new Message();
//群发聊天类型
message.setMesType(MessageType.MESSAGE_TO_ALL_MES);
message.setSender(senderId);//设置发送者id
message.setContent(content);//设置发送内容
//发送时间设置到message对象
message.setSendTime(new Date().toString());
System.out.println("\n" + senderId + "对大家说:" + content);
try {
//发送给服务端
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread
.getClientConnectServerThread(senderId)
.getSocket().getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
客户端主要代码
if (message.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES)) {
//需要遍历 管理线程的集合 把所有的线程的socket得到,然后把message进行转发即可
HashMap<String, ServerConnectClientThread> hm = ManageClientThreads.getHm();
Iterator<String> iterator = hm.keySet().iterator();
while (iterator.hasNext()) {
//取出在线用户id
String onLineUserId = iterator.next().toString();
if (!onLineUserId.equals(message.getSender())) {
//进行转发message
ObjectOutputStream oos = new ObjectOutputStream
(hm.get(onLineUserId).getSocket().getOutputStream());
oos.writeObject(message);
}
}
}
服务端主要代码
服务器接收到发来的消息类型,进行判断,之后遍历管理线程的集合,把所有的线程的socket得到,然后把message进行转发即可
3.私聊消息
/**
* @param content 内容
* @param senderId 发送用户id
* @param getterId 接收用户id
*/
public void sendMessageToOne(String content, String senderId, String getterId) {
//构建message
Message message = new Message();
//普通聊天类型
message.setMesType(MessageType.MESSAGE_COMM_MES);
message.setSender(senderId);
message.setGetter(getterId);
message.setContent(content);
//发送时间设置到message对象
message.setSendTime(new Date().toString());
System.out.println(senderId + "对" + getterId + "说" + content);
try {
//发送给服务端
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread
.getClientConnectServerThread(senderId)
.getSocket().getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
客户端主要代码
if (message.getMesType().equals(MessageType.MESSAGE_COMM_MES)) {
//根据messgae获取getter id,让后在得到对应的线程
ServerConnectClientThread scct =
ManageClientThreads.getServerConnectClientThread(message.getGetter());
//得到对应socket的对象输出流。将message对象转发给指定的客户端
ObjectOutputStream oos = new ObjectOutputStream(scct.getSocket().getOutputStream());
//TODO 如果客户不在线可以保存到数据库,这样就可以实现离线留言
oos.writeObject(message);
服务器端主要代码
服务端获取到要私聊的对象线程,返回给客户端。
4.发送文件
/**
* @param src 文件源路径
* @param dest 文件传输目标路径
* @param senderId 文件发送者
* @param getterId 文件接收者
*/
public void sendFileToOne(String src, String dest, String senderId, String getterId) {
// 读取src文件 -->message
Message message = new Message();
message.setMesType(MessageType.MESSAGE_FILE_MES);
message.setSender(senderId);
message.setGetter(getterId);
message.setSrc(src);
message.setDest(dest);
// 需要将文件读取
FileInputStream fileInputStream = null;
byte[] fileBytes = new byte[(int) new File(src).length()];
try {
fileInputStream = new FileInputStream(src);
//将src文件读入到程序的字节数组
fileInputStream.read(fileBytes);
//将文件对应的字节数组设置message
message.setFileBytes(fileBytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//发送
try {
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread
.getClientConnectServerThread(senderId).getSocket().getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
//提示信息
System.out.println("\n" + senderId + "给" + getterId +
"发送文件:" + src + "到对方的电脑的目录" + dest);
}
}
客户端主要代码
if (message.getMesType().equals(MessageType.MESSAGE_FILE_MES)) {
// 根据getter id获取到对应的线程,将message对象转发
ObjectOutputStream oos = new ObjectOutputStream(ManageClientThreads
.getServerConnectClientThread(message.getGetter())
.getSocket().getOutputStream());
// 转发
oos.writeObject(message);
}
服务端主要代码
客户端将要发送的文件保存到一个·字节数组里,然后发送给服务端。
5.登出
public void logout() {
Message message = new Message();
message.setMesType(MessageType.MESSAGE_CLIENT_EXIT);
message.setSender(user.getUserId());
try {
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread
.getClientConnectServerThread(user.getUserId())
.getSocket().getOutputStream());
oos.writeObject(message);
System.out.println(user.getUserId() + "退出系统");
//结束进程
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
}
客户端主要代码
if (message.getMesType().equals(MessageType.MESSAGE_CLIENT_EXIT)) {
System.out.println(message.getSender() + "退出");
// 将这个客户端对应线程,从集合中删除
ManageClientThreads.removeServerConnectClientThread(message.getSender());
socket.close();
//退出循环,关闭线程
break;
}
服务端主要代码
本文介绍了使用Java实现的聊天系统,包括用户在线列表获取、群发消息、私聊、文件传输功能,以及用户登出操作。通过多线程和网络编程展示了如何构建一个简单的前后端交互应用。
2033

被折叠的 条评论
为什么被折叠?



