全部功能已实现 支持离线发消息
package regexp;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class regexp_ {
File file = new File("d:\\tmp\\text.txt");
static StringBuilder sb ;
public static void main(String[] args) throws IOException {
new regexp_().info();
}
public void info() throws IOException {
if(file.exists()){
sb = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String readLen = "";
while((readLen = bufferedReader.readLine())!=null){
sb.append(readLen);
}
Pattern pattern = Pattern.compile(" ");
Matcher matcher = pattern.matcher(sb.toString());
while(matcher.find()){
System.out.println("找到:" + matcher.group(0));
}
}
else{
System.out.println("文件不存在");
}
}
}
package QQ;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Scanner;
public class Interface implements Serializable{
private boolean loop = true;
private boolean subLoop = true;
private String select = "";
User user ;
public static void main(String[] args) {
new Interface().mainMenu();
}
public void mainMenu() {
while (loop) {
System.out.println("******欢迎登录网络通信系统******");
System.out.println("\t\t\t1.登录系统");
System.out.println("\t\t\t9.退出系统");
System.out.print("请输入您的选择:");
select = Utility.readString(1);
if ("1".equals(select)) {
System.out.print("请输入您的ID:");
String id = Utility.readString(50);
System.out.print("请输入您的密码");
String pwd = Utility.readString(20);
System.out.println();
if (UserClientService.checkUser(id, pwd)) {
user = new User(id,pwd);
subMenu();
} else {
System.out.println("用户不存在");
}
} else if ("9".equals(select)) {
loop = false;
System.exit(0);
} else {
System.out.println("输入错误");
}
}
}
public void subMenu() {
while (subLoop) {
System.out.println("********欢迎(用户" + user.getUserId() + ")*******");
System.out.println("********网络通信系统二级菜单********");
System.out.println("\t\t\t1.显示在线用户列表");
System.out.println("\t\t\t2.群发消息");
System.out.println("\t\t\t3.私聊消息");
System.out.println("\t\t\t4.发送文件");
System.out.println("\t\t\t9.退出当前帐号");
System.out.print("请输入您的选择:");
select = Utility.readString(1);
switch (select) {
case "1":
System.out.println("*******显示在线用户列表******");
UserClientService.toServerMessage(user.getUserId(),MessageType.MESSAGE_GET_ONLINE_FRIEND);
break;
case "2":
System.out.println("群发消息");
UserClientService.toServerMessage(user.getUserId(),MessageType.MESSAGE_ALL_SEND);
break;
case "3":
System.out.println("私聊消息");
UserClientService.toServerMessage(user.getUserId(), MessageType.MESSAGE_COMM_MES);
break;
case "4":
System.out.println("发送文件");
break;
case "9":
System.out.println("******帐号已退出******");
UserClientService.toServerMessage(user.getUserId(),MessageType.MESSAGE_CLIENT_EXIT);
subLoop = false;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package QQ;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Interface anInterface = new Interface();
anInterface.mainMenu();
System.out.println(new Scanner(System.in).next());
}
}
package QQ;
public class Main1 {
public static void main(String[] args) {
Interface anInterface = new Interface();
anInterface.mainMenu();
}
}
package QQ;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 管理客户端连接到服务器的
*/
public class ManageClientConnectServerThread {
//把多个线程放在hashmap中 key为用户id ,,value是一个线程
private static Map<String,ClientConnectServer> map = new HashMap<>();
public static Map<String, ClientConnectServer> getMap() {
return map;
}
public static void addClientConnectServerThread(String userId, ClientConnectServer client){
map.put(userId,client);
}
//还可以通过一个方法获得 线程
public static ClientConnectServer getClientConnectServerThread(String userId) {
return map.get(userId);
}
}
package QQ;
import java.util.HashMap;
import java.util.Map;
/**
* 用于管理服务器的线程
*/
public class ManageServerThread {
private static Map<String,ServerConnectClientThread> map = new HashMap<>();
//将对象传入到集合中
public static void addServerThread(String userId, ServerConnectClientThread s){
map.put(userId,s);
}
public static ServerConnectClientThread getServerConnectThread(String userId){
return map.get(userId);
}
public static Map<String, ServerConnectClientThread> getMap() {
return map;
}
}
package QQ;
import org.junit.jupiter.api.Test;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Message implements MessageType, Serializable {
private static final long SerialVersionUID = 1L;
private String Sender;
private String getter;
private String content;
private String sendTime;
private String mesType; //消息类型[可以在接口中定义]
public String getMesType() {
return mesType;
}
public void setMesType(String mesType) {
this.mesType = mesType;
}
public String getSender() {
return Sender;
}
public void setSender(String sender) {
Sender = sender;
}
public String getGetter() {
return getter;
}
public void setGetter(String getter) {
this.getter = getter;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getSendTime() {
return sendTime;
}
@Test
public void setSendTime() {
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = dtf.format(ldt);
this.sendTime = format;
// System.out.println(format);
}
}
package QQ;
/**
* 消息类型
*/
public interface MessageType {
//登录成功/失败
String MESSAGE_LOGIN_SUCCESS = "1";
String MESSAGE_LOGIN_FAIL = "2";
String MESSAGE_COMM_MES = "3"; //普通的信息包
String MESSAGE_GET_ONLINE_FRIEND = "4"; //获取当前在线用户
String MESSAGE_RET_ONLINE_FRIEND = "5";
String MESSAGE_CLIENT_EXIT = "6";
String MESSAGE_ALL_SEND = "7";
}
package QQ;
import java.util.HashMap;
public class OffLin {
private static HashMap<String,Message> OffMessage = new HashMap<>();
public static HashMap<String, Message> getOffMessage() {
return OffMessage;
}
public static Message getOffMessage(String user){
return OffMessage.get(user);
}
public static void setOffMessage(String user,Message mes){
OffMessage.put(user,mes);
}
}
package QQ;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class Server {
static User user;
ServerSocket serverSocket;
static ConcurrentHashMap<String,String> validUser;
public static void main(String[] args) {
new Server();
}
static{
validUser = new ConcurrentHashMap<String,String>();
validUser.put("100","123456");
validUser.put("200","123456");
validUser.put("李憬硕","123456");
validUser.put("赵鹏","123456");
validUser.put("秦利鑫","123456");
}
public Server() {
try {
serverSocket = new ServerSocket(8888);
System.out.println("已打开服务器");
System.out.println("服务器正在8888监听....");
//要一直与客户端监听
while (true) {
Socket socket = serverSocket.accept();
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
ObjectInputStream obInput = new ObjectInputStream(inputStream);
user = (User) obInput.readObject();
Message message = new Message();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
if (validUser.containsKey(user.getUserId())&&validUser.get(user.getUserId()).equals(user.getUserPwd())) {
//登录成功
message.setMesType(MessageType.MESSAGE_LOGIN_SUCCESS);
//创建线程 与 客户端保持连接
ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, user.getUserId());
serverConnectClientThread.start();
//将服务器线程放在 Map中
ManageServerThread.addServerThread(user.getUserId(),serverConnectClientThread);
objectOutputStream.writeObject(message);
} else {
//登录失败
message.setMesType(MessageType.MESSAGE_LOGIN_FAIL);
objectOutputStream.writeObject(message);
socket.close();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void displayAllUser(Socket socket,Message mes){
//System.out.println(ManageServerThread.getMap());
System.out.println("用户" + mes.getSender() + "正在获取全部在线列表");
Set<String> allUser = ManageServerThread.getMap().keySet();
Message message = new Message();
message.setMesType(MessageType.MESSAGE_RET_ONLINE_FRIEND);
StringBuffer sb = new StringBuffer();
for(String str:allUser){
sb.append(str+" ");
}
message.setContent(sb.toString());
message.setGetter(message.getSender());
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void allSend(Socket socket,Message mes){
Map<String, ServerConnectClientThread> map = ManageServerThread.getMap();
Set<String> user = map.keySet();
Message message = new Message();
message.setContent(mes.getContent());
message.setSendTime();
message.setSender(mes.getSender());
message.setMesType(MessageType.MESSAGE_ALL_SEND);
for(String u : user){
ServerConnectClientThread serverConnectClientThread = map.get(u);
Socket socket1 = serverConnectClientThread.getSocket();
if(socket1!=socket){
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket1.getOutputStream());
objectOutputStream.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void exitUser(Socket socket,Message mes){
Message message = new Message();
message.setMesType(MessageType.MESSAGE_CLIENT_EXIT);
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(message);
System.out.println("用户" + mes.getSender() + "已退出");
Map<String, ServerConnectClientThread> map = ManageServerThread.getMap();
map.remove(mes.getSender());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void sendMessage(Socket socket,Message mes){
Message message = new Message();
message.setMesType(MessageType.MESSAGE_COMM_MES);
try {
ObjectOutputStream r = new ObjectOutputStream(socket.getOutputStream());
message.setGetter(mes.getGetter());
message.setSender(mes.getSender());
message.setContent(mes.getContent());
message.setSendTime();
r.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
package QQ;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.Set;
/**
* 服务器与客户端保持 通信
*/
public class ServerConnectClientThread extends Thread{
//必须持有socket
private Socket socket;
private String UserId;
private boolean loop = true;
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
public void setLoop(boolean loop) {
this.loop = loop;
}
public ServerConnectClientThread(Socket socket, String userId) {
this.socket = socket;
UserId = userId;
}
@Override
public void run(){
Set<String> users = OffLin.getOffMessage().keySet();
for(String st : users){
if(st.equals(UserId)){
try {
//写入离线 操作
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(OffLin.getOffMessage().get(UserId));
} catch (IOException e) {
e.printStackTrace();
}
}
}
while(loop){
System.out.println("正在与"+UserId+"保持通信");
try {
//System.out.println("正在准备接收写入的对象");
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message) ois.readObject();
//读或写 从客户端来的信息
if(message.getMesType().equals(MessageType.MESSAGE_GET_ONLINE_FRIEND)){
Server.displayAllUser(socket,message);
}
else if(message.getMesType().equals(MessageType.MESSAGE_CLIENT_EXIT)){
Server.exitUser(socket,message);
loop = false;
break;
}
else if(message.getMesType().equals(MessageType.MESSAGE_COMM_MES)){
Map<String, ServerConnectClientThread> map = ManageServerThread.getMap();
if(!map.containsKey(message.getGetter())){
OffLin.setOffMessage(message.getGetter(),message);
return ;
}
ServerConnectClientThread serverConnectClientThread = map.get(message.getGetter());
Server.sendMessage(serverConnectClientThread.socket,message);
}
else if(message.getMesType().equals(MessageType.MESSAGE_ALL_SEND)){
Server.allSend(socket,message);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
package QQ;
/**
* 用于存储用户信息
*/
import java.io.Serializable;
public class User implements Serializable {
private static final long SerialVersionUID = 1L;
private String userId;
private String userPwd;
public User(){}
public User(String userId, String userPwd) {
this.userId = userId;
this.userPwd = userPwd;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
@Override
public String toString() {
return "User{" +
"userId='" + userId + '\'' +
", userPwd='" + userPwd + '\'' +
'}';
}
}
package QQ;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class UserClientService implements Serializable{
private static User user;
static Socket socket;
static boolean b = false;
public static boolean checkUser(String id, String pwd) {
// new Server().OpenServer();
user = new User(id,pwd);
Message re = null;
try {
socket = new Socket("127.0.0.2", 8888);
System.out.println("已连接服务器");
user = new User(id,pwd);
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
ObjectOutputStream objOutput = new ObjectOutputStream(outputStream);
objOutput.writeObject(user);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
try {
re = (Message) objectInputStream.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if(re.getMesType().equals(MessageType.MESSAGE_LOGIN_SUCCESS)){
//连接成功 那么需要创建一个线程和服务器连接
ClientConnectServer clientConnectServer = new ClientConnectServer(socket);
clientConnectServer.start();
b = true;
// 为了方便 管理我们需要把一个socket 放在 集合中
ManageClientConnectServerThread.addClientConnectServerThread(user.getUserId(),clientConnectServer);
}
else{
//如果登录失败,则关闭接口
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if(b){
return true;
}
else {
return false;
}
}
public static void allSend(Message mes){
System.out.println("\n来自" + mes.getSender() + "的消息 " + mes.getSendTime() + ":\n" + mes.getContent());
}
public static void displayAllUser(Message message){
String user[] = message.getContent().split(" ");
for(String str : user){
System.out.println("用户: " + str);
}
}
public static void sendMessage(Message message){
System.out.println("\n来自" + message.getSender() + "的消息" + message.getSendTime() + ":");
System.out.println(message.getContent());
}
public static void toServerMessage(String user,String mes){
ClientConnectServer clientConnectServerThread = ManageClientConnectServerThread.getClientConnectServerThread(user);
Message message = new Message();
message.setMesType(mes);
message.setSender(user);
message.setSendTime();
if(mes.equals(MessageType.MESSAGE_COMM_MES)){
System.out.println("请输入您要要发送的消息人");
message.setGetter(new Scanner(System.in).next());
System.out.println("请输入您要发送的内容");
message.setContent(new Scanner(System.in).next());
message.setSendTime();
}
if(mes.equals(MessageType.MESSAGE_ALL_SEND)){
System.out.print("请输入您要群发的消息:");
message.setContent(new Scanner(System.in).next());
}
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(clientConnectServerThread.socket.getOutputStream());
objectOutputStream.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
package QQ;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
public class UserServerService {
}
package QQ;
/**
* 工具类的作用:
* 处理各种情况的用户输入,并且能够按照程序员的需求,得到用户的控制台输入。
*/
import java.util.*;
public class Utility {
//静态属性
private static Scanner scanner = new Scanner(System.in);
/**
* 功能:读取键盘输入的一个菜单选项,值:1——5的范围
*
* @return 1——5
*/
public static char readMenuSelection() {
char c;
for (; ; ) {
String str = readKeyBoard(1, false);//包含一个字符的字符串
c = str.charAt(0);//将字符串转换成字符char类型
if (c != '1' && c != '2' &&
c != '3' && c != '4' && c != '5') {
System.out.print("选择错误,请重新输入:");
} else break;
}
return c;
}
/**
* 功能:读取键盘输入的一个字符
*
* @return 一个字符
*/
public static char readChar() {
String str = readKeyBoard(1, false);//就是一个字符
return str.charAt(0);
}
/**
* 功能:读取键盘输入的一个字符,如果直接按回车,则返回指定的默认值;否则返回输入的那个字符
*
* @param defaultValue 指定的默认值
* @return 默认值或输入的字符
*/
public static char readChar(char defaultValue) {
String str = readKeyBoard(1, true);//要么是空字符串,要么是一个字符
return (str.length() == 0) ? defaultValue : str.charAt(0);
}
/**
* 功能:读取键盘输入的整型,长度小于2位
*
* @return 整数
*/
public static int readInt() {
int n;
for (; ; ) {
String str = readKeyBoard(10, false);//一个整数,长度<=10位
try {
n = Integer.parseInt(str);//将字符串转换成整数
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
* 功能:读取键盘输入的 整数或默认值,如果直接回车,则返回默认值,否则返回输入的整数
*
* @param defaultValue 指定的默认值
* @return 整数或默认值
*/
public static int readInt(int defaultValue) {
int n;
for (; ; ) {
String str = readKeyBoard(10, true);
if (str.equals("")) {
return defaultValue;
}
//异常处理...
try {
n = Integer.parseInt(str);
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
* 功能:读取键盘输入的指定长度的字符串
*
* @param limit 限制的长度
* @return 指定长度的字符串
*/
public static String readString(int limit) {
return readKeyBoard(limit, false);
}
/**
* 功能:读取键盘输入的指定长度的字符串或默认值,如果直接回车,返回默认值,否则返回字符串
*
* @param limit 限制的长度
* @param defaultValue 指定的默认值
* @return 指定长度的字符串
*/
public static String readString(int limit, String defaultValue) {
String str = readKeyBoard(limit, true);
return str.equals("") ? defaultValue : str;
}
/**
* 功能:读取键盘输入的确认选项,Y或N
* 将小的功能,封装到一个方法中.
*
* @return Y或N
*/
public static char readConfirmSelection() {
System.out.println("请输入你的选择(Y/N): 请小心选择");
char c;
for (; ; ) {//无限循环
//在这里,将接受到字符,转成了大写字母
//y => Y n=>N
String str = readKeyBoard(1, false).toUpperCase();
c = str.charAt(0);
if (c == 'Y' || c == 'N') {
break;
} else {
System.out.print("选择错误,请重新输入:");
}
}
return c;
}
/**
* 功能: 读取一个字符串
*
* @param limit 读取的长度
* @param blankReturn 如果为true ,表示 可以读空字符串。
* 如果为false表示 不能读空字符串。
* <p>
* 如果输入为空,或者输入大于limit的长度,就会提示重新输入。
* @return
*/
private static String readKeyBoard(int limit, boolean blankReturn) {
//定义了字符串
String line = "";
//scanner.hasNextLine() 判断有没有下一行
while (scanner.hasNextLine()) {
line = scanner.nextLine();//读取这一行
//如果line.length=0, 即用户没有输入任何内容,直接回车
if (line.length() == 0) {
if (blankReturn) return line;//如果blankReturn=true,可以返回空串
else continue; //如果blankReturn=false,不接受空串,必须输入内容
}
//如果用户输入的内容大于了 limit,就提示重写输入
//如果用户如的内容 >0 <= limit ,我就接受
if (line.length() < 1 || line.length() > limit) {
System.out.print("输入长度(不能大于" + limit + ")错误,请重新输入:");
continue;
}
break;
}
return line;
}
}
%%%