Java基于Socket实现聊天、群聊、敏感词汇过滤功能

首先的话,这个代码主要是我很久以前写的,然后当时还有很多地方没有理解,现在再来看看这份代码,实在是觉得丑陋不堪,想改,但是是真的改都不好改了…
所以,写代码,规范真的很重要。

实现的功能:

  1. 用户私聊
  2. 群聊功能:进群退群,群发消息,查看群聊
  3. 查看自己的消息记录
  4. 通过文件流,设置敏感词汇过滤(这里还用到了字典树…)不过我还有点不熟练…
  5. 离线,退出登录

不足:
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);
        aGroup.put(groupName, nickNameList);
        //2.发送信息给客户端,问要邀请谁
        sendToSomeone(hostname, "你的【" + groupName + "】群聊创建成功!您可以邀请人了");
        System.out.println("“" + hostname + "”新建了【" + groupName + "】群聊");
        //3.群主发信息邀请其他成员
    }

    private synchronized void groupInvite(String msgString, String hostname) {
        //"xx群邀请:昵称"
        int locate = msgString.indexOf("群邀请:");
        String subString = msgString.substring(locate + 4);//获取昵称
        String groupname = msgString.substring(0, locate);//群聊名称
        //3.2检查是哪位成员	(找key)
        Set<String> names = storeInfo.keySet();
        for (String needName : names) {
            if (needName.equals(subString)) {
                sendToSomeone(needName, "群主“" + hostname + "”邀请你加入【" + groupname + "】 群聊");
                sendToSomeone(hostname, "群邀请信息发送成功,等待“" + needName + "”回应");
                return;
            }
        }
        //没有找到成员
        sendToSomeone(hostname, "对不起,没有找到“ " + subString + "”成员,请重试。");
    }

    /**
     * 例如:我想进群:(群)
     *
     * @param groupName 进群语句
     * @param aName     发送语句人名称
     * @return true说明包含了进群 or 退群指令
     */
    private synchronized void acceptGroup(String groupName, String aName) {
        //遍历已知的群聊
        String hostname = null;
        LinkedList<String> nickList = aGroup.get(groupName);
        if (nickList == null) {
            sendToSomeone(aName, "进群失败,您输入的群名称无效!");
        } else {
            //进群,并通知群里所有的人
            nickList.add(aName);
            aGroup.put(groupName, nickList);
            for (String s : nickList) {
                sendToSomeone(s, "[系统消息]:刚刚“" + aName + "”已经加入群【" + groupName + "】啦");
            }
        }
    }


    /**
     * 用户退群
     */
    private synchronized void exitGroup(String groupName, String aName) {
        LinkedList<String> nickNameList = aGroup.get(groupName);
        if (nickNameList == null) {
            sendToSomeone(aName, "退群失败,您输入的群名称无效!");
        } else {
            nickNameList.remove(aName);
            aGroup.put(groupName, nickNameList);
            sendToSomeone(aName, "您已经成功退群【"+groupName+"】了");
            sendToGroup(groupName, aName+"退群!", aName);
        }
    }

    /**
     * 显示我加入的群聊
     */
    private synchronized List<String> showMyGroups(String aName) {
        List<String> listGroup = new ArrayList<>();
        for (String group : aGroup.keySet()) {
            LinkedList<String> nickNameList = aGroup.get(group);
            if (nickNameList.contains(aName)) {
                listGroup.add(group);
            }
        }
        return listGroup;
    }

    public synchronized void printOnlineUser(String myName) {
        Set<String> set = storeInfo.keySet();
        StringBuilder sb = new StringBuilder().append("所有在线用户:{");
        for (String obj : set) {
            sb.append(obj).append(",");
        }
        sb.deleteCharAt(sb.length() - 1);
        sb.append("}");
        sendToSomeone(myName, sb.toString());
    }

    /**
     * 打印我之前发过的所有消息
     */
    public synchronized void printAllMessages(String name) {
        Set<String> set = storeMessages.keySet();
        String sb = "我之前发过的信息有:" + isIllegal(storeMessages.get(name).toString());
        sendToSomeone(name, sb);
    }

    /**
     * 消息的撤回  看需求,可以撤回最近的一条消息
     *
     * @param name
     */
    public synchronized void withdraw(String name) {
        LinkedList<String> list = storeMessages.get(name);
        if (list == null || list.isEmpty()){
            sendToSomeone(name, name + "现在还没有消息可以撤回");
            return;
        }
        String removeMsg = list.remove(list.size() - 1);
        storeMessages.put(name, list);
        sendToSomeone(name, name + "成功撤回最近的消息:" + removeMsg);
        System.out.println(name + "刚撤回了[" + removeMsg + "]消息");
    }

    public static void print() {
        System.out.println("|\t\t提示信息\t\t\t\t\t\t|");
        System.out.println("| 私聊:@xxx:。。。(内容)\t\t\t\t|");
        System.out.println("| 群聊:①新建群:xxx	②群邀请:XX群邀请:昵称	|");
        System.out.println("| ③同意进群:我想进群:XXX	④退群:退群:XXX	|");
        System.out.println("| 撤回最近一条消息 |");
        System.out.println("| 查看消息记录  ||  查看我加入的群聊 \t⑤群发信息:群发给XXX:。。。 |");
        System.out.println("|注:敏感词汇有:" + sensitiveFilter.getSensitiveWords().toString());
        System.out.println("| 退出登录用[exit]      |");
        System.out.println("+-----------------------------------------------+");
    }

}

TCPClient

这里的客户端,一边进行不断通过Scanner的输入消息,另一边,通过listenerServer方法不断监听服务端发送过来的消息,并进行打印在控制台。

补充:如何同时启动多个客户端:
在这里插入图片描述在这里插入图片描述

package test1;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class TCPClient {
    /**
     * 代表一个客户端
     */
    static private Socket clientSocket;

    public static void main(String[] args) throws IOException {
        TCPServer.print();
        clientSocket = new Socket("localhost", 9999);
        TCPClient client = new TCPClient();
        client.start();
    }

    public void start() {
        try {
            System.out.println("客户机创建成功!---已自动登录本机IP:" + clientSocket.getInetAddress().getHostAddress());
            Scanner scanner = new Scanner(System.in);
            //设置昵称
            setName(scanner);
            // ① 接收  服务器端发送过来的信息的线程启动
            ExecutorService exec = Executors.newCachedThreadPool();
            exec.execute(new listenerServer());//监听服务端的消息

            // ② 建立输出流,给服务端发送信息//字符流==>字节流;设立为true自动刷新缓冲区
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), StandardCharsets.UTF_8), true);

            while (true) {
                String msg = scanner.nextLine();
                if ("".equals(msg.trim())) {
                    System.out.println("[系统提示]:自己发送的消息不能为空");
                    continue;
                }
                //打印自己说的话
                pw.println(msg);
                if (msg.equals("exit")) {
                    System.out.println("您已经退出客户端程序");
                    clientSocket.shutdownOutput();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {//关闭Socket
            if (clientSocket != null) {
                try {
                    System.out.println("您已经下线");
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 设置昵称 并登录
     */
    private void setName(Scanner scan) throws Exception {
        String name;
        //创建输出流
        PrintWriter pw = new PrintWriter(
                new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true);
        //创建输入流
        BufferedReader br = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
        while (true) {
            System.out.println("请创建您的昵称(登录):");
            name = scan.nextLine();
            if ("".equals(name.trim())) {
                System.out.println("昵称不得为空");
            } else {
                pw.println(name);
                String pass = br.readLine();
                if (pass != null && (!"OK".equals(pass))) {     /*接收从br发送的输入中获取的信息       */
                    System.out.println("昵称已经被占用,请重新输入:");
                } else {
                    System.out.println("昵称“" + name + "”已设置成功,可以开始聊天了");
                    break;
                }
            }
        }

    }

    /**
     * 监听(在客户做其他的事情的时候这个也一直 在运行,就可以接受服务端传过来的信息)
     * 循环读取  -服务端- 发送过来的信息并输出到客户端的控制台
     * 接收信息,来一句打印一句
     */
    class listenerServer implements Runnable {
        @Override
        public void run() {
            try {
                BufferedReader br = new BufferedReader(//读取clientSocket的输入流并打印
                        new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8));
                String msgString;
                while ((msgString = br.readLine()) != null) {
                    System.out.println(msgString);
                }
            } catch (Exception e) {
                System.out.println("出现异常");
                e.printStackTrace();
            }
        }
    }

}

SensitiveFilter

实现过滤敏感词汇的功能:

注意这里的读取文件中的内容:

getResource方法: 查找具有给定名称的资源。 搜索与给定类相关联的资源的规则由类的定义类加载器实现。 此方法委托给此对象的类加载器。 如果此对象由引导类加载器加载,则该方法委托给ClassLoader.getSystemResource 。

String filePath = SensitiveFilter.class.getResource("sensitive-words.txt").getPath();

此时打印得到的filePath 就是文件的绝对路径了。然后再使用Reader进行读取:

BufferedReader reader = new BufferedReader(new FileReader(filePath));

package test1;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;


public class SensitiveFilter {
    /**
     * 替换符
     */
    private static final String REPLACEMENT = "***";

    /**
     * 根节点
     */
    private final TrieNode rootNode = new TrieNode();

    public static final ArrayList<String> sensitiveWordsList = new ArrayList<>();

    public SensitiveFilter() {
        try {
            String filePath = SensitiveFilter.class.getResource("sensitive-words.txt").getPath();
            BufferedReader reader = new BufferedReader(new FileReader(filePath));
            String keyword;
            while ((keyword = reader.readLine()) != null) {
                // 添加到前缀树
                this.addKeyword(keyword);
                sensitiveWordsList.add(keyword);
            }
        } catch (IOException e) {
            System.out.println("加载敏感词文件失败: " + e.getMessage());
        }
    }

    public ArrayList<String> getSensitiveWords() {
        return sensitiveWordsList;
    }

    /**
     * 将一个敏感词添加到前缀树中
     */
    private void addKeyword(String keyword) {
        TrieNode tempNode = rootNode;
        for (int i = 0; i < keyword.length(); i++) {
            char c = keyword.charAt(i);
            TrieNode subNode = tempNode.getSubNode(c);
            if (subNode == null) {
                // 初始化子节点
                subNode = new TrieNode();
                tempNode.addSubNode(c, subNode);
            }
            // 指向子节点,进入下一轮循环
            tempNode = subNode;
            // 设置结束标识
            if (i == keyword.length() - 1) {
                tempNode.setKeywordEnd(true);
            }
        }
    }

    /**
     * 过滤敏感词
     *
     * @param text 待过滤的文本
     * @return 过滤后的文本。如果源字符串是null或者为空,返回 null
     */
    public String filter(String text) {
        if (text == null || "".equals(text.trim())) {
            return null;
        }
        // 指针1
        TrieNode tempNode = rootNode;
        // 指针2
        int begin = 0;
        // 指针3
        int position = 0;
        // 结果
        StringBuilder sb = new StringBuilder();
        while (position < text.length()) {
            char c = text.charAt(position);
            // 跳过符号
            if (isSymbol(c)) {
                // 若指针1处于根节点,将此符号计入结果,让指针2向下走一步
                if (tempNode == rootNode) {
                    sb.append(c);
                    begin++;
                }
                // 无论符号在开头或中间,指针3都向下走一步
                position++;
                continue;
            }
            // 检查下级节点
            tempNode = tempNode.getSubNode(c);
            if (tempNode == null) {
                // 以begin开头的字符串不是敏感词
                sb.append(text.charAt(begin));
                // 进入下一个位置
                position = ++begin;
                // 重新指向根节点
                tempNode = rootNode;
            } else if (tempNode.isKeywordEnd()) {
                // 发现敏感词,将begin~position字符串替换掉
                sb.append(REPLACEMENT);
                // 进入下一个位置
                begin = ++position;
                // 重新指向根节点
                tempNode = rootNode;
            } else {
                // 检查下一个字符
                position++;
            }
        }
        // 将最后一批字符计入结果
        sb.append(text.substring(begin));
        return sb.toString();
    }

    /**
     * 判断是否为符号
     */
    private boolean isSymbol(Character c) {
        // 0x2E80~0x9FFF 是东亚文字范围
        return !isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
    }

    private boolean isAsciiAlphanumeric(Character ch) {
        return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9');
    }

    /**
     * 前缀树
     */
    private class TrieNode {
        /**
         * 关键词结束标识
         */
        private boolean isKeywordEnd = false;

        /**
         * 孩子节点(key是下级字符,value是下级节点)
         */
        private Map<Character, TrieNode> subNodes = new HashMap<>();

        public boolean isKeywordEnd() {
            return isKeywordEnd;
        }

        public void setKeywordEnd(boolean keywordEnd) {
            isKeywordEnd = keywordEnd;
        }

        /**
         * 添加子节点
         */
        public void addSubNode(Character c, TrieNode node) {
            subNodes.put(c, node);
        }

        // 获取子节点
        public TrieNode getSubNode(Character c) {
            return subNodes.get(c);
        }

    }

    public static void main(String[] args) throws Exception {
        String msg = "赌博交易违法啊 啊吸毒 啊啊吸毒开票嫖娼都是敏感词汇!!!";
        SensitiveFilter sensitiveFilter = new SensitiveFilter();
        String filter = sensitiveFilter.filter(msg);
        System.out.println(msg);
        System.out.println(filter);
    }
}

sensitive-words.txt

这个就是存放的敏感词汇了。
比如说我的:注意SensitiveFilter类会一行一行地读取这里面的敏感词!

在这里插入图片描述

拓展

最后的话,我还想到了使用springboot的websocket(实现页面的聊天以及消息推送),以前我也看过很多遍websocket的代码以及博客吧,但是吧,我每次懒,然后居然没有去自己去实现一遍啊啊啊。
在这里插入图片描述
想想就觉得傻。所以一定一定要去亲自做一遍,不然你永远也不知道自己会不会。
后面还有一个 是基于NIO的socket通信,我也想后面学习一下(❁´◡`❁)

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是一个简单的Java基于socket实现聊天功能的示例代码: 服务端: ```java import java.io.*; import java.net.*; public class ChatServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8888); System.out.println("Server started."); while (true) { Socket socket = serverSocket.accept(); System.out.println("Client connected: " + socket.getInetAddress()); // 创建一个新的线程来处理客户端的请求 Thread thread = new Thread(new ChatHandler(socket)); thread.start(); } } } class ChatHandler implements Runnable { private Socket socket; private BufferedReader in; private PrintWriter out; public ChatHandler(Socket socket) { this.socket = socket; } public void run() { try { in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); out.println("Welcome to the chat room."); while (true) { String message = in.readLine(); if (message == null) { break; } System.out.println("Received message: " + message); // 广播消息给其他客户端 broadcast(message); } } catch (IOException e) { System.out.println("Error handling client: " + e); } finally { try { socket.close(); } catch (IOException e) { System.out.println("Error closing client connection: " + e); } } } private void broadcast(String message) { for (ChatHandler handler : ChatServer.handlers) { if (handler != this) { handler.out.println(message); } } } } ``` 客户端: ```java import java.io.*; import java.net.*; public class ChatClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost", 8888); System.out.println("Connected to server."); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); // 接收服务端的欢迎消息 String message = in.readLine(); System.out.println(message); BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); while (true) { String input = console.readLine(); out.println(input); } } } ``` 以上代码只实现了一对一的聊天,如果想要实现多人聊天,可以在服务端维护一个聊天室成员列表,然后在广播消息时,只将消息发送给聊天室成员。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值