白名单和敏感词规则过滤
本文最后更新于 2025-04-04,文章超过7天没更新,应该是已完结了~
今天在解析xfg对于白名单和敏感词规则过滤这个功能的实现,蛮有收获的,写一篇文章记录下~~
整体的设计思路:
具体实现代码
public interface ILogicFilter {
RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception;
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogicStrategy {
DefaultLogicFactory.LogicModel logicMode();
}
@Slf4j
@Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.SENSITIVE_WORD)
public class SensitiveWordFilter implements ILogicFilter {
@Resource
private SensitiveWordBs words;
@Value("${app.config.white-list}")
private String whiteListStr;
@Override
public RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception {
// 白名单用户不做敏感词处理
if (chatProcess.isWhiteList(whiteListStr)) {
return RuleLogicEntity.<ChatProcessAggregate>builder()
.type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
}
ChatProcessAggregate newChatProcessAggregate = new ChatProcessAggregate();
newChatProcessAggregate.setOpenid(chatProcess.getOpenid());
newChatProcessAggregate.setModel(chatProcess.getModel());
List<MessageEntity> newMessages = chatProcess.getMessages().stream()
.map(message -> {
String content = message.getContent();
String replace = words.replace(content);
return MessageEntity.builder()
.role(message.getRole())
.name(message.getName())
.content(replace)
.build();
})
.collect(Collectors.toList());
newChatProcessAggregate.setMessages(newMessages);
return RuleLogicEntity.<ChatProcessAggregate>builder()
.type(LogicCheckTypeVO.SUCCESS)
.data(newChatProcessAggregate)
.build();
}
}
@Slf4j
@Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.ACCESS_LIMIT)
public class AccessLimitFilter implements ILogicFilter {
@Value("${app.config.limit-count:10}")
private Integer limitCount;
@Value("${app.config.white-list}")
private String whiteListStr;
@Resource
private Cache<String, Integer> visitCache;
@Override
public RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception {
// 1. 白名单用户直接放行
if (chatProcess.isWhiteList(whiteListStr)) {
return RuleLogicEntity.<ChatProcessAggregate>builder()
.type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
}
String openid = chatProcess.getOpenid();
// 2. 访问次数判断
int visitCount = visitCache.get(openid, () -> 0);
if (visitCount < limitCount) {
visitCache.put(openid, visitCount + 1);
return RuleLogicEntity.<ChatProcessAggregate>builder()
.type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
}
return RuleLogicEntity.<ChatProcessAggregate>builder()
.info("您今日的免费" + limitCount + "次,已耗尽!")
.type(LogicCheckTypeVO.REFUSE).data(chatProcess).build();
}
}
@Service
public class DefaultLogicFactory {
public Map<String, ILogicFilter> logicFilterMap = new ConcurrentHashMap<>();
public DefaultLogicFactory(List<ILogicFilter> logicFilters) {
logicFilters.forEach(logic -> {
LogicStrategy strategy = AnnotationUtils.findAnnotation(logic.getClass(), LogicStrategy.class);
if (null != strategy) {
logicFilterMap.put(strategy.logicMode().getCode(), logic);
}
});
}
public Map<String, ILogicFilter> openLogicFilter() {
return logicFilterMap;
}
/**
* 规则逻辑枚举
*/
public enum LogicModel {
ACCESS_LIMIT("ACCESS_LIMIT", "访问次数过滤"),
SENSITIVE_WORD("SENSITIVE_WORD", "敏感词过滤"),
;
}
}
使用过程
@Override
protected RuleLogicEntity<ChatProcessAggregate> doCheckLogic(ChatProcessAggregate chatProcess, String... logics) throws Exception {
Map<String, ILogicFilter> logicFilterMap = logicFactory.openLogicFilter();
RuleLogicEntity<ChatProcessAggregate> entity = null;
for (String code : logics) {
entity = logicFilterMap.get(code).filter(chatProcess);
if (!LogicCheckTypeVO.SUCCESS.equals(entity.getType())) return entity;
}
return entity != null ? entity : RuleLogicEntity.<ChatProcessAggregate>builder()
.type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
}
解析以及相关设计模式
1、依赖注入+反射 + 注解驱动(基于元编程)
@Service
public class DefaultLogicFactory {
public Map<String, ILogicFilter> logicFilterMap = new ConcurrentHashMap<>();
public DefaultLogicFactory(List<ILogicFilter> logicFilters) {
logicFilters.forEach(logic -> {
LogicStrategy strategy = AnnotationUtils.findAnnotation(logic.getClass(), LogicStrategy.class);
if (null != strategy) {
logicFilterMap.put(strategy.logicMode().getCode(), logic);
}
});
}
....
1.自动注入和Bean初始化
DefaultLogicFactory 被Spring容器管理,构造函数会在Bean实例化时被调用。
构造函数的参数
List<ILogicFilter> logicFilters
会被Spring自动收集。也就是说,Spring会将容器中所有实现了ILogicFilter
接口的Bean注入到这个列表中。即我们实现的AccessLimitFilter
和SensitiveWordFilter
2.不需要手动维护 ILogicFilter
的映射关系
AnnotationUtils.findAnnotation()
通过反射获取类上的@LogicStrategy
注解。动态获取logicMode()
,并将ILogicFilter
实例注册到logicFilterMap
,相当于 给每个加了@LogicStrategy
的过滤器加了个标识。
3.实现了“无侵入式”扩展:新的规则引擎过滤器 只需要实现ILogicFilter
,就会自动被工厂发现和注册,并给加上 @LogicStrategy
自动添加标记识别。(优雅~)
2、 策略模式(Strategy Pattern)
不同的过滤策略(如 AccessLimitFilter
、SensitiveWordFilter
)可以独立定义并在运行时动态选择
public interface ILogicFilter {
RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception;
}
@Slf4j
@Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.ACCESS_LIMIT)
public class AccessLimitFilter implements ILogicFilter {
@Override
public RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception {
// 访问次数校验逻辑
}
}
@Slf4j
@Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.SENSITIVE_WORD)
public class SensitiveWordFilter implements ILogicFilter {
@Override
public RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception {
// 敏感词过滤逻辑
}
}
策略模式的好处:
✅ 开闭原则(OCP):可以添加新的 ILogicFilter
实现,而不需要修改现有代码。
✅ 降低耦合:具体的过滤逻辑被隔离到不同的 ILogicFilter
里,工厂负责选择正确的策略。
✅ 运行时动态选择:过滤器的选择基于 logicMode
,可以在运行时灵活调整,而不需要写死在代码里,如下:
3、 责任链模式(Chain of Responsibility Pattern)
多个 ILogicFilter
形成责任链,逐个执行,直到某个过滤器失败
@Override
protected RuleLogicEntity<ChatProcessAggregate> doCheckLogic(ChatProcessAggregate chatProcess, String... logics) throws Exception {
Map<String, ILogicFilter> logicFilterMap = logicFactory.openLogicFilter();
RuleLogicEntity<ChatProcessAggregate> entity = null;
for (String code : logics) {
entity = logicFilterMap.get(code).filter(chatProcess);
if (!LogicCheckTypeVO.SUCCESS.equals(entity.getType())) return entity;
}
return entity != null ? entity : RuleLogicEntity.<ChatProcessAggregate>builder()
.type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
}
logics
传入多个逻辑码(如"ACCESS_LIMIT"
、"SENSITIVE_WORD"
)。遍历
logics
,依次获取logicFilterMap
中的过滤器,并执行filter(chatProcess)
。如果某个过滤器返回失败(
entity.getType()
不是SUCCESS
),立即终止责任链并返回失败结果。
责任链模式的好处:
✅ 增强扩展性:可以轻松添加新的 ILogicFilter
,不会影响现有逻辑。
✅ 灵活组合:调用方可以根据业务需要动态指定执行哪些过滤器,而不是固定的流程。
✅ 优化性能:一旦有一个过滤器失败,后续的过滤器不会执行,节省计算资源。
4、 工厂模式(Factory Pattern)
public class DefaultLogicFactory {
public Map<String, ILogicFilter> logicFilterMap = new ConcurrentHashMap<>();
public DefaultLogicFactory(List<ILogicFilter> logicFilters) {
logicFilters.forEach(logic -> {
LogicStrategy strategy = AnnotationUtils.findAnnotation(logic.getClass(), LogicStrategy.class);
if (null != strategy) {
logicFilterMap.put(strategy.logicMode().getCode(), logic);
}
});
}
public Map<String, ILogicFilter> openLogicFilter() {
return logicFilterMap;
}
}
DefaultLogicFactory
负责管理所有ILogicFilter
实现类。在构造函数中,它扫描所有实现了
ILogicFilter
接口的类,并通过 @LogicStrategy 注解找到它们的logicMode
,然后将其注册到logicFilterMap
。当
ChatService
需要使用过滤器时,只需从logicFilterMap
获取,而不需要手动创建实例。
工厂模式的好处:
✅ 解耦对象创建过程:ChatService
并不关心具体的 ILogicFilter
具体实现是如何创建的,它只需要从 DefaultLogicFactory
获取。
✅ 易于扩展:如果有新的 ILogicFilter
需要加入,只需实现接口并添加 @LogicStrategy
注解,而不需要修改 DefaultLogicFactory
。
- 感谢你赐予我前进的力量