自定义注解+DFA敏感词校验

概要

自定义注解+Adf敏感词校验

整体架构流程

自定义注解:校验指定类中的指定属性


```java
@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SensitiveWord {
    Class<?> sensitiveDto() ;
    String[] filedNames() ;
}

利用反射获取对应属性值

@Aspect
@Component
@Slf4j
public class SensitiveWordAspect {
    @Pointcut("@annotation(**.**.SensitiveWord)")
    public void sensitiveWordCut(){}

    @Before( "sensitiveWordCut()")
    public void doAround(JoinPoint joinPoint) {
        Method method = JoinPointMethodUtil.currentMethod(joinPoint);
        SensitiveWord annotation = method.getAnnotation(SensitiveWord.class);
        Object[] args = joinPoint.getArgs();
        for(Object o:args){
            Class<?> aClass = o.getClass();
            if(aClass.equals(annotation.sensitiveDto())){
                String[] strings = annotation.filedNames();
                if(strings!=null&&strings.length>0){
                    Arrays.asList(strings).forEach(f->{
                        try {
                            Field field = aClass.getDeclaredField(f);
                            field.setAccessible(true);
                            Object o1 = field.get(o);
                            if(o1!=null){
                                String string = o1.toString();
                                if(SensitiveWordUtil.contains(string,SensitiveWordUtil.LONG_MATCH)){
                                    throw new MyException("包含敏感词汇:"+JSON.toJSONString(SensitiveWordUtil.getSensitiveWord(string,SensitiveWordUtil.LONG_MATCH)));
                                }
                            }
                        } catch (NoSuchFieldException e) {
                            throw new RuntimeException(e);
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        }
                    });
                }
            }
        }
    }
}

此处引用工具类添加链接描述

为方便维护字典持久化到数据库同时初始化map

    @GetMapping("/initMap")
    @ApiOperation("初始化map")
    public void initMap(){
        List<String> list=sensitiveWordService.getList();
        SensitiveWordUtil.initSensitiveWordMap(list);
    }

服务启动时初始化map

@Component
@Slf4j
public class MyStartupRunner implements CommandLineRunner {

    private final SensitiveWordController sensitiveWordController;

    public MyStartupRunner(SensitiveWordController sensitiveWordController) {
        this.sensitiveWordController = sensitiveWordController;
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("启动时调用了。。。。");
        sensitiveWordController.initMap();
    }
}

注解使用

 	@PostMapping
    @ApiOperation("保存")
    //针对入参MyDTO对象的属性title和content进行敏感词校验
    @SensitiveWord(sensitiveDto = MyDTO.class,filedNames = {"title","content"})
    public Result save(@RequestBody MyDTO dto) 


<think>好的,我现在需要帮用户解决如何在Spring Boot中使用AOP和DFA算法实现敏感词过滤与审核的问题。首先,我得回顾一下DFA算法的基本概念,因为用户提到了它。DFA,即确定有限状态自动机,常用于高效敏感词过滤。它的优势在于构建状态转移表,能快速检测文本中的敏感词。 接下来,用户还提到了AOP(面向切面编程)。AOP可以用来在不修改业务代码的情况下,统一处理敏感词过滤的逻辑。比如,在Controller层的方法执行前,通过切面拦截请求参数,进行敏感词检测或替换。这样设计符合Spring Boot的模块化思想,也便于维护。 我需要整合这两个技术点。首先,得实现DFA算法的敏感词过滤器。这包括读取敏感词库,构建Trie树结构,每个节点代表一个字符,叶子节点标记为敏感词结束。然后,在检测文本时,逐字符遍历,查看是否存在匹配的路径。 然后是AOP部分的实现。需要定义一个切面,针对特定的Controller方法,比如处理用户输入的POST请求,使用@Around通知来获取请求参数,调用DFA过滤器进行处理。如果发现敏感词,可以记录日志、返回错误信息或替换为星号。 另外,用户可能还关心审核功能的实现。审核通常涉及将检测到的敏感内容记录到数据库或日志,供后续人工审核。这部分可能需要异步处理,避免影响主流程的性能。 需要考虑的细节包括:敏感词库的加载方式(从数据库、文件或缓存),DFA树的初始化时机(应用启动时加载),以及如何高效处理大量敏感词。例如,引用中提到Spring Boot结合Redis处理热搜和敏感词过滤,可能可以考虑将敏感词库存储在Redis中,提高读取速度。 还有,敏感词替换的实现。比如,检测到“敏感文字”替换为“**”,需要遍历文本,找到所有敏感词并替换。DFA算法在检测时能高效定位敏感词的位置和长度,方便替换操作。 可能遇到的问题包括中文字符的处理,比如多字节字符的拆分,需要确保DFA构建时正确处理UTF-8字符。另外,AOP切入点的选择,确保覆盖所有需要过滤的接口,同时避免性能损耗。 最后,测试环节也很重要。需要编写单元测试,验证敏感词检测和替换的正确性,以及AOP切面是否按预期拦截请求。性能测试也是必要的,确保在高并发下过滤逻辑不会成为瓶颈。 总结下来,步骤大致分为:1. 实现DFA敏感词过滤器;2. 配置AOP切面拦截请求;3. 处理敏感词(拦截或替换);4. 记录审核日志;5. 集成测试和优化。同时,参考已有的实现,如引用中的SensitiveFilter类,可以借鉴其设计模式,比如单例模式确保过滤器实例唯一,提高效率。</think>### Spring Boot通过AOP与DFA算法实现敏感词过滤与审核方案 #### 一、DFA敏感词过滤实现 1. **DFA算法核心** DFA(确定有限状态自动机)通过构建敏感词树实现高效匹配,每个节点表示一个字符,叶子节点标记敏感词结束。例如,敏感词“测试”的树结构为: ```text root → 测 → 试(END) ``` 检测时逐字符遍历树结构,若匹配到END节点则命中敏感词[^1]。 2. **敏感词过滤器实现** ```java public class SensitiveFilter { private static final TrieNode root = new TrieNode(); // 初始化敏感词树(应用启动时加载) static { List<String> words = loadSensitiveWords(); // 从数据库/文件加载 for (String word : words) { TrieNode node = root; for (char c : word.toCharArray()) { node = node.getChildren().computeIfAbsent(c, k -> new TrieNode()); } node.setEnd(true); } } // 检测并替换敏感词 public String filter(String text) { StringBuilder result = new StringBuilder(); int start = 0; TrieNode current = root; for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); current = current.getChildren().get(c); if (current == null) { i = start; result.append(text.charAt(start)); start++; current = root; } else if (current.isEnd()) { result.append("*".repeat(i - start + 1)); start = i + 1; current = root; } } return result.toString(); } } ``` --- #### 二、AOP切面集成 1. **定义切面拦截请求** 针对Controller层方法,拦截包含用户输入的参数(如@RequestBody): ```java @Aspect @Component public class SensitiveAspect { @Autowired private SensitiveFilter filter; // 拦截所有POST请求且含@RequestBody注解的方法 @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping) && args(..,@RequestBody *)") public void requestPointcut() {} @Around("requestPointcut()") public Object filterInput(ProceedingJoinPoint joinPoint) throws Throwable { Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { if (args[i] instanceof String text) { args[i] = filter.filter(text); // 替换敏感词 } } return joinPoint.proceed(args); } } ``` 2. **审核日志记录** 检测到敏感词时异步记录日志(如使用@Async): ```java @Async public void logSensitiveAction(String text, String userId) { auditLogRepository.save(new AuditLog(userId, text, LocalDateTime.now())); } ``` --- #### 三、性能优化与扩展 1. **敏感词库存储** - 将敏感词存储在Redis中,利用缓存加速加载[^2]。 - 使用`@PostConstruct`在服务启动时加载词库。 2. **多模式处理** ```java public enum FilterMode { REPLACE, // 替换为* BLOCK // 直接拦截请求 } ``` 根据业务需求通过配置切换模式。 --- #### 四、测试验证 1. **单元测试** ```java @Test public void testFilter() { SensitiveFilter filter = new SensitiveFilter(); assertEquals("****", filter.filter("测试文字")); } ``` 2. **性能压测** 使用JMeter模拟高并发请求,确保过滤延迟<10ms。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值