diff --git a/music-houduan/src/main/java/com/test/musichouduan/service/SensitiveWordService.java b/music-houduan/src/main/java/com/test/musichouduan/service/SensitiveWordService.java new file mode 100644 index 0000000..fd613e9 --- /dev/null +++ b/music-houduan/src/main/java/com/test/musichouduan/service/SensitiveWordService.java @@ -0,0 +1,14 @@ +package com.test.musichouduan.service; + +/** + * 敏感词服务接口 + */ +public interface SensitiveWordService { + + /** + * 校验评论内容是否包含敏感词 + * + * @param content 评论内容 + */ + void validateCommentContent(String content); +} diff --git a/music-houduan/src/main/java/com/test/musichouduan/service/impl/CommentServiceImpl.java b/music-houduan/src/main/java/com/test/musichouduan/service/impl/CommentServiceImpl.java index 9b2c8a2..fdfa260 100644 --- a/music-houduan/src/main/java/com/test/musichouduan/service/impl/CommentServiceImpl.java +++ b/music-houduan/src/main/java/com/test/musichouduan/service/impl/CommentServiceImpl.java @@ -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()); diff --git a/music-houduan/src/main/java/com/test/musichouduan/service/impl/SensitiveWordServiceImpl.java b/music-houduan/src/main/java/com/test/musichouduan/service/impl/SensitiveWordServiceImpl.java new file mode 100644 index 0000000..f3adee2 --- /dev/null +++ b/music-houduan/src/main/java/com/test/musichouduan/service/impl/SensitiveWordServiceImpl.java @@ -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 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("评论敏感词校验失败"); + } + } +} diff --git a/music-houduan/src/main/resources/sensitive-words.txt b/music-houduan/src/main/resources/sensitive-words.txt new file mode 100644 index 0000000..8826d0e --- /dev/null +++ b/music-houduan/src/main/resources/sensitive-words.txt @@ -0,0 +1,3 @@ +# 敏感词词库(每行一个,支持后续自行维护) +# 示例词条: +# 坏词示例