diff --git a/README.md b/README.md index f02ad92..4dbcd65 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ```sh # 在解决方案下运行 docker build -t miaoyu:dev-0.0.3 -f src/2-api/HuanMeng.MiaoYu.WebApi/Dockerfile . -docker build -t miaoyu:dev-0.0.3 --build-arg VERSION=7.0 --build-arg TARGET=dev -f src/2-api/HuanMeng.MiaoYu.WebApi/Dockerfile . +docker build -t miaoyu:dev-0.0.4 --build-arg VERSION=7.0 --build-arg TARGET=dev -f src/2-api/HuanMeng.MiaoYu.WebApi/Dockerfile . # 运行 diff --git a/src/0-core/HuanMeng.DotNetCore/TextCensor/SensitiveWord/SensitiveWordFilterFrozen.cs b/src/0-core/HuanMeng.DotNetCore/TextCensor/SensitiveWord/SensitiveWordFilterFrozen.cs new file mode 100644 index 0000000..fcfd5d2 --- /dev/null +++ b/src/0-core/HuanMeng.DotNetCore/TextCensor/SensitiveWord/SensitiveWordFilterFrozen.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace HuanMeng.DotNetCore.TextCensor.SensitiveWord +{ + public class SensitiveWordFilterFrozen : ITextCensor + { + /// + /// 定义Trie树节点 + /// + private class TrieNode + { + /// + /// 标记是否是一个敏感词的结尾 + /// + public bool IsEnd { get; set; } + /// + /// 存储子节点 + /// + public FrozenDictionary Children { get; private set; } + + public TrieNode() + { + IsEnd = false; + Children = null; + } + + /// + /// 将子节点字典冻结为 FrozenDictionary + /// + public void FreezeChildren(Dictionary children) + { + Children = children.ToFrozenDictionary(); + } + } + + /// + /// 根节点 + /// + private TrieNode Root { get; set; } + + public SensitiveWordFilterFrozen() + { + Root = new TrieNode(); + } + + /// + /// 添加敏感词到Trie树中 + /// + /// + public void AddSensitiveWord(string word) + { + TrieNode currentNode = Root; + word = CleanText(word); + foreach (char c in word.ToLower()) + { + // 如果当前字符不存在于子节点中,则添加 + if (currentNode.Children == null || !currentNode.Children.ContainsKey(c)) + { + var children = currentNode.Children?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? new Dictionary(); + children[c] = new TrieNode(); + currentNode.FreezeChildren(children); + } + currentNode = currentNode.Children[c]; + } + currentNode.IsEnd = true; // 标记当前节点为敏感词结尾 + } + + /// + /// 清理文字 + /// + /// + /// + public string CleanText(string sourceTxt) + { + if (string.IsNullOrEmpty(sourceTxt)) + { + return string.Empty; + } + + string cleanedText = sourceTxt + .Replace(',', ' ') + .Replace('.', ' ') + .Replace('。', ' ') + .Replace(',', ' ') + .Replace('@', ' ') + .Replace('-', ' ') + .Replace('*', ' ') + .Replace("1", string.Empty) + .Replace("2", string.Empty) + .Replace("3", string.Empty) + .Replace("4", string.Empty) + .Replace("5", string.Empty) + .Replace("6", string.Empty) + .Replace("9", string.Empty) + .Replace("0", string.Empty) + .Replace("_", string.Empty) + .Replace(" ", string.Empty).ToLower(); + return cleanedText; + } + + /// + /// 判断文本中是否包含敏感词 + /// + /// + /// + public bool ContainsSensitiveWord(string text) + { + //过滤字符串 + text = CleanText(text); + for (int i = 0; i < text.Length; i++) + { + TrieNode currentNode = Root; + int j = i; + // 从当前位置开始匹配敏感词 + while (j < text.Length && currentNode.Children != null && currentNode.Children.ContainsKey(text[j])) + { + currentNode = currentNode.Children[text[j]]; + // 如果当前节点是敏感词结尾,返回true + if (currentNode.IsEnd) + { + return true; + } + j++; + } + } + return false; + } + + public bool TextCensor(string text) + { + return ContainsSensitiveWord(text); + } + + public Task TextCensorAsync(string text) + { + return Task.Run(() => + { + return ContainsSensitiveWord(text); + }); + + } + } +} diff --git a/src/0-core/HuanMeng.DotNetCore/TextCensor/TextCensorExtend.cs b/src/0-core/HuanMeng.DotNetCore/TextCensor/TextCensorExtend.cs index c129f92..f5e2254 100644 --- a/src/0-core/HuanMeng.DotNetCore/TextCensor/TextCensorExtend.cs +++ b/src/0-core/HuanMeng.DotNetCore/TextCensor/TextCensorExtend.cs @@ -24,8 +24,12 @@ namespace HuanMeng.DotNetCore.TextCensor public static ITextCensor GetITextCensor(string _dirPath) { - return GetSensitiveWordFilter(_dirPath); + return GetSensitiveWordFilterFrozen(_dirPath) + //GetSensitiveWordFilter(_dirPath) + ; } + + /// /// /// @@ -43,6 +47,50 @@ namespace HuanMeng.DotNetCore.TextCensor return sensitiveWordFilter; } + /// + /// + /// + /// + /// + public static SensitiveWordFilterFrozen GetSensitiveWordFilterFrozen(string _dirPath) + { + SensitiveWordFilterFrozen sensitiveWordFilter = new SensitiveWordFilterFrozen(); + var ckPath = Path.GetFullPath(_dirPath); + var filePath = Directory.EnumerateFiles(ckPath); + foreach (var item in filePath) + { + AddShieldString(item, sensitiveWordFilter); + } + return sensitiveWordFilter; + } + + /// + /// + /// + /// + /// + public static void AddShieldString(string path, SensitiveWordFilterFrozen sensitiveWordFilter) + { + + if (!File.Exists(path)) + { + throw new Exception("文件不存在"); + } + using (StreamReader reader = new StreamReader(path, UnicodeEncoding.UTF8)) + { + + while (reader.Peek() > 0) + { + + var tempStr = (reader.ReadLine() ?? ""); + if (!string.IsNullOrEmpty(tempStr)) + { + sensitiveWordFilter.AddSensitiveWord(tempStr); + + } + } + } + } /// /// /// @@ -68,8 +116,6 @@ namespace HuanMeng.DotNetCore.TextCensor } } - - } } } diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Cache/MiaoYuCache.cs b/src/0-core/HuanMeng.MiaoYu.Code/Cache/MiaoYuCache.cs index d2d05b0..6a655aa 100644 --- a/src/0-core/HuanMeng.MiaoYu.Code/Cache/MiaoYuCache.cs +++ b/src/0-core/HuanMeng.MiaoYu.Code/Cache/MiaoYuCache.cs @@ -162,6 +162,30 @@ namespace HuanMeng.MiaoYu.Code.Cache } #endregion + + #region 角色类型缓存表 + + + /// + /// 菜单类型缓存表 + /// + public CommonDataEntityCache? _category_Child_Menu { get; set; } + /// + /// 菜单类型的角色 + /// + public List CategoryChildMenuList + { + get + { + if (_category_Child_Menu == null) + { + _category_Child_Menu = MiaoYuCacheExtend.GetMiaoYuDataEntityCache(cacheBase, expWhere: it => it.IsEnabled); + } + return _category_Child_Menu.DataList ?? new List(); + } + } + + #endregion } /// /// 缓存扩展类 diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Category/CategoryBLL.cs b/src/0-core/HuanMeng.MiaoYu.Code/Category/CategoryBLL.cs index 96db245..a3a8658 100644 --- a/src/0-core/HuanMeng.MiaoYu.Code/Category/CategoryBLL.cs +++ b/src/0-core/HuanMeng.MiaoYu.Code/Category/CategoryBLL.cs @@ -69,7 +69,8 @@ namespace HuanMeng.MiaoYu.Code.Category public BaseResponse>> GetRecommendList() { List> recommendDtos = new List>(); - var menuList = Dao.daoDbMiaoYu.context.T_Category_Child_Menu.Where(it => it.IsEnabled).ToList(); + + var menuList = MiaoYuCache.CategoryChildMenuList.Where(it => it.IsEnabled).ToList(); var node = DictionaryInfo.GetDictionariesChildNode(T_Sys_DictionaryEnum.categorymenu); node.ForEach(_node => { @@ -85,59 +86,6 @@ namespace HuanMeng.MiaoYu.Code.Category recommendDtos.Add(banner); } }); - //#region 假数据 - //RecommendDto banner = new RecommendDto(); - //banner.Title = "Banner"; - //banner.Type = RecommendTypeEnum.banner.ToString(); - //banner.Data = new List(); - //banner.Data.Add(new CommonRecommendData - //{ - // ActionId = "1", - // ActionType = RecommendActionTypeEnum.Mall.ToString(), - // ImageUrl = "https://cos.shhuanmeng.com/banner/20240717214627.png", - //}); - //banner.Data.Add(new CommonRecommendData - //{ - // ActionId = "2", - // ActionType = RecommendActionTypeEnum.Page.ToString(), - // ImageUrl = "https://cos.shhuanmeng.com/banner/202407172146272.png", - //}); - //banner.Data.Add(new CommonRecommendData - //{ - // ActionId = "3", - // ActionType = RecommendActionTypeEnum.Chat.ToString(), - // ImageUrl = "https://cos.shhuanmeng.com/banner/20240717214735.png", - //}); - //recommendDtos.Add(banner); - //RecommendDto tuijian = new RecommendDto(); - //tuijian.Title = "推荐"; - //tuijian.Type = RecommendTypeEnum.tuijian.ToString(); - //tuijian.Data = new List(); - - - //RecommendDto xiaoshuo = new RecommendDto(); - //xiaoshuo.Data = new List(); - //xiaoshuo.Title = "小说"; - //xiaoshuo.Type = RecommendTypeEnum.xiaoshuo.ToString(); - //int index = 0; - //MiaoYuCache.CharacterList.ForEach(x => - //{ - // if (index > 5) - // { - // return; - // } - // var data = Mapper.Map(x); - // data.ActionType = RecommendActionTypeEnum.Chat.ToString(); - // data.ActionId = data.Id.ToString(); - // data.ImageUrl = x.BgImage;//data.BgImage; - - // tuijian.Data.Add(data); - // xiaoshuo.Data.Add(data); - // index++; - //}); - //recommendDtos.Add(tuijian); - //recommendDtos.Add(xiaoshuo); - //#endregion return new BaseResponse>>(ResonseCode.Success, "", recommendDtos); } } diff --git a/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs b/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs index 2e511f1..c5db5ac 100644 --- a/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs +++ b/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs @@ -64,6 +64,9 @@ builder.Services.AddControllers() options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; // 忽略循环引用 options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();// 首字母小写(驼峰样式) options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";// 时间格式化 + #if !DEBUG + options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.None; + #endif //options.SerializerSettings.Converters.Add() // 其他配置... }) @@ -155,7 +158,7 @@ app.UseAuthorization(); //使用跨域 app.UseCors(_myAllowSpecificOrigins); app.MapControllers(); - + app.UseStaticFiles();//静态文件访问配置 //数据库中间件 app.UseMultiTenantMiaoYu(); @@ -187,4 +190,4 @@ app.MapGet("/system", () => }; }).WithName("获取系统数据"); #endregion - app.Run(); +app.Run(); diff --git a/src/9-test/TextCensorFilterTest/SensitiveWordFilterTest.cs b/src/9-test/TextCensorFilterTest/SensitiveWordFilterTest.cs index 3d398e6..b8f02c1 100644 --- a/src/9-test/TextCensorFilterTest/SensitiveWordFilterTest.cs +++ b/src/9-test/TextCensorFilterTest/SensitiveWordFilterTest.cs @@ -14,6 +14,7 @@ namespace TextCensorFilterTest [MemoryDiagnoser] public class SensitiveWordFilterTest { + public SensitiveWordFilterTest() { string path = "DataStorage/TextCensor/"; @@ -21,22 +22,56 @@ namespace TextCensorFilterTest { sensitiveWordFilter = TextCensorExtend.GetSensitiveWordFilter(path); } + if (sensitiveWordFilterFrozen == null) + { + sensitiveWordFilterFrozen = TextCensorExtend.GetSensitiveWordFilterFrozen(path); + } + //CheckTextVerification.VerifyTxtString(""); } - SensitiveWordFilter sensitiveWordFilter = null; + SensitiveWordFilter sensitiveWordFilter = null; + SensitiveWordFilterFrozen sensitiveWordFilterFrozen = null; [Benchmark] public bool SensitiveWordFiltermax() { return sensitiveWordFilter.TextCensor("*林婉儿面露疑惑之色,你突然来这么一声问候,实在令她有些摸不着头脑。作为一位淑女,她自是明白礼数之重要性的。见你竟三番两次地打断了她们之间正在深入的对话,不禁蹙起秀眉,神色间略带不悦。* \"阁下这般反复无常,却是何意?\"她语气平和,却不无不满,\"我们方才正在讨论魔兽山脉的来历,你也说了许多让婉儿费解的奇闻逸事。我正渴望能从你这里获知更多有益的解惑呢。\" *她优雅地抿了一口香茶,似在给自己一些缓冲的时间*\"不知阁下可曾见过其他游历山川的高人?他们对于这处所在是否也有过非同寻常的评说?又或是流传下来的什么古老传闻?\" *说着,她的目光缓缓流转,最终重新落在你的身上,眸中满怀期盼之色*\"若阁下实在没什么更多可说的了,不若就让我回忆起从前所读所闻,慢慢为你道来一二吧?或许还能给你带来一些新的启发。\""); } - + [Benchmark] + public bool SensitiveWordFiltermaxs() + { + var b = false; + for (int i = 0; i < 10; i++) + { + b = sensitiveWordFilter.TextCensor("*林婉儿面露疑惑之色,你突然来这么一声问候,实在令她有些摸不着头脑。作为一位淑女,她自是明白礼数之重要性的。见你竟三番两次地打断了她们之间正在深入的对话,不禁蹙起秀眉,神色间略带不悦。* \"阁下这般反复无常,却是何意?\"她语气平和,却不无不满,\"我们方才正在讨论魔兽山脉的来历,你也说了许多让婉儿费解的奇闻逸事。我正渴望能从你这里获知更多有益的解惑呢。\" *她优雅地抿了一口香茶,似在给自己一些缓冲的时间*\"不知阁下可曾见过其他游历山川的高人?他们对于这处所在是否也有过非同寻常的评说?又或是流传下来的什么古老传闻?\" *说着,她的目光缓缓流转,最终重新落在你的身上,眸中满怀期盼之色*\"若阁下实在没什么更多可说的了,不若就让我回忆起从前所读所闻,慢慢为你道来一二吧?或许还能给你带来一些新的启发。\""); + } + return b; + } [Benchmark] public bool SensitiveWordFilter() { return sensitiveWordFilter.TextCensor("*林婉儿面露疑惑之色,"); } + [Benchmark] + public bool SensitiveWordFiltermaxFrozen() + { + return sensitiveWordFilterFrozen.TextCensor("*林婉儿面露疑惑之色,你突然来这么一声问候,实在令她有些摸不着头脑。作为一位淑女,她自是明白礼数之重要性的。见你竟三番两次地打断了她们之间正在深入的对话,不禁蹙起秀眉,神色间略带不悦。* \"阁下这般反复无常,却是何意?\"她语气平和,却不无不满,\"我们方才正在讨论魔兽山脉的来历,你也说了许多让婉儿费解的奇闻逸事。我正渴望能从你这里获知更多有益的解惑呢。\" *她优雅地抿了一口香茶,似在给自己一些缓冲的时间*\"不知阁下可曾见过其他游历山川的高人?他们对于这处所在是否也有过非同寻常的评说?又或是流传下来的什么古老传闻?\" *说着,她的目光缓缓流转,最终重新落在你的身上,眸中满怀期盼之色*\"若阁下实在没什么更多可说的了,不若就让我回忆起从前所读所闻,慢慢为你道来一二吧?或许还能给你带来一些新的启发。\""); + } - + [Benchmark] + public bool SensitiveWordFilterFrozen() + { + return sensitiveWordFilterFrozen.TextCensor("*林婉儿面露疑惑之色,"); + } + [Benchmark] + public bool SensitiveWordFilterFrozens() + { + var b = false; + for (int i = 0; i < 10; i++) + { + b = sensitiveWordFilterFrozen.TextCensor("*林婉儿面露疑惑之色,你突然来这么一声问候,实在令她有些摸不着头脑。作为一位淑女,她自是明白礼数之重要性的。见你竟三番两次地打断了她们之间正在深入的对话,不禁蹙起秀眉,神色间略带不悦。* \"阁下这般反复无常,却是何意?\"她语气平和,却不无不满,\"我们方才正在讨论魔兽山脉的来历,你也说了许多让婉儿费解的奇闻逸事。我正渴望能从你这里获知更多有益的解惑呢。\" *她优雅地抿了一口香茶,似在给自己一些缓冲的时间*\"不知阁下可曾见过其他游历山川的高人?他们对于这处所在是否也有过非同寻常的评说?又或是流传下来的什么古老传闻?\" *说着,她的目光缓缓流转,最终重新落在你的身上,眸中满怀期盼之色*\"若阁下实在没什么更多可说的了,不若就让我回忆起从前所读所闻,慢慢为你道来一二吧?或许还能给你带来一些新的启发。\""); + } + return b; + } } }