package com.sinata.appointment.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.sinata.appointment.constants.CacheNames; import com.sinata.appointment.entity.BizSensitiveWord; import com.sinata.appointment.mapper.BizSensitiveWordMapper; import java.util.Comparator; import java.util.List; import java.util.Locale; import lombok.RequiredArgsConstructor; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @Service @RequiredArgsConstructor public class SensitiveWordFilterService { private final BizSensitiveWordMapper bizSensitiveWordMapper; private final CacheManager cacheManager; public String filter(String text) { if (!StringUtils.hasText(text)) { return text; } List words = enabledWords(); if (words.isEmpty()) { return text; } String result = text; for (String word : words) { result = replaceIgnoreCase(result, word); } return result; } public void evictCache() { Cache cache = cacheManager.getCache(CacheNames.BIZ_SENSITIVE_WORD); if (cache != null) { cache.evict(CacheNames.BIZ_SENSITIVE_WORD_ENABLED_KEY); } } @SuppressWarnings("unchecked") public List enabledWords() { Cache cache = cacheManager.getCache(CacheNames.BIZ_SENSITIVE_WORD); if (cache != null) { Cache.ValueWrapper cached = cache.get(CacheNames.BIZ_SENSITIVE_WORD_ENABLED_KEY); if (cached != null && cached.get() instanceof List list) { return (List) list; } } List words = bizSensitiveWordMapper .selectList( new LambdaQueryWrapper() .eq(BizSensitiveWord::getDelFlag, 0) .eq(BizSensitiveWord::getEnabled, 1)) .stream() .map(BizSensitiveWord::getWord) .filter(StringUtils::hasText) .map(String::trim) .distinct() .sorted(Comparator.comparingInt(String::length).reversed()) .toList(); if (cache != null) { cache.put(CacheNames.BIZ_SENSITIVE_WORD_ENABLED_KEY, words); } return words; } private String replaceIgnoreCase(String source, String word) { if (!StringUtils.hasText(source) || !StringUtils.hasText(word)) { return source; } String lowerSource = source.toLowerCase(Locale.ROOT); String lowerWord = word.toLowerCase(Locale.ROOT); StringBuilder builder = new StringBuilder(source.length()); int cursor = 0; int matchIndex = lowerSource.indexOf(lowerWord, cursor); while (matchIndex >= 0) { builder.append(source, cursor, matchIndex); builder.append("*".repeat(word.length())); cursor = matchIndex + word.length(); matchIndex = lowerSource.indexOf(lowerWord, cursor); } builder.append(source, cursor, source.length()); return builder.toString(); } }