一,服务端搭建
1.Servce
package server;
import commen.model.group;
import commen.model.user;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class Servce {
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(10086);
} catch (IOException e) {
System.err.println("Could not listen on port: 10086.");
System.exit(1);
}
List<Socket> socketList=new ArrayList<>();
List<user>userList=new ArrayList<>();
// new Thread(new Outputall(socketList)).start();
//自旋
while (true){
System.out.println("Waiting for a client...");
Socket socket= null;
try {
socket = serverSocket.accept();
System.out.println("Client connected.");
//连接成功创建新线程
Thread thread=new Thread(new ServerThread(socket,socketList,userList));
thread.start();
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
}
}
}
2.连接成功的线程(接收登录/注册信息,并且操作数据库)
serverThread
package server;
import Tool.MD5Util;
import commen.model.group;
import commen.model.user;
import commen.messages.Message;
import commen.messages.MessageType;
import mysqlConnection.mysqlconnection;
import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import server.service.*;
public class ServerThread extends Thread {
public Socket socket;
private static List<Socket> socketList;
private static List<user> userList;
public ServerThread(Socket socket, List<Socket> socketList, List<user> userList) {
this.socket = socket;
this.socketList = socketList;
this.userList = userList;
}
public static List<user> getUserList() {
return userList;
}
public static List<Socket> getSocketList() {
return socketList;
}
//注册时创建随机账号
private static Set<String> generatedNumbers = new HashSet<>();
public static String generateUniqueNumber() {
while (true) {
// 生成 UUID
UUID uuid = UUID.randomUUID();
String uuidString = uuid.toString();
// 截取 UUID 的前一部分并去除 "-"
String uuidPart = uuidString.split("-")[0];
// 将字符转换为数字
long number = Long.parseLong(uuidPart, 16);
// 确保数字是 10 位并且唯一
String numberStr = String.valueOf(number);
if (numberStr.length() == 10&&uniqueCheck(numberStr)) {
generatedNumbers.add(numberStr); // 添加到已生成的数字集合中
return numberStr;
}
}
}
private static boolean uniqueCheck(String numberStr) {
// 这里可以是你的唯一性检查逻辑,例如检查数字是否已经存在于集合中
// 在这个简单示例中,我们假设所有生成的数字都是唯一的
return !generatedNumbers.contains(numberStr);
}
@Override
public void run() {
try {
//服务端接收信息
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//反序列化强转为String类型,提示信息
Message message = (Message) ois.readObject();
user users = new user();
//如果提示消息为注册消息
if (message.getMesType().equals(MessageType.login)) {
//调用创建账号的方法
String uniqueNumber = generateUniqueNumber();
System.out.println("Unique 10-digit number: " + uniqueNumber);
users.setAccount(uniqueNumber);
users.setUsername(message.getSender().getUsername());
users.setPassword(MD5Util.encrypt(message.getSender().getPassword()));
users.setEmail(message.getSender().getEmail());
System.out.println(message.getSender().getAccount());
System.out.println(message.getSender().getUsername());
System.out.println(message.getSender().getPassword());
System.out.println(message.getSender().getEmail());
if (users.getUsername() == null) {
mysqlconnection.flag = 0;
}
//添加user信息,如果重复,flag变为0
//调用操作数据库的方法
new mysqlconnection(users.getUsername(), users.getAccount(), users.getPassword(), users.getEmail()).add();
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
Message message1 = new Message();
if (mysqlconnection.flag == 0) {
message1.setMesType(MessageType.returnloginfail);
oos.writeObject(message1);
mysqlconnection.flag = 1;
} else {
message1.setMesType(MessageType.returnloginsuccess);
oos.writeObject(message1);
}
}
//如果提示消息为登录
else if (message.getMesType().equals(MessageType.registertip)) {
user stu = new user();
stu.setAccount(message.getSender().getAccount());
System.out.println(message.getSender().getAccount()+"sss");
stu.setPassword(MD5Util.encrypt(message.getSender().getPassword()));
//调用操作数据库的方法
user flag = new mysqlconnection(stu.getAccount(), stu.getPassword()).buildcontest();
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
Message message1 = new Message();
if (flag != null) {
stu = flag;
ServerConnectClientThread clientThread=ManageClientThread.getServerConnectClientThread(stu.getAccount());
if(clientThread!=null&&clientThread.getSocket()!=null) {
message1.setMesType(MessageType.returnregisterfail);
oos.writeObject(message1);//转发,如果客户不在线,保存到数据库
}
else{
System.out.println(stu.getAccount()+"mmm");
userList.add(stu);
message1.setMesType(MessageType.returnregistersuccess);
//调用操作数据库的方法
//得到该用户的群聊列表
message1.setGroupList(mysqlconnection.getGroupList(message.getSender()));
message1.setFriendlist(mysqlconnection.getfriendlist(stu));
message1.setUserList(userList);
stu.setExpression(mysqlconnection.getexpresion(stu.getAccount()));
message1.setGetter(stu);
message1.setUserList(userList);
oos.writeObject(message1);
socketList.add(socket);
// out.close();
ServerConnectClientThread serverConnectClientThread =
new ServerConnectClientThread(socket, stu, userList);
serverConnectClientThread.start();
ManageClientThread.addClientThread(stu.getAccount(), serverConnectClientThread);
clientThread2 clientThrea= new clientThread2();
clientThrea.start();
MangeClientThread2.addClientThread(stu.getAccount(),clientThrea);
for (user user1:message1.getFriendlist()) {
try {
Message message2 = new Message();
message2.setMesType(MessageType.MESS_RET_ONLINE_FRIEND);
message2.setSender(stu);
message2.setUserList(userList);
ServerConnectClientThread clientThread1=ManageClientThread.getServerConnectClientThread(user1.getAccount());
if(clientThread1!=null&&clientThread1.getSocket()!=null) {
System.out.println(user1.getAccount());
ObjectOutputStream oos1 = new ObjectOutputStream(clientThread1.getSocket().getOutputStream());
oos1.writeObject(message2);
//转发,如果客户不在线,保存到数据库
}
} catch (SocketException e) {
System.out.println(1);
} catch (IOException e) {
e.printStackTrace();
}
}}
} else {
message1.setMesType(MessageType.returnregisterfail);
oos.writeObject(message1);
}
}
} catch (IOException e) {
System.out.println("ServceThread输入/输出操作期间可能发生的异常");
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
System.out.println("ServceThread这个类在类路径中没有被找到");
throw new RuntimeException(e);
} catch (Exception e) {
System.out.println("ServceThread运行时出现异常");
throw new RuntimeException(e);
}
}
}
3.登录成功后开启新线程与客户端保持长连接(线程开启位置在上一段代码中哦)
public class ServerConnectClientThread extends Thread {
private Socket socket;
private user stu;
private List<user> userList;
public static Message messaged;
public ServerConnectClientThread(Socket socket, user stu, List<user> userList) {
this.socket = socket;
this.stu = stu;
this.userList = userList;
}
@Override
public void run() {
while (true) {
System.out.println("服务端与客户端" + stu.getUsername() + "保持联系,读取数据....");
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message) ois.readObject();
if (message.getMesType().equals(MessageType.MESS_CLIENT_EXIT)) {
}//根据消息类型执行不同操作。。。。。
}
}
}
4.管理线程2中只要又用户登陆成功后就开起新的线程(那我们如何区别这些线程的拥有者(连接的用户)是谁呢)答案就是管理线程
package server.service;
import java.util.HashMap;
import java.util.Iterator;
public class ManageClientThread {
private static HashMap<String,ServerConnectClientThread>hm=new HashMap<>();
//在2中有运用
public static void addClientThread(String account,ServerConnectClientThread serverConnectClientThread){
hm.put(account,serverConnectClientThread);
}
//根据用户的账号查找线程
public static ServerConnectClientThread getServerConnectClientThread(String account){
return hm.get(account);
}
//当用户退出时在列表中删除该线程
public static void removeServerConnectClientThread(String account){
hm.remove(account);
}
}
二、客户端
1,登录
JavaFX界面
JavaFX控制类
package com.example.view;
import Client.service.UserClientService;
import commen.model.user;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.scene.control.Alert;
import javafx.scene.control.TextField;
import java.io.IOException;
import java.net.URL;
public class start {
@FXML
private PasswordField password;
@FXML
private Button denglubutton;
@FXML
private ImageView dis;
@FXML
private ImageView is;
@FXML
private TextField dispassword;
@FXML
private Button findbutton;
@FXML
private Button lookpassword;
@FXML
private Button zhucebutton;
@FXML
private TextField account;
@FXML
private Button email;
@FXML
private void initialize() {
is.setVisible(false);
}
@FXML
void zhucebuttonAnAction(ActionEvent event) {
zhucebutton.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
//得到注册界面的upl
URL upl = getClass().getResource("dianji-zhuce.fxml");
Parent root = null;
try {
root = FXMLLoader.load(upl);//加载
} catch (IOException e) {
e.printStackTrace();
}
Scene scene=new Scene(root);
Stage stage=new Stage();
stage.setTitle("注册界面");
stage.initStyle(StageStyle.DECORATED);//该画面不能移动
stage.setScene(scene);
stage.show();
// 关闭登录界面
Stage stage1 = (Stage) zhucebutton.getScene().getWindow();
stage1.close();
}
});
}
@FXML
void denglubuttonOnAction(ActionEvent event) throws Exception {
String account = this.account.getText();
String password = this.password.getText();
user u = null;
//判断文本框内容是否为空
if (account == null || account.isEmpty() || password == null || password.isEmpty()) {
// 创建一个信息提醒框
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Information Dialog");
alert.setHeaderText(null);
alert.setContentText("没有填写关键信息,请仔细检查你的账号,密码");
// 显示提醒框并等待用户关闭
alert.showAndWait();
} else {
UserClientService userClientService=new UserClientService();
if (!userClientService.checkUser(account,password)) {
// 创建一个信息提醒框
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Information Dialog");
alert.setHeaderText(null);
alert.setContentText("登录失败");
// 显示提醒框并等待用户关闭
alert.showAndWait();
} else {
// 创建一个信息提醒框
// 创建一个信息提醒框
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Information Dialog");
alert.setHeaderText(null);
alert.setContentText("登录成功");
// 显示提醒框并等待用户关闭
alert.showAndWait();
Stage oldStage = (Stage) denglubutton.getScene().getWindow();
oldStage.close();
FXMLLoader fxmlLoader = new FXMLLoader(start.class.getResource("chatroom.fxml"));
Scene scene = new Scene(fxmlLoader.load());
Stage stage = new Stage();
// stage.initStyle(StageStyle.UNDECORATED);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
}
}
@FXML
void findbuttonOnAction(ActionEvent event) {
URL upl = getClass().getResource("findpassword.fxml");
Parent root = null;
try {
root = FXMLLoader.load(upl);//加载
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setTitle("注册界面");
stage.initStyle(StageStyle.DECORATED);//该画面不能移动
stage.setScene(scene);
stage.show();
// 关闭登录界面
Stage stage1 = (Stage) findbutton.getScene().getWindow();
stage1.close();
}
@FXML
void lookpasswordOnAction(ActionEvent event) {
dis.setVisible(!dis.isVisible());
is.setVisible(!is.isVisible());
String look = password.getText();
String look_second = dispassword.getText();
boolean isPasswordFieldVisible = password.isVisible();
password.setVisible(!isPasswordFieldVisible);
if(!isPasswordFieldVisible){
password.setText(look_second);
}
else {
dispassword.setText(look);
}
dispassword.setVisible(isPasswordFieldVisible);
}
@FXML
void inemail(ActionEvent event) {
email.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
//得到注册界面的upl
URL upl = getClass().getResource("inEmail.fxml");
Parent root = null;
try {
root = FXMLLoader.load(upl);//加载
} catch (IOException e) {
e.printStackTrace();
}
Scene scene=new Scene(root);
Stage stage=new Stage();
stage.setTitle("sss");
stage.initStyle(StageStyle.DECORATED);//该画面不能移动
stage.setScene(scene);
stage.show();
// 关闭登录界面
Stage stage1 = (Stage) email.getScene().getWindow();
stage1.close();
}
});
}
}
根据实参的不同运用不同的checkUser
我们现在来看一下checkUser吧
public class UserClientService {
private static user u = new user();
private Socket socket;
public user getU() {
return u;
}
public boolean checkUser(String account, String password) {
u.setAccount(account);
u.setPassword(password);
boolean b = false;
try {
Message message = new Message();
message.setMesType(MessageType.registertip);
message.setSender(u);
socket = new Socket("127.0.0.1", 10086);
//创建输出流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
System.out.println("登录请求已发送");
// 接收登录结果
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message1 = (Message) ois.readObject();
if (message1.getMesType().equals(MessageType.returnregisterfail)) {
b = false;
socket.close();
} else if (message1.getMesType().equals(MessageType.returnregistersuccess)) {
chatroom.allList=message1.getUserList();
chatroom.FriendList=message1.getFriendlist();
chatroom.groupList=message1.getGroupList();
u.setUsername(message1.getGetter().getUsername());
u.setEmail(message1.getGetter().getEmail());
u.setSignature(message1.getGetter().getSignature());
u.setBirthday(message1.getGetter().getBirthday());
u.setFemale(message1.getGetter().getFemale());
u.setBlood(message1.getGetter().getBlood());
u.setAvatar(message1.getGetter().getAvatar());
u.setExpression(message1.getGetter().getExpression());
b = true;
System.out.println(u.getUsername());
System.out.println(u.getAccount());
ClientConnectSeverThread clientConnectSeverThread =
new ClientConnectSeverThread(socket);
clientConnectSeverThread.start();
ManageClientConnectServerThread.addClientConnectServerThread(account, clientConnectSeverThread);
Thread thread=new Thread(new getMessageThread(message1));
thread.start();
Thread heartbeatThread = new Thread(() -> {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
Message message2=new Message();// 发送心跳信号
message2.setMesType(MessageType.HEARTBEAT);
message2.setSender(u);
ObjectOutputStream oos1 = new ObjectOutputStream
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
});
heartbeatThread.start();
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return b;
}
public boolean checkUser(String username,String password, String email) {
u.setUsername(username);
u.setPassword(password);
u.setEmail(email);
boolean b = false;
try {
Message message = new Message();
message.setMesType(MessageType.login);
message.setSender(u);
socket = new Socket("127.0.0.1", 10086);
//创建输出流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//序列化,并传输提示词和user对象
oos.writeObject(message);
System.out.println("注册请求已发送");
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message1 = (Message) ois.readObject();
if (message1.getMesType().equals(MessageType.returnloginfail)) {
b = false;
socket.close();
} else if (message1.getMesType().equals(MessageType.returnloginsuccess)) {
b = true;
if(message1.getGetter()!=null)
u.setAccount(message1.getGetter().getAccount());
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return b;
}
}
好了今天就到这,登录已经结束了,注册界面可以自己创作一个