feat(comment): 新增敏感词过滤并拦截评论发送

This commit is contained in:
root
2026-03-08 14:43:58 +08:00
parent 1383c4a7de
commit bd5af140fe
4 changed files with 133 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
package com.test.musichouduan.service;
/**
* 敏感词服务接口
*/
public interface SensitiveWordService {
/**
* 校验评论内容是否包含敏感词
*
* @param content 评论内容
*/
void validateCommentContent(String content);
}

View File

@@ -14,6 +14,7 @@ import com.test.musichouduan.repository.PlaylistRepository;
import com.test.musichouduan.repository.SingerRepository;
import com.test.musichouduan.repository.UserRepository;
import com.test.musichouduan.service.CommentService;
import com.test.musichouduan.service.SensitiveWordService;
import org.springframework.messaging.simp.SimpMessagingTemplate; // 添加导入
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -55,6 +56,9 @@ public class CommentServiceImpl implements CommentService {
@Autowired
private SimpMessagingTemplate messagingTemplate; // 注入 SimpMessagingTemplate
@Autowired
private SensitiveWordService sensitiveWordService; // 注入敏感词服务
@Override
public CommentDTO getCommentById(Long id) {
Comment comment = commentRepository.findById(id)
@@ -114,6 +118,9 @@ public class CommentServiceImpl implements CommentService {
User user = userRepository.findById(userId)
.orElseThrow(() -> new BusinessException("用户不存在"));
// 保存前统一校验评论内容,覆盖音乐/歌单/歌手评论及回复评论
sensitiveWordService.validateCommentContent(commentDTO.getContent());
// 创建评论实体
Comment comment = new Comment();
comment.setContent(commentDTO.getContent());

View File

@@ -0,0 +1,109 @@
package com.test.musichouduan.service.impl;
import cn.hutool.dfa.SensitiveUtil;
import com.test.musichouduan.exception.BusinessException;
import com.test.musichouduan.service.SensitiveWordService;
import jakarta.annotation.PostConstruct;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* 敏感词服务实现
*/
@Service
public class SensitiveWordServiceImpl implements SensitiveWordService {
/**
* 服务启动后加载一次词库
*/
@PostConstruct
public void initSensitiveWords() {
List<String> words = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new ClassPathResource("sensitive-words.txt").getInputStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
String word = line.trim();
// 忽略空行和注释行
if (!word.isEmpty() && !word.startsWith("#")) {
words.add(word);
}
}
} catch (Exception e) {
throw new BusinessException("敏感词词库加载失败");
}
// 若词库为空,直接跳过初始化,避免影响正常启动
if (words.isEmpty()) {
return;
}
try {
// 兼容不同版本 Hutool 的 init 方法签名
Method[] methods = SensitiveUtil.class.getMethods();
for (Method method : methods) {
if (!"init".equals(method.getName())) {
continue;
}
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Class<?> type = parameterTypes[0];
if (type.isAssignableFrom(List.class) || type.isAssignableFrom(java.util.Collection.class)) {
method.invoke(null, words);
return;
}
if (type.isArray() && type.getComponentType() == String.class) {
method.invoke(null, (Object) words.toArray(new String[0]));
return;
}
}
if (parameterTypes.length == 2) {
Class<?> firstType = parameterTypes[0];
Class<?> secondType = parameterTypes[1];
if ((firstType.isAssignableFrom(List.class) || firstType.isAssignableFrom(java.util.Collection.class))
&& (secondType == boolean.class || secondType == Boolean.class)) {
// 默认关闭异步,确保启动即生效
method.invoke(null, words, false);
return;
}
}
}
throw new BusinessException("敏感词工具初始化失败");
} catch (BusinessException e) {
throw e;
} catch (Exception e) {
throw new BusinessException("敏感词工具初始化失败");
}
}
@Override
public void validateCommentContent(String content) {
if (content == null || content.trim().isEmpty()) {
return;
}
try {
Method containsMethod = SensitiveUtil.class.getMethod("containsSensitive", String.class);
Object result = containsMethod.invoke(null, content);
boolean hasSensitive = result instanceof Boolean && (Boolean) result;
if (hasSensitive) {
throw new BusinessException("评论包含敏感词,请修改后再发布");
}
} catch (BusinessException e) {
throw e;
} catch (Exception e) {
throw new BusinessException("评论敏感词校验失败");
}
}
}

View File

@@ -0,0 +1,3 @@
# 敏感词词库(每行一个,支持后续自行维护)
# 示例词条:
# 坏词示例