Java基于Socket实现聊天群聊敏感词汇过滤功能
Posted 吹灭读书灯 一身都是月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基于Socket实现聊天群聊敏感词汇过滤功能相关的知识,希望对你有一定的参考价值。
首先的话,这个代码主要是我很久以前写的,然后当时还有很多地方没有理解,现在再来看看这份代码,实在是觉得丑陋不堪,想改,但是是真的改都不好改了…
所以,写代码,规范真的很重要。
实现的功能:
- 用户私聊
- 群聊功能:进群退群,群发消息,查看群聊
- 查看自己的消息记录
- 通过文件流,设置敏感词汇过滤(这里还用到了字典树…)不过我还有点不熟练…
- 离线,退出登录
不足:
emmm,其实说到不足的地方实在是太多了。
首先功能并没有完全完善,尤其是群聊的功能(但是我觉得后面的功能实现了也意义不大了)
然后,写代码并不规范。
也没有用到Java面向对象的知识,只存放用户的昵称,没有设置密码什么的
还要设置个,当用户上线之后,再来发送缓存之中的数据。
数据没有保存起来,关闭程序之后,数据消失了…
最开始的时候,我还不怎么会使用集合,后面发现在集合中放List(其实就是对象嘛),可以存很多东西的…
总而言之就是,还是要多写代码的,同时要多学习知识啊!!!
开始上代码!
目录结构
我这里的话,把我这四个类都放在test1包下。
实在是,这里用到了很多if else…然后,我这里想调用对应的方法语句都是要先输入对应的中文前缀的,很麻烦…建议大家使用循环,然后每次提示用户输入对应的指令。
TCPServer
首先就是要先启动服务端,如果没有启动的话是会报错的!!!
package test1;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TCPServer {
public static void main(String[] args) {
TCPServer server = new TCPServer();
server.start();
}
/**
* 创建线程池来管理客户端的连接线程
* 避免系统资源过度浪费
*/
private ServerSocket serverSocket;
private ExecutorService exec;
/**
* 存放用户昵称,打印流
*/
private Map<String, PrintWriter> storeInfo;
/**
* 存放客户端之间私聊的信息
*/
private Map<String, LinkedList<String>> storeMessages;
/**
* 用户没有上线的消息【我这里没有实现】
*/
private Map<String, String> waitMessages;
/**
* 群 K:群名称,Value:人员的昵称集合
*/
Map<String, LinkedList<String>> aGroup = new LinkedHashMap<>();
public TCPServer() {//构造器
try {
serverSocket = new ServerSocket(9999);
storeInfo = new ConcurrentHashMap<String, PrintWriter>();
exec = Executors.newCachedThreadPool();//创建线程池
storeMessages = new ConcurrentHashMap<String, LinkedList<String>>();
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
try {
while (true) {
System.out.println("服务端等待客户端连接... ... ");
Socket socket = serverSocket.accept();//出现一个客户才会accept()
System.out.println("客户端:“" + socket.getInetAddress().getHostAddress() + "”连接成功! ");
//启动一个线程,由线程来处理客户端的请求,这样可以再次监听下一个客户端的连接
//每次都是一个服务端Socket跟一个客户端绑定。同时服务端开启监听客户端的请求输入流
exec.execute(new ListenerClient(socket)); //通过线程池来分配线程 监听客户机 出现一个客户,就新建一个线程
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建内部类来获取昵称
* 监听客户端
* 该线程体用来处理给定的某一个客户端的消息,循环接收客户端发送 的每一个字符串,并输出到控制台
*/
class ListenerClient implements Runnable {
private Socket socket;
private String name;
public ListenerClient(Socket socket) {
this.socket = socket;
}
/**
* 管理昵称的方法
*/
private String getName() throws Exception {
//服务端的输入流读取客户端发送来的昵称输出流
BufferedReader bReader = new BufferedReader(
new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
//服务端将昵称验证结果通过自身的输出流发送给客户端
PrintWriter ipw = new PrintWriter(
new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
//读取客户端发来的昵称
while (true) {
String nameString = bReader.readLine();
if ((nameString.trim().length() == 0) || storeInfo.containsKey(nameString)) {
ipw.println("FAIL");//发送给客户端
} else {
ipw.println("OK");
return nameString;
}
}
}
/**
* 监听方法
* 通过客户端的Socket获取客户端的输出流,用来将消息发送给客户端
*/
@Override
public void run() {
try {
PrintWriter pw = new PrintWriter(
new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
name = getName();
putIn(name, pw, storeInfo);//将客户昵称和服务端所说的内容存入共享集合HashMap-storeInfo中
Thread.sleep(100);
// 服务端通知所有客户端,某用户上线(是群发的)
sendToAll("[系统通知] “" + name + "”已上线");
System.out.println("[系统通知] “" + name + "”已上线");
/* 读取客户端
* 通过客户端的Socket获取输入流读取客户端发送来的信息
*/
BufferedReader bReader = new BufferedReader(
new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
String msgString = null;//用msgString来获取客户端的输入
while ((msgString = bReader.readLine()) != null) {
LinkedList<String> msgList = storeMessages.get(name);
if (msgList == null) {
msgList = new LinkedList<String>();
}
// 检验是否为私聊(格式:@昵称:内容)
if (msgString.startsWith("@")) {
int index = msgString.indexOf(":");//@deng:xxx(冒号后面为内容)
if (index == -1) {
index = msgString.indexOf(":");
}
if (index >= 0) {
String theName = msgString.substring(1, index);//获取昵称
String info = msgString.substring(index + 1);//获取发送的内容
if (isBlank(info)) {
pw.println("[系统提示]:给好友发送的消息不能为空哦!");
}
info = "“" + name + "”:" + info;
//将私聊信息发送出去
boolean b = sendToSomeone(theName, isIllegal(info));
if (!b) {
//返回给原来的用户:消息发送失败,找不到人
pw.println("[系统提示]:未找到指定用户“" + theName + "“,消息发送失败");
}
msgList.add(msgString);
storeMessages.put(name, msgList);
continue;
}
} else if (msgString.startsWith("新建群:") || msgString.startsWith("新建群:")) {
creatGroup(msgString, name);
continue;
} else if (msgString.contains("群邀请:") || msgString.contains("群邀请:")) {
groupInvite(msgString, name);
continue;
} else if (msgString.startsWith("退群:") || msgString.startsWith("退群:")) {
String groupName = msgString.substring(3);
exitGroup(groupName, name);
continue;
} else if (msgString.startsWith("我想进群:") || msgString.startsWith("我想进群:") ) {
String groupName = msgString.substring(5);
acceptGroup(groupName, name);
continue;
} else if (msgString.contains("查看我加入的群聊")) {
pw.println("我加入的群聊有"+showMyGroups(name));
continue;
} else if ("查看消息记录".equals(msgString)) {
printOnlineUser(name);
printAllMessages(name);
continue;
} else if ("撤回最近一条消息".equals(msgString)) {
withdraw(name);
continue;
} else if (msgString.startsWith("群发给")) {//在群里发信息:群发给XXX:。。。1.判断是否在群XXX里 2.群发内容
int index = msgString.indexOf(':');
if (index == -1) {
index = msgString.indexOf(":");
}
String theGroupName = msgString.substring(3, index);//群聊名称
String theMsg = msgString.substring(index + 1);//内容
sendToGroup(theGroupName, isIllegal(theMsg), name);
continue;
}
if ("exit".equals(msgString)) {//手动退出程序
remove(name);
sendToAll("[系统通知] “" + name + "”已经手动下线了。");// 通知所有客户端,某某客户已经下线
}
//否则:(自己乱发消息) 遍历所有输出流,将该客户端发送的信息转发给所有客户端
System.out.println(name + ":" + isIllegal(msgString));
sendToSomeone(name, isIllegal(msgString));
msgList.add(msgString);
storeMessages.put(name, msgList);
}
} catch (Exception e) {
// e.printStackTrace();
} finally {
remove(name);
sendToAll("[系统通知] “" + name + "”已经下线了。");// 通知所有客户端,某某客户已经下线
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private boolean isBlank(String msg) {
return msg == null || "".equals(msg.trim());
}
private void putIn(String name, PrintWriter value, Map<String, PrintWriter> store) {
synchronized (this) {
store.put(name, value);
}
}
/**
* 将给定的输出流从共享集合中删除
*/
private synchronized void remove(String key) {
storeInfo.remove(key);
System.out.println("系统当前在线人数为:" + storeInfo.size());
}
/**
* 将给定的消息转发给所有客户端(群发)
*/
private synchronized void sendToAll(String message) {
for (PrintWriter everyone : storeInfo.values()) {
everyone.println(message);
}
}
/**
* 群发信息
*
* @param groupName 群聊名称
* @param message 群发的内容
* @param username 发信息的人
*/
private synchronized void sendToGroup(String groupName, String message, String username) {
LinkedList<String> nickNameList = aGroup.get(groupName);
if (nickNameList == null) {
sendToSomeone(username, "未找到指定的群:" + groupName);
} else {
for (String name : nickNameList) {
sendToSomeone(name, "【"+groupName + "】群的“" + username + "”说" + message);
}
}
}
/**
* 将给定的消息转发给私聊的客户端
*/
private synchronized boolean sendToSomeone(String name, String message) {//每一个名字对应一个只给它发送信息的PrintWriter
PrintWriter pw = storeInfo.get(name); //将对应客户端的聊天信息取出作为私聊内容发送出去(相当于只发给指定的name的)
if (pw != null) {
pw.println(message);
return true;
}
return false;
}
private static final SensitiveFilter sensitiveFilter = new SensitiveFilter();
/**
* 检测从服务端读入的信息是否合法-->读取 不含敏感信息
* 否侧把敏感词汇进行过滤
*/
private synchronized String isIllegal(String message) {
String msg = sensitiveFilter.filter(message);
if (msg == null) {
return "[系统提示]:消息为空,发送失败了";
}
return msg;
}
private synchronized void creatGroup(String msgString, String hostname) {
String groupName = msgString.substring(4);
//1.建立Map,添加群主及群聊名称
LinkedList<String> nickNameList = new LinkedList<>();
nickNameList.add(hostname)node.js + socket.io 聊天群聊系统