SpringBoot实现过滤敏感词的示例代码

过滤敏感词

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

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

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

@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<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);
        }
    }
}

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

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

1.定义前缀树(Tree)

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

// 前缀树
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);
    }
}

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);
}

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

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

特殊符号怎么处理:

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

定义三个指针:

  • 指针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过滤敏感词的资料请关注我们其它相关文章!

(0)

相关推荐

  • 使用Springboot对配置文件中的敏感信息加密

    Springboot对配置文件的敏感信息加密 前言 最近公司对软件的安全问题比较在意,要求对配置文件中的敏感信息如数据库密码等进行加密.但是Springboot是一款高度集成的框架,如果仅仅是简单的对数据库密码进行加密了,由于连接数据库的操作是框架自己完成的,这就会造成不小的麻烦. 经过调研,找到了如下方式还比较方便. 项目配置 该项目用到了jasypt库.原理很简单,通过该库提供的方法进行敏感信息加密,生成密文xxxxx,然后将密文使用ENC()包裹起来. 添加依赖 <!-- jasypt场景

  • springboot实现敏感字段加密存储解密显示功能

    springboot实现敏感字段加密存储,解密显示,通过mybatis,自定义注解+AOP切面,Base64加解密方式实现功能. 1.代码实现: 创建springboot项目 添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <de

  • SpringBoot使用前缀树过滤敏感词的方法实例

    目录 一.前缀树 二.敏感词过滤器 总结 一.前缀树 一般设计网站的时候,会有问题发布或者是内容发布的功能,这些功能的有一个很重要的点在于如何实现敏感词过滤,要不然可能会有不良信息的发布,或者发布的内容中有夹杂可能会有恶意功能的代码片段,敏感词过滤的基本的算法是前缀树算法,前缀树也就是字典树,通过前缀树匹配可以加快敏感词匹配的速度. 前缀树又称为Trie.字典树.查找树.主要特点是:查找效率高,但内存消耗大:主要应用于字符串检索.词频统计.字符串排序等. 到底什么是前缀树?前缀树的功能是如何实现

  • Springboot敏感字段脱敏的实现思路

    生产环境用户的隐私数据,比如手机号.身份证或者一些账号配置等信息,入库时都要进行不落地脱敏,也就是在进入我们系统时就要实时的脱敏处理. 用户数据进入系统,脱敏处理后持久化到数据库,用户查询数据时还要进行反向解密.这种场景一般需要全局处理,那么用AOP切面来实现在适合不过了. 首先自定义两个注解@EncryptField.@EncryptMethod分别用在字段属性和方法上,实现思路很简单,只要方法上应用到@EncryptMethod注解,则检查入参字段是否标注@EncryptField注解,有则

  • Springboot AOP对指定敏感字段数据加密存储的实现

    前言 本文主要内容: 1. 插入数据 自定义注解方式  对 指定接口方法 的 参数的指定字段进行 加密存储: 2.对数据内的加密数据,进行解密返回 先看看效果 : 数据存入数据库表内, 手机号phone和邮箱email 属于敏感数据,我们需要密文存储 : 查询解密返回: 1.  自定义注解 加密标识注解  NeedEncrypt.java : import java.lang.annotation.*; /** * @Author JCccc * @Description 需加密 * @Date

  • SpringBoot集成Jasypt敏感信息加密的操作方法

    目录 前言 哪些信息需要加密 敏感信息加密的作用 选择加密的组件 项目集成Jasypt方式 方式一 方式二 方式三 Springboot整合Jasypt实战 一.引入依赖 二.配置文件中添加Jasypt配置信息 三.使用Jasypt对数据库账号和密码加密,并替换明文. 四.查看执行结果 使用中的一些坑 1.使用jasypt3.0启动时报:Failed to bind properties under ‘xxx.xxx.xxx’ to java.lang.String 2.加解密秘钥如何存储 如何

  • php过滤敏感词的示例

    复制代码 代码如下: $badword = array(    '张三','张三丰','张三丰田');$badword1 = array_combine($badword,array_fill(0,count($badword),'*'));$bb = '我今天开着张三丰田上班';$str = strtr($bb, $badword1);echo $str; 复制代码 代码如下: $hei=array('中国','日本');$blacklist="/".implode("|&

  • 利用Python正则表达式过滤敏感词的方法

    问题描述:很多网站会对用户发帖内容进行一定的检查,并自动把敏感词修改为特定的字符. 技术要点: 1)Python正则表达式模块re的sub()函数: 2)在正则表达式语法中,竖线"|"表示二选一或多选一. 参考代码: 以上这篇利用Python正则表达式过滤敏感词的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • springboot 使用自定义的aspect的示例代码

    对某个类型中的方法进行拦截,然后加入固定的业务逻辑,这是AOP面向切面编程可以做的事,在springboot里实现aop的方法也有很多, spring-boot-starter-aop 或者 aspectjweaver 都是可以实现的,不过我们在实现之前,先来看一下aop里的几个概念. 概念 切面(Aspect):是指横切多个对象的关注点的一个模块化,事务管理就是J2EE应用中横切关注点的很好示例.在Spring AOP中,切面通过常规类(基本模式方法)或者通过使用了注解@Aspect的常规类来

  • SpringBoot 签到奖励实现方案的示例代码

    前言 最近在做社交业务,用户进入APP后有签到功能,签到成功后获取相应的奖励: 项目状况:前期尝试业务阶段: 特点: 快速实现(不需要做太重,满足初期推广运营即可) 快速投入市场去运营 用户签到: 用户在每次启动时查询签到记录(规则:连续7日签到从0开始,签到过程中有断签从0开始) 如果今日未签到则提示用户可以进行签到 用户签到获取相应的奖励 提到签到,脑海中首先浮现特点: 需要记录每位用户每天的签到情况 查询时根据规则进行签到记录情况 需求&流程设计&技术实现方案 需求原型图 查询签到记

  • SpringBoot集成阿里巴巴Druid监控的示例代码

    druid是阿里巴巴开源的数据库连接池,提供了优秀的对数据库操作的监控功能,本文要讲解一下springboot项目怎么集成druid. 本文在基于jpa的项目下开发,首先在pom文件中额外加入druid依赖,pom文件如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&qu

  • ajax实现的提交文章前进行敏感词审核的代码

    于是想到在提交时返回Ajax传递的布尔值.而实际上,Ajax传递的函数get2()是chkfull(bt)的子函数,不能向外部函数进行传值,alert()也不起作用.所以干脆取消了"提交"按钮的"提交"类型,而使用Javascript进行一系列检查后,自动提交表单. 代码如下 HTML 复制代码 代码如下: <input type="button" class="body" id="subm" nam

  • SpringBoot与velocity的结合的示例代码

    Velocity是一种Java模版引擎技术,MVC架构的一种实现,但它更多的是关注在Model和View之间,作为它们的桥梁.服务端渲染,我们使用最多的就是用他来渲染HTML.下面我们看看他与spring boot的结合. 老样子,我们看下pom中定义的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifact

  • SpringBoot返回json和xml的示例代码

    有些情况接口需要返回的是xml数据,在springboot中并不需要每次都转换一下数据格式,只需做一些微调整即可. 新建一个springboot项目,加入依赖jackson-dataformat-xml,pom文件代码如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&qu

  • springboot集成dubbo注解版的示例代码

    工作中用springboot搭建项目,用dubbo做远程调用.springboot提倡注解配置和java配置,本文是基于dubbo最新版本2.6.3,使用注解方式的示例. 本文假定你已经有springboot和dubbo的使用经验. dubbo简介 dubbo是阿里巴巴开源的分布式服务框架,一般使用dubbo的RPC调用.但2016年停止维护,现在使用的2.8.4版本其实是当当维护的dubbox.2017年8月阿里又重启维护dubbo,并从2.5.7版本开始支持注解配置. 准备 此示例使用gra

  • springBoot整合RocketMQ及坑的示例代码

    版本: JDK:1.8 springBoot:1.5.10 rocketMQ:4.2.0 pom 配置: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.10.RELEASE</version> </parent> <d

随机推荐

其他