当前位置: 首页 > news >正文

网站是怎么屏蔽脏话的呢:简单学会SpringBoot项目敏感词、违规词过滤方案

一个社区最重要的就是交流氛围与审查违规,而这两者都少不了对于敏感词进行过滤的自动维护措施。基于这样的措施,我们才能基本保证用户在使用社区的过程中,不至于被敏感违规词汇包围,才能够正常的进行发布帖子和评论,享受美好的社区氛围。目前,对于 springboot 项目也有较为成熟的敏感词过滤方案。

文章目录

    • 敏感词过滤方案
      • 实现思路

敏感词过滤方案

本文将采用 Github 上 houbb 大神开源的 sensitive-word 工具包来进行敏感词过滤操作,它具备以下优秀特点:

  • 包含 6W+ 词库,且不断优化更新
  • 基于 fluent-api 实现,使用优雅简洁
  • 完美兼容 spring boot 项目
  • 支持自定义敏感词一对一替换成对应正常词汇
  • 支持敏感词的判断、返回、脱敏等常见操作
  • 支持全角半角互换
  • 支持英文大小写互换
  • 支持数字常见形式的互换
  • 支持中文繁简体互换
  • 支持英文常见形式的互换
  • 支持用户自定义敏感词和白名单
  • 支持数据的数据动态更新,实时生效

敏感词过滤效果如下:

image-20230322171239034

它不仅可以通过自定义替换词,也就是过滤后文本的 * 号可以随意更改,如果想要删去敏感词,替换词直接选为空即可,他还可以通过自定义对应词的替换词,比如说:五星红旗指定为国家旗帜,毛主席指定为教员,示例如下:

“五星红旗迎风飘扬,毛主席的画像屹立在广场前”。变为 “国家旗帜迎风飘扬,教员的画像屹立在广场前。”

实现思路

  • 实现 sensitive-word 的配置文件
  • 利用自定义的 SensitiveWordUtil 进行封装
  • 调用 SensitiveWordUtil 即可

XML导包模板:

<!-- 敏感词工具包 -->
<dependency><groupId>com.github.houbb</groupId><artifactId>sensitive-word</artifactId><version>0.2.1</version>
</dependency>

sensitive-word 配置是通过 SensitiveWordBs.newInstance() 进行配置的,它传回的是 SensitiveWordBs 对象,而不是默认的 SensitiveWordHelper 对象。配置类注意添加 @Configuration 注解

它的配置项如下:

序号方法说明默认值
1ignoreCase忽略大小写true
2ignoreWidth忽略半角圆角true
3ignoreNumStyle忽略数字的写法true
4ignoreChineseStyle忽略中文的书写格式true
5ignoreEnglishStyle忽略英文的书写格式true
6ignoreRepeat忽略重复词false
7enableNumCheck是否启用数字检测。true
8enableEmailCheck是有启用邮箱检测true
9enableUrlCheck是否启用链接检测true
10numCheckLen数字检测,自定义指定长度。8

在完成配置之前,我们可以先添加两个词库文本,作为自定义的敏感词库以及非敏感词库,第一个词库大家都理解,为什么还要定义非敏感词库呢?因为默认的 6w+ 敏感词中免不了存在部分在社区业务中不算过于敏感的词汇,想要予以保留,这样的话,我们就需要使用非敏感词库进行排除。当然,敏感词库不能够频繁更新以及初始化,会耗费过多的时间和性能。这两个词库放置在 resource 目录下,博主使用的是 jdk17 ,所以采用 NIO 进行文件读取,简洁高效。两个文件名称如下:

  • myAllowWords.txt:非敏感词库
  • mySensitiveWords.txt:敏感词库

要使 sensitive-word 配置上自定义两个词库内容,必须分别继承以下两个接口:

  • IWordDeny:敏感词继承方法
  • IWordAllow:非敏感词继承方法

不仅需要实现这两个接口,还要配置默认词库、自定义词库合并的词库,否则,如果在 SensitiveWordBs.newInstance() 直接配置继承方法,就只生效自定义词库。合并词库的方法为:WordDenys.chains(),默认词库分别为WordDenys.system()、WordAllows.system(),合并后词库分别赋值给 IWordDeny、IWordAllow

模板配置如下:

// 自定义敏感词
// 注意每一行为一个敏感词,单行不能只包括空格,否则,也会把空格识别为敏感词
public class MyWordDeny implements IWordDeny {@Overridepublic List<String> deny() {List<String> list = new ArrayList<String>();;try {Resource mySensitiveWords = new ClassPathResource("mySensitiveWords.txt");Path mySensitiveWordsPath = Paths.get(mySensitiveWords.getFile().getPath());list =  Files.readAllLines(mySensitiveWordsPath, StandardCharsets.UTF_8);} catch (IOException ioException) {logger.error("读取敏感词文件错误!"+ ioException.getMessage());}return list;}}// 自定义非敏感词
// 注意每一行为一个非敏感词,单行不能只包括空格,否则,也会把空格识别为非敏感词
public class MyWordAllow implements IWordAllow {@Overridepublic List<String> allow() {List<String> list = new ArrayList<String>();;try {Resource myAllowWords = new ClassPathResource("myAllowWords.txt");Path myAllowWordsPath = Paths.get(myAllowWords.getFile().getPath());list =  Files.readAllLines(myAllowWordsPath, StandardCharsets.UTF_8);} catch (IOException ioException) {logger.error("读取非敏感词文件错误!"+ ioException.getMessage());}return list;}}// 配置默认敏感词 + 自定义敏感词
IWordDeny wordDeny = WordDenys.chains(WordDenys.system(), new MyWordDeny());
// 配置默认非敏感词 + 自定义非敏感词
IWordAllow wordAllow = WordAllows.chains(WordAllows.system(), new MyWordAllow());

而自定义替换规则就必须继承并实现 ISensitiveWordReplace 接口其中的 replace() 方法。实现模板代码如下:

public class mySensitiveWordReplace implements ISensitiveWordReplace {@Overridepublic String replace(ISensitiveWordReplaceContext context) {String sensitiveWord = context.sensitiveWord();// 自定义不同的敏感词替换策略,可以从数据库等地方读取if("五星红旗".equals(sensitiveWord)) {return "国家旗帜";}if("毛主席".equals(sensitiveWord)) {return "教员";}// 其他默认使用 * 代替int wordLength = context.wordLength();return CharUtil.repeat('*', wordLength);}
}

最后就是通过 SensitiveWordBs.newInstance() 进行配置,模板代码如下:

@Bean
public SensitiveWordBs sensitiveWordBs(){return SensitiveWordBs.newInstance()// 忽略大小写.ignoreCase(true)// 忽略半角圆角.ignoreWidth(true)// 忽略数字的写法.ignoreNumStyle(true)// 忽略中文的书写格式:简繁体.ignoreChineseStyle(true)// 忽略英文的书写格式.ignoreEnglishStyle(true)// 忽略重复词.ignoreRepeat(false)// 是否启用数字检测.enableNumCheck(true)// 是否启用邮箱检测.enableEmailCheck(true)// 是否启用链接检测.enableUrlCheck(true)// 数字检测,自定义指定长度.numCheckLen(8)// 配置自定义敏感词.wordDeny(wordDeny)// 配置非自定义敏感词.wordAllow(wordAllow).init();
}

配置完成之后,我们就可以使用 SensitiveWordUtil 进行封装使用了,实现代码如下:

@Component
public class SensitiveWordUtil {@Autowiredprivate SensitiveWordBs sensitiveWordBs;// 刷新敏感词库与非敏感词库缓存public void refresh(){sensitiveWordBs.init();}// 判断是否含有敏感词public boolean contains(String text){return sensitiveWordBs.contains(text);}// 指定替换符进行替换敏感词public String replace(String text, char replaceChar){return sensitiveWordBs.replace(text,replaceChar);}// 使用默认替换符 * 进行替换敏感词public String replace(String text){return sensitiveWordBs.replace(text);}// 返回所有敏感词public List<String> findAll(String text){return sensitiveWordBs.findAll(text);}
}

调用就不用说明了吧,我们敏感词过滤的部分就完成了。放一下 API 文档

方法参数返回值说明
contains(String)待验证的字符串布尔值验证字符串是否包含敏感词
replace(String, ISensitiveWordReplace)使用指定的替换策略替换敏感词字符串返回脱敏后的字符串
replace(String, char)使用指定的 char 替换敏感词字符串返回脱敏后的字符串
replace(String)使用 * 替换敏感词字符串返回脱敏后的字符串
findAll(String)待验证的字符串字符串列表返回字符串中所有敏感词
findFirst(String)待验证的字符串字符串返回字符串中第一个敏感词
findAll(String, IWordResultHandler)IWordResultHandler 结果处理类字符串列表返回字符串中所有敏感词
findFirst(String, IWordResultHandler)IWordResultHandler 结果处理类字符串返回字符串中第一个敏感词

测试方法:

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class SensitiveTest {@Autowiredprivate SensitiveWordUtil sensitiveWordUtil;@Testpublic void utilTest02(){String result = sensitiveWordUtil.replace("法网恢恢 哇 nnd 复活");System.out.println(result);}
}

求关注点赞

相关文章:

网站是怎么屏蔽脏话的呢:简单学会SpringBoot项目敏感词、违规词过滤方案

一个社区最重要的就是交流氛围与审查违规&#xff0c;而这两者都少不了对于敏感词进行过滤的自动维护措施。基于这样的措施&#xff0c;我们才能基本保证用户在使用社区的过程中&#xff0c;不至于被敏感违规词汇包围&#xff0c;才能够正常的进行发布帖子和评论&#xff0c;享…...

kafka经典面试题

这里写目录标题1.生产者1.1 生产者发送原理1.2 分区有什么好处?1.3 生产消息时, 是如何决定消息落盘到哪个分区的?1.4 生产者如何提高吞吐量1.5 如何保证生产的消息不丢失(能成功落盘)1.6 ack为-1, 就肯定不会丢失数据吗?1.7 生产者重复发送消息的场景1.8 生产者如何保证数据…...

我的CSDN笔记总索引(阅读量降序,代码自动遍历生成HTML5源码)

Python代码用Linux命令行工具crul获取CSDN博文页面源码&#xff0c;Python内置re正则解析出博文笔记信息。 (本文获得CSDN质量评分【xx】)【学习的细节是欢悦的历程】Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学…...

修改Windows hosts文件的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

愤怒的Spring(三)Idaea Maven搭建Spring并运行项目(超详细,超全)

愤怒的Spring&#xff08;三&#xff09; 一、目录结构 环境搭配与上一篇内容一样&#xff0c;详情请看愤怒的Spring&#xff08;二&#xff09;Idaea Maven搭建Spring并运行项目&#xff08;超详细&#xff0c;超全&#xff09;https://blog.csdn.net/sz710211849/article/d…...

NDK(三):JNIEnv解析

文章目录一、概述二、JNIEnv结构体三、JNINativeInterface结构体3.1 Class操作3.2 反射操作3.3 对象字段 & 方法操作3.4 类的静态字段 & 静态方法操作3.5 字符串操作3.6 锁操作3.7 数组操作3.8 注册和反注册native方法3.9 异常Exception操作3.10 引用的操作3.11 其它四…...

禅道——图文安装及使用教程

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;练习时长两年半的java博主 &#x1f4d6;个人主页&#xff1a;君临๑ &#x1f39e;️文章介绍&#xff1a;禅道的2023版安装图文教程 &#x1f381; 如果文章对你有用&#xff0c;就点个免费的赞吧&#x1f44d; 目录 一、搜…...

Java基础——枚举类enum

枚举类是一种特殊的数据类型&#xff0c;可以理解为一个数组&#xff0c;数组成员为特定的对象枚举类不能在外面创建对象&#xff0c;在类里面就包含了一组特定的对象&#xff0c;每个对象有着相同数量的属性枚举类的对象放在最前面&#xff0c;且对象们的顺序就是对应的索引枚…...

【机器学习】一文了解如何评估和选择最佳机器学习模型并绘制ROC曲线?

一文了解如何评估和选择最佳机器学习模型? 问ChatGPT:如何选择最佳机器学习模型?问ChatGPT:评估机器学习模型有哪些指标?0. 引言1. 混淆矩阵2. 评价指标3. ROC与AUC4. PR(precision recall )曲线参考资料问ChatGPT:如何选择最佳机器学习模型? 选择最佳机器学习模型是机…...

vue3 笔记

watchEffect 的起源 stackoverflow - watchEffect vs. watch watch behavior in v3 is different to v2Change watch Options API to trigger immediately vue3 最初只有 watch &#xff0c;没有 watchEffect。这个时候的 watch 默认是 immediate true&#xff0c;可以 wat…...

第12章_MySQL数据类型精讲

第12章_MySQL数据类型精讲 &#x1f3e0;个人主页&#xff1a;shark-Gao &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是shark-Gao&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f389;目前状况&#xff1a;23届毕业生&#xff0c…...

二叉树路径总和第一题

1题目 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点 是指没有…...

@RefreshScope源码解析

前言 RefeshScope这个注解想必大家都用过&#xff0c;在微服务配置中心的场景下经常出现&#xff0c;它可以用来刷新Bean中的属性配置&#xff0c;那么它是如何做到的呢&#xff1f;让我们来一步步揭开它神秘的面纱。 RefreshScope介绍 就是说我们在修改了bean属性的时候项目…...

【开发】后端框架——Spring

前置知识&#xff1a;JSP&Servlet 学习视频&#xff1a;https://www.bilibili.com/video/BV1WE411d7Dv?spm_id_from333.999.0.0 IoC&#xff1a;控制反转 IoC的理解&#xff1a;IoC思想&#xff0c;IoC怎么创建对象&#xff0c;IoC是Spring的核心 依赖注入三种方式&#x…...

vue中的自定义指令

前言 说到 vue 中的自定义指令&#xff0c;相信大家都不陌生。在官网中是这么说的&#xff0c;除了核心功能默认内置的指令 (v-model 和 v-show)&#xff0c;vue 也允许注册自定义指令。那什么时候会用到自定义指令呢&#xff1f;代码复用和抽象的主要形式是组件。然而&#xf…...

技术分享及探讨

前言 很高兴给大家做一个技术分享及探讨。 下面给大家分享几个工作遇到有趣的例子。 docker docker 进程 现象 ​ 客户的模型导入到BML平台发布预测服务后&#xff0c;模型本身是用django提供的支持。按照本地docker的方式进行调试&#xff0c;kill掉django的进程修改代码…...

人工智能AI

AI 模型。它使用深度神经网络&#xff0c;从数十亿或数万亿个单词中学习&#xff0c;能够生成任何主题或领域的文本。它可以执行各种自然语言任务&#xff0c;如分类、总结、翻译、生成和对话。 大语言模型开发建立在4个核心思想上&#xff1a; 模型 – Models 提示词 - Prompt…...

2022天梯赛补题

题目详情 - L2-041 插松枝 (pintia.cn) 思路&#xff1a;模拟 背包就是个栈&#xff0c;开个stack解决流程思路是&#xff0c;每次取推进器前&#xff0c;尽可能拿背包的&#xff0c;背包拿到不可以时&#xff0c;跳出拿推进器时判断&#xff1a; 如果背包装得下&#xff0c;…...

字节跳动测试岗面试挂在2面,复盘后,我总结了失败原因,决定再战一次...

先说下我基本情况&#xff0c;本科不是计算机专业&#xff0c;现在是学通信&#xff0c;然后做图像处理&#xff0c;可能面试官看我不是科班出身没有问太多计算机相关的问题&#xff0c;因为第一次找工作&#xff0c;字节的游戏专场又是最早开始的&#xff0c;就投递了&#xf…...

Nodejs实现通用的加密和哈希算法(MD5、SHA1、Hmac、AES、Diffie-Hellman、RSA),crypto模块详解

crypto crypto模块的目的是为了提供通用的加密和哈希算法(hash)。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。 MD5和SHA1 MD5是一种常用的哈希算法,…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...