前言

在内容审核、用户评论、社区管理等场景中,敏感词检测是必不可少的功能。本文将介绍如何在 Spring Boot 项目中集成 sensitive-word 库,实现高效的敏感词检测。

tabs

  • 用户昵称、签名过滤
  • 评论、弹幕审核
  • 论坛帖子过滤
  • 聊天内容监管
  • 客服质检/tab
  • 🚀 高性能:基于 DFA 算法,14万+ QPS
  • 🎯 准确率高:支持数字变体、重复词等检测
  • 🔧 易集成:开箱即用,注解驱动
  • 📦 功能丰富:内置大量敏感词库
  • 🔌 可扩展:支持自定义敏感词和白名单/tab
  • Spring Boot 2.x/3.x
  • sensitive-word 0.18.0
  • DFA 算法(确定有限状态自动机)
  • 注解式编程/tab

项目地址https://github.com/houbb/sensitive-word

一、快速开始

1.1 Maven 依赖

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>sensitive-word</artifactId>
    <version>0.18.0</version>
</dependency>

1.2 基础使用

import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
import com.github.houbb.sensitive.word.core.SensitiveWordHelper;
​
public class SensitiveWordDemo {
    public static void main(String[] args) {
        String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
​
        // 1. 检测是否包含敏感词
        boolean contains = SensitiveWordHelper.contains(text);
        System.out.println("是否包含敏感词: " + contains); // true
​
        // 2. 查找第一个敏感词
        String first = SensitiveWordHelper.findFirst(text);
        System.out.println("第一个敏感词: " + first); // 五星红旗
​
        // 3. 查找所有敏感词
        List<String> all = SensitiveWordHelper.findAll(text);
        System.out.println("所有敏感词: " + all);
        // [五星红旗, 毛主席, 天安门]
​
        // 4. 替换敏感词
        String replaced = SensitiveWordHelper.replace(text, '*');
        System.out.println("替换后: " + replaced);
        // ***迎风飘扬,***的画像屹立在***前。
    }
}

二、核心功能详解

2.1 四种检测方法

方法参数返回值说明
contains(String text)待检测文本boolean是否包含敏感词
findFirst(String text)待检测文本String第一个敏感词
findAll(String text)待检测文本List所有敏感词
replace(String text)待检测文本String替换敏感词为*
String text = "这是一个测试,包含不良信息。";
​
// 快速检测
if (SensitiveWordHelper.contains(text)) {
    // 包含敏感词,拒绝提交
    throw new BusinessException("内容包含敏感词");
}
​
// 查找具体敏感词
String firstWord = SensitiveWordHelper.findFirst(text);
List<String> allWords = SensitiveWordHelper.findAll(text);
​
// 替换敏感词
String cleanText = SensitiveWordHelper.replace(text);

2.2 数字变体检测

这个功能可以检测用户用数字替换字符的变体:

String text1 = "法轮功";
String text2 = "法0轮0功";
String text3 = "法O轮O功";
​
SensitiveWordBs wordBs = SensitiveWordBs.newInstance()
    .enableNumCheck(true)  // 启用数字变体检测
    .enableEnglishCheck(true)  // 启用英文字母变体检测
    .init();
​
System.out.println(wordBs.contains(text1));  // true
System.out.println(wordBs.contains(text2));  // true
System.out.println(wordBs.contains(text3));  // true

注意:数字变体检测会增加计算量,根据实际需求选择是否开启。

三、Spring Boot 集成

3.1 配置文件

application.yaml 中配置敏感词检测:

sensitive-word:
  # 是否启用敏感词检测,默认为 true
  enabled: true
​
  # 敏感词检测模式
  # true=严格模式(检测所有),false=快速模式(发现第一个就返回)
  strict-mode: false
​
  # 是否启用数字变体检测
  # 例如:将 "法轮功" 替换为 "法0轮0功"
  enable-num-check: true
​
  # 是否启用邮箱检测
  enable-email-check: true
​
  # 是否启用 URL 检测
  enable-url-check: true
​
  # 是否启用 IPv4 检测
  enable-ipv4-check: false
​
  # 自定义敏感词列表
  custom-words:
    - 自定义敏感词1
    - 自定义敏感词2
​
  # 自定义白名单列表
  white-list:
    - 允许的词1
    - 允许的词2

3.2 注解使用

字段级别检测

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import com.yourpackage.framework.sensitiveword.core.annotation.SensitiveWordCheck;
​
@Data
@Schema(description = "用户信息修改请求参数")
public class UserProfileEditReqVO {
​
    @Schema(description = "用户ID")
    private Long userId;
​
    @Schema(description = "用户昵称")
    @SensitiveWordCheck(value = "用户昵称")
    private String nickname;
​
    @Schema(description = "个人简介")
    @SensitiveWordCheck(value = "个人简介")
    private String bio;
}

方法级别检测

import com.yourpackage.framework.sensitiveword.core.annotation.SensitiveWordValidate;
import org.springframework.web.bind.annotation.*;
​
@RestController
@RequestMapping("/user/profile")
public class UserProfileController {
​
    @Resource
    private UserService userService;
​
    @PostMapping("/update")
    public CommonResult<Boolean> updateUserProfile(
        @RequestBody
        @Valid
        @SensitiveWordValidate  // 触发敏感词检测
        UserProfileEditReqVO editReqVO
    ) {
        return CommonResult.success(userService.updateProfile(editReqVO));
    }
}

Service 层检测

import com.yourpackage.framework.sensitiveword.core.annotation.SensitiveWordValidate;
​
@Service
public class UserServiceImpl implements UserService {
​
    @Override
    public Boolean updateProfile(@SensitiveWordValidate UserProfileEditReqVO editReqVO) {
        // 方法参数会被自动检测
        // 如果包含敏感词,会抛出 SensitiveWordException
        // ...
    }
}

3.3 完整工作流程

客户端请求
  ↓
Controller 层
  ↓
@SensitiveWordValidate 注解检测
  ↓
包含敏感词?
  ├─ 是 → 抛出 SensitiveWordException → 返回 400 错误
  └─ 否 → Service 层处理 → 持久化 → 返回成功

实际案例

// 1. 用户提交昵称修改请求
POST /user/profile/update
Content-Type: application/json

{
  "nickname": "我是主席",  // 包含敏感词
  "avatarUrl": "https://example.com/avatar.jpg"
}

// 2. 后端检测流程
@SensitiveWordValidate UserProfileEditReqVO editReqVO
  ↓
检测到 "主席" 是敏感词
  ↓
抛出 SensitiveWordException: 用户昵称包含敏感词: 主席
  ↓
返回 400 错误

// 3. 响应
{
  "code": 400,
  "msg": "用户昵称包含敏感词: 主席",
  "data": null
}

四、自定义敏感词和白名单

4.1 配置文件方式

application.yaml 中配置:

sensitive-word:
  # 自定义敏感词
  custom-words:
    - 垃圾信息
    - 广告词
    - 违法词汇

  # 白名单(这些词不会被检测为敏感词)
  white-list:
    - 主席
    - 总统
    - 领导

4.2 编程方式

import com.github.houbb.sensitive.word.support.allow.WordAllows;
import com.github.houbb.sensitive.word.support.deny.WordDenys;
import java.util.Arrays;
import java.util.List;

// 自定义敏感词列表
List<String> myDenyWords = Arrays.asList(
    "垃圾信息",
    "广告词",
    "违法词汇"
);

// 自定义白名单列表
List<String> myAllowWords = Arrays.asList(
    "主席",
    "总统"
);

SensitiveWordBs wordBs = SensitiveWordBs.newInstance()
    .wordDeny(WordDenys.chain()
        .add(myDenyWords)  // 添加自定义敏感词
        .add(WordDenys.defaults())  // 保留默认敏感词库
    )
    .wordAllow(WordAllows.chain()
        .add(myAllowWords)  // 添加自定义白名单
        .add(WordAllows.defaults())  // 保留默认白名单
    )
    .init();

4.3 动态加载(数据库)

import com.github.houbb.sensitive.word.support.deny.IWordDeny;
import org.springframework.stereotype.Component;
import java.util.List;

@Component
public class DatabaseWordDeny implements IWordDeny {

    @Resource
    private SensitiveWordMapper sensitiveWordMapper;

    @Override
    public List<String> deny() {
        // 从数据库加载敏感词列表
        return sensitiveWordMapper.selectAll();
    }
}

使用方式:

SensitiveWordBs wordBs = SensitiveWordBs.newInstance()
    .wordDeny(new DatabaseWordDeny())
    .init();

五、高级配置

5.1 自定义替换字符

String replaced = SensitiveWordHelper.replace(text, "❌");
// 输出:这是一个❌,包含❌。

5.2 自定义替换策略

import com.github.houbb.sensitive.word.support.replace.WordReplace;

// 自定义替换策略
WordReplace replace = (word, stringBuilder) -> {
    stringBuilder.append("[屏蔽]");
};

String result = SensitiveWordBs.newInstance()
    .wordReplace(replace)
    .init()
    .replace(text);

5.3 指定检测类型

import com.github.houbb.sensitive.word.bs.SensitiveWordBs;

SensitiveWordBs wordBs = SensitiveWordBs.newInstance()
    // 只检测数字
    .wordDeny(WordDenys.defaults())
    // 白名单
    .wordAllow(WordAllows.defaults())
    // 启用邮箱检测
    .enableEmailCheck(true)
    // 启用 URL 检测
    .enableUrlCheck(true)
    // 启用数字变体检测
    .enableNumCheck(true)
    .init();

六、性能优化

6.1 性能指标

根据官方测试数据(机器配置:i7-6700, 16GB RAM):

场景QPS
简单文本检测140,000+
复杂文本检测100,000+
数字变体检测80,000+
大量敏感词库50,000+

提示:实际性能取决于机器配置、词典大小和检测策略。

6.2 优化建议

tabs

sensitive-word:
  strict-mode: false  # 快速模式
  • 检测到第一个敏感词就返回
  • 适合实时验证场景
  • 性能提升 30-50%/tab
sensitive-word:
  enable-email-check: false
  enable-url-check: false
  enable-ipv4-check: false
  enable-num-check: false
  • 只启用必需的检测
  • 减少不必要的计算
  • 性能提升 20-40%/tab
@Component
public class SensitiveWordCache {

    private final Cache<String, Boolean> cache =
        Caffeine.newBuilder()
            .maximumSize(10_000)
            .expireAfterWrite(1, TimeUnit.HOURS)
            .build();

    public boolean contains(String text) {
        return cache.get(text, key ->
            SensitiveWordHelper.contains(key)
        );
    }
}
  • 重复内容直接返回缓存结果
  • 适合热点内容检测
  • 性能提升 90%+/tab
@Async
public void checkAsync(String content, Consumer<Boolean> callback) {
    boolean result = SensitiveWordHelper.contains(content);
    callback.accept(result);
}
  • 非阻塞式检测
  • 适合高并发场景
  • 提升系统吞吐量/tab

6.3 批量检测优化

import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

public class BatchSensitiveWordChecker {

    private final ExecutorService executor =
        Executors.newFixedThreadPool(10);

    /**
     * 批量检测敏感词
     */
    public List<String> batchCheck(List<String> texts) {
        List<Future<String>> futures = texts.stream()
            .map(text -> executor.submit(() -> {
                if (SensitiveWordHelper.contains(text)) {
                    return text;
                }
                return null;
            }))
            .collect(Collectors.toList());

        return futures.stream()
            .map(future -> {
                try {
                    return future.get();
                } catch (Exception e) {
                    return null;
                }
            })
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
    }
}

七、异常处理

7.1 自定义异常处理

import com.yourpackage.framework.sensitiveword.core.exception.SensitiveWordException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class SensitiveWordExceptionHandler {

    @ExceptionHandler(SensitiveWordException.class)
    public CommonResult<?> handleSensitiveWordException(SensitiveWordException e) {
        // 获取检测到的敏感词列表
        List<String> words = e.getWords();

        // 记录日志
        log.warn("检测到敏感词: {}", words);

        // 返回友好的错误信息
        return CommonResult.error(400,
            "内容包含敏感词,请修改后提交");
    }
}

7.2 敏感词记录

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class SensitiveWordLogAspect {

    @Before("@annotation(check)")
    public void logSensitiveWord(SensitiveWordCheck check) {
        log.info("检测字段: {}", check.value());
    }

    @Before("@annotation(validate)")
    public void logSensitiveWordValidate(SensitiveWordValidate validate) {
        log.info("执行敏感词检测");
    }
}

八、实战案例

8.1 用户昵称过滤

需求:用户修改昵称时,检测并拒绝包含敏感词的昵称。

实现

@Data
@Schema(description = "用户信息修改请求参数")
public class UserProfileEditReqVO {

    @Schema(description = "用户昵称")
    @SensitiveWordCheck(value = "用户昵称")
    private String nickname;
}

测试

// 测试用例1:正常昵称
{
  "nickname": "快乐的小猪"
}
// 结果:通过 ✅

// 测试用例2:包含敏感词
{
  "nickname": "我是主席"
}
// 结果:拒绝 ❌
// 返回:用户昵称包含敏感词: 主席

8.2 评论内容审核

需求:用户提交评论时,自动替换敏感词。

实现

@Service
public class CommentService {

    public void createComment(CommentCreateReqVO reqVO) {
        String content = reqVO.getContent();

        // 替换敏感词
        String cleanContent = SensitiveWordHelper.replace(content);

        // 保存清理后的内容
        CommentDO comment = new CommentDO();
        comment.setContent(cleanContent);
        commentMapper.insert(comment);

        // 如果内容被修改,通知用户
        if (!content.equals(cleanContent)) {
            log.info("评论内容包含敏感词,已自动替换");
        }
    }
}

8.3 批量内容审核

需求:管理员批量审核用户提交的内容。

实现

@Service
public class ContentAuditService {

    /**
     * 批量审核内容
     */
    public AuditResult batchAudit(List<String> contents) {
        AuditResult result = new AuditResult();

        for (String content : contents) {
            // 检测敏感词
            List<String> words = SensitiveWordHelper.findAll(content);

            if (!words.isEmpty()) {
                // 记录违规内容
                result.addViolation(content, words);
            }
        }

        return result;
    }

    /**
     * 获取内容审核报告
     */
    public String generateReport(List<String> contents) {
        StringBuilder report = new StringBuilder();
        report.append("内容审核报告\n");
        report.append("==========================================\n");

        int total = contents.size();
        int passed = 0;
        int rejected = 0;

        for (String content : contents) {
            List<String> words = SensitiveWordHelper.findAll(content);

            if (words.isEmpty()) {
                passed++;
                report.append("✅ 通过: ").append(content).append("\n");
            } else {
                rejected++;
                report.append("❌ 拒绝: ").append(content).append("\n");
                report.append("   敏感词: ").append(words).append("\n");
            }
        }

        report.append("==========================================\n");
        report.append("总计: ").append(total).append("\n");
        report.append("通过: ").append(passed).append("\n");
        report.append("拒绝: ").append(rejected).append("\n");

        return report.toString();
    }
}

九、最佳实践

9.1 敏感词管理

tabs

  • 从官方仓库更新敏感词库
  • 根据业务需求添加自定义词
  • 定期审查白名单/tab
  • 普通敏感词:警告并替换
  • 严重敏感词:直接拒绝
  • 白名单词汇:允许通过/tab
  • 敏感词列表纳入版本管理
  • 记录每次修改的原因
  • 支持快速回滚/tab
  • 记录所有敏感词检测
  • 统计敏感词出现频率
  • 分析违规趋势/tab

9.2 性能监控

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Slf4j
@Aspect
@Component
public class SensitiveWordPerformanceAspect {

    @Around("@annotation(validate)")
    public Object monitorPerformance(ProceedingJoinPoint pjp,
                                    SensitiveWordValidate validate)
                                    throws Throwable {
        long start = System.currentTimeMillis();

        try {
            return pjp.proceed();
        } finally {
            long duration = System.currentTimeMillis() - start;

            // 记录检测耗时
            if (duration > 100) {
                log.warn("敏感词检测耗时: {}ms", duration);
            } else {
                log.info("敏感词检测耗时: {}ms", duration);
            }
        }
    }
}

9.3 降级策略

@Service
public class SensitiveWordService {

    @Value("${sensitive-word.enabled:true}")
    private boolean enabled;

    public boolean check(String text) {
        if (!enabled) {
            // 降级:敏感词检测关闭时直接通过
            return false;
        }

        try {
            return SensitiveWordHelper.contains(text);
        } catch (Exception e) {
            // 降级:检测失败时记录日志但放行
            log.error("敏感词检测异常,降级通过", e);
            return false;
        }
    }
}

十、总结

核心要点:sensitive-word 是一款高性能的敏感词检测库,基于 DFA 算法,支持多种检测策略和自定义扩展。

主要优势

  1. 高性能:基于 DFA 算法,单机 14万+ QPS
  2. 易集成:注解驱动,开箱即用
  3. 功能丰富:支持数字变体、邮箱、URL 等检测
  4. 可扩展:支持自定义敏感词和白名单
  5. 线程安全:初始化后可安全用于多线程环境

适用场景

  • ✅ 用户昵称、签名过滤
  • ✅ 评论、弹幕审核
  • ✅ 论坛帖子过滤
  • ✅ 聊天内容监管
  • ✅ 客服质检

参考资料

最后修改:2026 年 01 月 26 日
如果觉得我的文章对你有用,请随意赞赏