当前位置:

首页 > 编程开发 > SpringBoot如何实现过滤敏感词

SpringBoot如何实现过滤敏感词

过滤敏感词1.创建一个储存要过滤的敏感词的文本文件首先创建一个文本文件储存要过滤的敏感词在下面的工具类中我们会读取这个文本文件,这里提前给出@PostConstruct//这个注解表示当容器实例化这个bean(服务启动的时候)之后在调用构造器之后这个方法会自动的调用publicvoidinit(){try(//读取写有“敏感词”的文件,getClass表示从程序编译之后的target/classes读配置文件,读之后是字节流//java7语法,在这里的句子最后会自动执行close语句InputStream

本文目录

    过滤敏感词

    SpringBoot如何实现过滤敏感词

    1. 创建一个储存要过滤的敏感词的文本文件

    首先创建一个文本文件储存要过滤的敏感词

    SpringBoot如何实现过滤敏感词

    在下面的工具类中我们会读取这个文本文件,这里提前给出

    @PostConstruct   // 这个注解表示当容器实例化这个bean(服务启动的时候)之后在调用构造器之后这个方法会自动的调用
    public void init(){
        try(
                // 读取写有“敏感词”的文件,getClass表示从程序编译之后的target/classes读配置文件,读之后是字节流
                // java7语法,在这里的句子最后会自动执行close语句
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
                // 字节流  ->   字符流  ->  缓冲流
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    
        ) {
            String keyword;
            // 从文件中一行一行读
            while ((keyword = reader.readLine()) != null){
                // 添加到前缀树
                this.addKeyword(keyword);
            }
        } catch (IOException e) {
            logger.error("加载敏感词文件失败: " + e.getMessage());
        }
    }

    2. 开发过滤敏感词的工具类

    开发过滤敏感词组件

    为了方便以后复用,我们把过滤敏感词写成一个工具类SensitiveFilter。

    @Component
    public class SensitiveFilter {
    
        private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);
    
        // 当检测到敏感词后我们要把敏感词替换成什么符号
        private static final String REPLACEMENT = "***";
    
        // 根节点
        private TrieNode rootNode = new TrieNode();
    
        @PostConstruct   // 这个注解表示当容器实例化这个bean(服务启动的时候)之后在调用构造器之后这个方法会自动的调用
        public void init(){
            try(
                    // 读取写有“敏感词”的文件,getClass表示从程序编译之后的target/classes读配置文件,读之后是字节流
                    // java7语法,在这里的句子最后会自动执行close语句
                    InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
                    // 字节流  ->   字符流  ->  缓冲流
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    
            ) {
                String keyword;
                // 从文件中一行一行读
                while ((keyword = reader.readLine()) != null){
                    // 添加到前缀树
                    this.addKeyword(keyword);
                }
            } catch (IOException e) {
                logger.error("加载敏感词文件失败: " + e.getMessage());
            }
        }
    
        // 将一个敏感词添加到前缀树中
        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为空,初始化子节点;subNode不为空,直接用就可以了
                    subNode = new TrieNode();
                    tempNode.addSubNode(c, subNode);
                }
                // 指针指向子节点,进入下一轮循环
                tempNode = subNode;
            }
            // 最后要设置结束标识
            tempNode.setKeywordEnd(true);
        }
    
        /**
         * 过滤敏感词
         * @param text 待过滤的文本
         * @return  过滤后的文本
         */
        public String filter(String text){
            if(StringUtils.isBlank(text)){
                // 待过滤的文本为空,直接返回null
                return null;
            }
            // 指针1,指向树
            TrieNode tempNode = rootNode;
            // 指针2,指向正在检测的字符串段的首
            int begin = 0;
            // 指针3,指向正在检测的字符串段的尾
            int position = 0;
            // 储存过滤后的文本
            StringBuilder sb = new StringBuilder();
            while (begin < text.length()){
                char c = text.charAt(position);
    
                // 跳过符号,比如 “开票”是敏感词 #开#票# 这个字符串中间的 '#' 应该跳过
                if(isSymbol(c)){
                    // 是特殊字符
                    // 若指针1处于根节点,将此符号计入结果,指针2、3向右走一步
                    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字符串替换掉,存 REPLACEMENT (里面是***)
                    sb.append(REPLACEMENT);
                    // 进入下一个位置
                    begin = ++position;
                    // 重新指向根节点
                    tempNode = rootNode;
                } else {
                    // 检查下一个字符
                    position++;
                }
            }
            return sb.toString();
        }
    
        // 判断是否为特殊符号,是则返回true,不是则返回false
        private boolean isSymbol(Character c){
            // CharUtils.isAsciiAlphanumeric(c)方法:a、b、1、2···返回true,特殊字符返回false
            // 0x2E80  ~  0x9FFF 是东亚的文字范围,东亚文字范围我们不认为是符号
            return  !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
        }
    
        // 前缀树
        private class TrieNode{
    
            // 关键词结束标识
            private boolean isKeywordEnd = false;
    
            // 当前节点的子节点(key是下级字符、value是下级节点)
            private Map 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);
            }
        }
    }

    SpringBoot如何实现过滤敏感词

    上面就是过滤敏感词工具类的全部代码,接下来我们来解释一下开发步骤

    开发过滤敏感词组件分为三步:

    1.定义前缀树(Tree)

    我们将定义前缀树写为SensitiveFilter工具类的内部类

    // 前缀树
    private class TrieNode{
    
        // 关键词结束标识
        private boolean isKeywordEnd = false;
    
        // 当前节点的子节点(key是下级字符、value是下级节点)
        private Map 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);
        }
    }

    SpringBoot如何实现过滤敏感词

    2.根据敏感词,初始化前缀树

    将敏感词添加到前缀树中

    // 将一个敏感词添加到前缀树中
    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为空,初始化子节点;subNode不为空,直接用就可以了
                subNode = new TrieNode();
                tempNode.addSubNode(c, subNode);
            }
            // 指针指向子节点,进入下一轮循环
            tempNode = subNode;
        }
        // 最后要设置结束标识
        tempNode.setKeywordEnd(true);
    }

    SpringBoot如何实现过滤敏感词

    3.编写过滤敏感词的方法

    如何过滤文本中的敏感词:

    SpringBoot如何实现过滤敏感词

    特殊符号怎么处理:

    SpringBoot如何实现过滤敏感词

    敏感词前缀树初始化完毕之后,过滤文本中的敏感词的算法应该如下:

    定义三个指针:

    • 指针1指向Tree树

    • 指针2指向待过滤字符串段的头

    • 指针3指向待过滤字符串段的尾

    /**
     * 过滤敏感词
     * @param text 待过滤的文本
     * @return  过滤后的文本
     */
    public String filter(String text){
        if(StringUtils.isBlank(text)){
            // 待过滤的文本为空,直接返回null
            return null;
        }
        // 指针1,指向树
        TrieNode tempNode = rootNode;
        // 指针2,指向正在检测的字符串段的首
        int begin = 0;
        // 指针3,指向正在检测的字符串段的尾
        int position = 0;
        // 储存过滤后的文本
        StringBuilder sb = new StringBuilder();
        while (begin < text.length()){
            char c = text.charAt(position);
    
            // 跳过符号,比如 “开票”是敏感词 #开#票# 这个字符串中间的 '#' 应该跳过
            if(isSymbol(c)){
                // 是特殊字符
                // 若指针1处于根节点,将此符号计入结果,指针2、3向右走一步
                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字符串替换掉,存 REPLACEMENT (里面是***)
                sb.append(REPLACEMENT);
                // 进入下一个位置
                begin = ++position;
                // 重新指向根节点
                tempNode = rootNode;
            } else {
                // 检查下一个字符
                position++;
            }
        }
        return sb.toString();
    }
    
    // 判断是否为特殊符号,是则返回true,不是则返回false
    private boolean isSymbol(Character c){
        // CharUtils.isAsciiAlphanumeric(c)方法:a、b、1、2···返回true,特殊字符返回false
        // 0x2E80  ~  0x9FFF 是东亚的文字范围,东亚文字范围我们不认为是符号
        return  !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
    }

    SpringBoot如何实现过滤敏感词

    最后:建议在测试类中测试一下

    SpringBoot如何实现过滤敏感词

    经测试,过滤敏感词的工具类开发完成,这个工具会在接下来的发布帖子的功能中用到。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    springBoot项目常用目录有哪些
    springBoot项目常用目录有哪些

    springBoot项目常用目录springBoot项目的目录结构及名规范介绍基于SpringBoot开发时的目录结构及命名规范,通过介绍能够为你解决,在实际项目中如何规划目录结构?如何命名目录更规范?各个目录分别代表什么含义?等三个问题。目录说明servicex//项目名|-admin-ui//管理服务前端代码(一般将UI和SERVICE放到一个工程中,便于管理)|-servicex-auth//模块1|-servicex-common//模块2|-servicex-gateway//模块3|-serv

    解析SpringBoot和SpringMVC之间的异同
    解析SpringBoot和SpringMVC之间的异同

    解析SpringBoot和SpringMVC之间的异同SpringBoot和SpringMVC是Java领域中非常重要的开发框架。虽然它们都属于Spring框架的一部分,但是在使用和功能上有一些明显的区别。本文将对SpringBoot和SpringMVC进行比较,解析它们之间的异同。首先,让我们来了解一下SpringBoot。SpringBo

    探索SpringCloud和SpringBoot在微服务领域的不同应用方式
    探索SpringCloud和SpringBoot在微服务领域的不同应用方式

    近年来,随着云计算和分布式架构的兴起,微服务架构的应用越来越广泛。而SpringCloud和SpringBoot作为Java开发中的两个重要框架,对于微服务的实现起到了重要的作用。然而,很多人对于它们在微服务领域的不同应用方式还存在一定的疑惑。本文将从不同的角度探索SpringCloud和SpringBoot在微服务中的应用方式。首先,我们来了解一下Spri

    SpringBoot和SpringMVC有何区别?
    SpringBoot和SpringMVC有何区别?

    SpringBoot与SpringMVC的不同之处在哪里?SpringBoot和SpringMVC是两个非常流行的Java开发框架,用于构建Web应用程序。尽管它们经常分别被使用,但它们之间的不同之处也是很明显的。首先,SpringBoot可以被看作是一个Spring框架的扩展或者增强版。它旨在简化Spring应用程序的初始化和配置过程,以帮助开发人

    比较SpringBoot和SpringMVC的异同
    比较SpringBoot和SpringMVC的异同

    SpringBoot和SpringMVC都是Java开发中常用的框架,但它们之间有一些明显的差异。本文将探究这两个框架的特点和用途,并对它们的差异进行比较。首先,我们来了解一下SpringBoot。SpringBoot是由Pivotal团队开发的,它旨在简化基于Spring框架的应用程序的创建和部署。它提供了一种快速、轻量级的方式来构建独立的、可执行

    SpringBoot与SpringMVC的不同点是什么?
    SpringBoot与SpringMVC的不同点是什么?

    SpringBoot和SpringMVC是Java开发中常用的两个框架,它们都是由Spring框架所提供的,但在功能和使用方式上有着一些区别。本文将分别介绍SpringBoot和SpringMVC的特点和区别。一、SpringBoot的特点:简化配置:SpringBoot通过约定优于配置的原则,大大简化了项目的配置过程。它可以自动配置项目所需要的参数,开发人

    比较和选择指南:SpringCloud与SpringBoot的功能比较
    比较和选择指南:SpringCloud与SpringBoot的功能比较

    SpringCloud和SpringBoot是目前Java领域中最热门的开源框架,它们分别提供了一套完善的微服务架构和快速构建应用程序的解决方案。本文将对它们的功能进行比较,并给出选择指南,以帮助读者了解它们的优势和适用场景。SpringBoot是一个用于开发Java应用程序的框架,它提供了一个简化的开发流程,集成了大量常用的功能和组件,减少了开发者的工作量

    SpringCloud与SpringBoot:分析它们之间的相似与不同
    SpringCloud与SpringBoot:分析它们之间的相似与不同

    深入剖析SpringCloud和SpringBoot的异同引言:在构建企业级应用程序时,Spring框架已经成为开发者们的首选。它提供了一种简单而强大的方式来构建独立于平台的应用程序。Spring框架由两个核心模块组成:SpringBoot和SpringCloud。虽然它们都可以帮助开发者快速搭建应用程序,但它们的目标和用途存在一些差异。本文将深入剖析Spr

    从架构角度看SpringCloud与SpringBoot的差异
    从架构角度看SpringCloud与SpringBoot的差异

    从架构角度看SpringCloud与SpringBoot的差异引言:在当今的互联网时代,构建分布式系统已经成为了一种必要的需求。而SpringBoot和SpringCloud正是为了满足这个需求而诞生的。尽管它们都是由Spring框架所提供的解决方案,但从架构角度来看,它们存在着一些重要的差异。本文将从架构的角度出发,对SpringBoot和SpringCl

    Java API 开发中使用 SpringBoot 的利弊分析
    Java API 开发中使用 SpringBoot 的利弊分析

    JavaAPI开发中使用SpringBoot的利弊分析随着互联网的快速发展和技术的不断更新迭代,Java技术在开发中的广泛应用引起了人们的重视。而SpringBoot作为一种微服务架构的解决方案,已经逐渐成为Java开发中的热门选择。那么,在JavaAPI开发中使用SpringBoot,到底有哪些利弊呢?下面来分析一下。利:简化开发

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。