Bladeren bron

Merge remote-tracking branch 'origin/cg_live_dev' into cg_live_dev

chenguo 1 week geleden
bovenliggende
commit
b9c6fc12e9

+ 141 - 0
fs-live-app/src/main/java/com/fs/app/config/ProductionWordFilter.java

@@ -0,0 +1,141 @@
+package com.fs.app.config;
+
+import com.fs.common.utils.spring.SpringUtils;
+import com.fs.live.service.ILiveSensitiveWordsService;
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class ProductionWordFilter implements InitializingBean {
+
+    @Autowired
+    private ILiveSensitiveWordsService liveSensitiveWordsService;
+
+
+    private static class TrieNode {
+        @Getter
+        private final Map<Character, TrieNode> children = new HashMap<>();
+        private boolean isEndOfWord;
+
+        public boolean isEndOfWord() {
+            return isEndOfWord;
+        }
+
+        public void setEndOfWord(boolean endOfWord) {
+            isEndOfWord = endOfWord;
+        }
+
+    }
+    @Getter
+    private static class MatchResult {
+        private final String word;
+        private final int endIndex;
+
+        public MatchResult(String word, int endIndex) {
+            this.word = word;
+            this.endIndex = endIndex;
+        }
+
+        public int getLength() {
+            return word.length();
+        }
+    }
+
+    @Getter
+    public static class FilterResult {
+        private final String filteredText;
+        private final Set<String> matchedWords;
+        private final int replacedCount;
+
+        public FilterResult(String filteredText, Set<String> matchedWords, int replacedCount) {
+            this.filteredText = filteredText;
+            this.matchedWords = matchedWords;
+            this.replacedCount = replacedCount;
+        }
+
+    }
+
+    private TrieNode root = new TrieNode();
+    private List<String> wordSources;
+    private final ScheduledExecutorService executor;
+
+    public ProductionWordFilter(List<String> wordSources) {
+        this.wordSources = wordSources;
+        this.executor = Executors.newSingleThreadScheduledExecutor();
+    }
+
+    @Override
+    public void afterPropertiesSet() {
+        reload();
+        executor.scheduleWithFixedDelay(this::reload, 1, 1, TimeUnit.HOURS);
+    }
+
+    public synchronized void reload() {
+        wordSources = liveSensitiveWordsService.selectAllWords();
+        TrieNode newRoot = new TrieNode();
+        wordSources.stream()
+                .flatMap(source -> loadWords(source).stream())
+                .forEach(word -> addWord(newRoot, word));
+        this.root = newRoot;
+    }
+
+    public FilterResult filter(String text) {
+        StringBuilder result = new StringBuilder();
+        Set<String> foundWords = new HashSet<>();
+        int replacedCount = 0;
+
+        for (int i = 0; i < text.length(); ) {
+            MatchResult match = findNextMatch(text, i);
+            if (match != null) {
+                foundWords.add(match.getWord());
+                result.append(StringUtils.repeat('*', match.getLength()));
+                replacedCount++;
+                i = match.getEndIndex();
+            } else {
+                result.append(text.charAt(i));
+                i++;
+            }
+        }
+
+        return new FilterResult(result.toString(), foundWords, replacedCount);
+    }
+
+
+    private MatchResult findNextMatch(String text, int start) {
+        TrieNode current = root;
+        for (int i = start; i < text.length(); i++) {
+            char c = text.charAt(i);
+            if (!current.getChildren().containsKey(c)) {
+                return null;
+            }
+            current = current.getChildren().get(c);
+            if (current.isEndOfWord()) {
+                return new MatchResult(text.substring(start, i + 1), i + 1);
+            }
+        }
+        return null;
+    }
+
+    private void addWord(TrieNode root, String word) {
+        TrieNode node = root;
+        for (char c : word.toCharArray()) {
+            node = node.getChildren().computeIfAbsent(c, k -> new TrieNode());
+        }
+        node.setEndOfWord(true);
+    }
+
+    private List<String> loadWords(String source) {
+        // 示例:实际应从 source(如 URL 或文件路径)读取
+        return Collections.singletonList(source); // 替换为真实逻辑
+    }
+
+
+}

+ 2 - 0
fs-live-app/src/main/java/com/fs/app/websocket/service/WebSocketServer.java

@@ -44,6 +44,7 @@ public class WebSocketServer {
     private final ILiveWatchUserService liveWatchUserService = SpringUtils.getBean(ILiveWatchUserService.class);
     private final IFsUserService fsUserService = SpringUtils.getBean(IFsUserService.class);
     private final ILiveDataService liveDataService = SpringUtils.getBean(ILiveDataService.class);
+    private final ProductionWordFilter productionWordFilter = SpringUtils.getBean(ProductionWordFilter.class);
     // 直播间在线用户缓存
     //private static final ConcurrentHashMap<Long, Integer> liveOnlineUsers = new ConcurrentHashMap<>();
 
@@ -185,6 +186,7 @@ public class WebSocketServer {
                     sendMessage(session, JSONObject.toJSONString(R.ok().put("data", msg)));
                     break;
                 case "sendMsg":
+                    msg.setMsg(productionWordFilter.filter(msg.getMsg()).getFilteredText());
                     LiveMsg liveMsg = new LiveMsg();
                     liveMsg.setLiveId(msg.getLiveId());
                     liveMsg.setUserId(msg.getUserId());

+ 3 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveSensitiveWordsServiceImpl.java

@@ -1,6 +1,7 @@
 package com.fs.live.service.impl;
 
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -51,6 +52,7 @@ public class LiveSensitiveWordsServiceImpl extends ServiceImpl<LiveSensitiveWord
     @Override
     public int insertLiveSensitiveWords(LiveSensitiveWords liveSensitiveWords)
     {
+        liveSensitiveWords.setCreatedAt(new Date());
         return baseMapper.insertLiveSensitiveWords(liveSensitiveWords);
     }
 
@@ -63,6 +65,7 @@ public class LiveSensitiveWordsServiceImpl extends ServiceImpl<LiveSensitiveWord
     @Override
     public int updateLiveSensitiveWords(LiveSensitiveWords liveSensitiveWords)
     {
+        liveSensitiveWords.setCreatedAt(new Date());
         return baseMapper.updateLiveSensitiveWords(liveSensitiveWords);
     }