OpenSource - 基于 DFA 算法实现的高性能 java 敏感词过滤工具框架

本文主要是介绍OpenSource - 基于 DFA 算法实现的高性能 java 敏感词过滤工具框架,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • sensitive-word
    • 创作目的
    • 特性
    • 变更日志
    • 更多资料
      • 敏感词控台
      • 敏感词标签文件
  • 快速开始
    • 准备
    • Maven 引入
    • 核心方法
      • 判断是否包含敏感词
      • 返回第一个敏感词
      • 返回所有敏感词
      • 默认的替换策略
      • 指定替换的内容
      • 自定义替换策略
    • IWordResultHandler 结果处理类
      • 使用实例
  • 更多特性
    • 样式处理
      • 忽略大小写
      • 忽略半角圆角
      • 忽略数字的写法
      • 忽略繁简体
      • 忽略英文的书写格式
      • 忽略重复词
    • 更多检测策略
      • 邮箱检测
      • 连续数字检测
      • 网址检测
  • 引导类特性配置
    • 说明
    • 配置方法
    • 配置说明
  • 忽略字符
    • 说明
    • 例子
  • 敏感词标签
    • 说明
    • 入门例子
      • 接口
      • 配置文件
      • 实现
  • 动态加载(用户自定义)
    • 情景说明
    • 接口说明
      • IWordDeny
      • IWordAllow
    • 配置使用
      • 系统的默认配置
      • 指定自己的实现
      • 同时配置多个
  • spring 整合
    • 背景
    • 自定义数据源
    • 动态变更
  • Benchmark
    • 环境
    • 测试效果记录
  • 后期 road-map
  • 拓展阅读
  • NLP 开源矩阵

在这里插入图片描述


sensitive-word

sensitive-word 基于 DFA 算法实现的高性能敏感词工具。

The sensitive word tool for java.(敏感词/违禁词/违法词/脏词。基于 DFA 算法实现的高性能 java 敏感词过滤工具框架。请勿发布涉及政治、广告、营销、翻墙、违反国家法律法规等内容。高性能敏感词检测过滤组件,附带繁体简体互换,支持全角半角互换,汉字转拼音,模糊搜索等功能。)

在这里插入图片描述

在线体验

创作目的

实现一款好用敏感词工具。

基于 DFA 算法实现,目前敏感词库内容收录 6W+(源文件 18W+,经过一次删减)。

后期将进行持续优化和补充敏感词库,并进一步提升算法的性能。

希望可以细化敏感词的分类,感觉工作量比较大,暂时没有进行。

特性

  • 6W+ 词库,且不断优化更新

  • 基于 fluent-api 实现,使用优雅简洁

  • 基于 DFA 算法,性能为 7W+ QPS,应用无感

  • 支持敏感词的判断、返回、脱敏等常见操作

  • 支持常见的格式转换

全角半角互换、英文大小写互换、数字常见形式的互换、中文繁简体互换、英文常见形式的互换、忽略重复词等

  • 支持敏感词检测、邮箱检测、数字检测、网址检测等

  • 支持自定义替换策略

  • 支持用户自定义敏感词和白名单

  • 支持数据的数据动态更新(用户自定义),实时生效

  • 支持敏感词的标签接口

  • 支持跳过一些特殊字符,让匹配更灵活

变更日志

CHANGE_LOG.md

更多资料

敏感词控台

有时候敏感词有一个控台,配置起来会更加灵活方便。

java 如何实现开箱即用的敏感词控台服务?

敏感词标签文件

梳理了大量的敏感词标签文件,可以让我们的敏感词更加方便。

这两个资料阅读可在下方文章获取:

v0.11.0-敏感词新特性及对应标签文件

快速开始

准备

  • JDK1.7+

  • Maven 3.x+

Maven 引入

<dependency><groupId>com.github.houbb</groupId><artifactId>sensitive-word</artifactId><version>0.12.0</version>
</dependency>

核心方法

SensitiveWordHelper 作为敏感词的工具类,核心方法如下:

方法参数返回值说明
contains(String)待验证的字符串布尔值验证字符串是否包含敏感词
replace(String, ISensitiveWordReplace)使用指定的替换策略替换敏感词字符串返回脱敏后的字符串
replace(String, char)使用指定的 char 替换敏感词字符串返回脱敏后的字符串
replace(String)使用 * 替换敏感词字符串返回脱敏后的字符串
findAll(String)待验证的字符串字符串列表返回字符串中所有敏感词
findFirst(String)待验证的字符串字符串返回字符串中第一个敏感词
findAll(String, IWordResultHandler)IWordResultHandler 结果处理类字符串列表返回字符串中所有敏感词
findFirst(String, IWordResultHandler)IWordResultHandler 结果处理类字符串返回字符串中第一个敏感词
tags(String)获取敏感词的标签敏感词字符串返回敏感词的标签列表

判断是否包含敏感词

final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";Assert.assertTrue(SensitiveWordHelper.contains(text));

返回第一个敏感词

final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";String word = SensitiveWordHelper.findFirst(text);
Assert.assertEquals("五星红旗", word);

SensitiveWordHelper.findFirst(text) 等价于:

String word = SensitiveWordHelper.findFirst(text, WordResultHandlers.word());

WordResultHandlers.raw() 可以保留对应的下标信息:

final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";IWordResult word = SensitiveWordHelper.findFirst(text, WordResultHandlers.raw());
Assert.assertEquals("WordResult{startIndex=0, endIndex=4}", word.toString());

返回所有敏感词

final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";List<String> wordList = SensitiveWordHelper.findAll(text);
Assert.assertEquals("[五星红旗, 毛主席, 天安门]", wordList.toString());

返回所有敏感词用法上类似于 SensitiveWordHelper.findFirst(),同样也支持指定结果处理类。

SensitiveWordHelper.findAll(text) 等价于:

List<String> wordList = SensitiveWordHelper.findAll(text, WordResultHandlers.word());

WordResultHandlers.raw() 可以保留对应的下标信息:

final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";List<IWordResult> wordList = SensitiveWordHelper.findAll(text, WordResultHandlers.raw());
Assert.assertEquals("[WordResult{startIndex=0, endIndex=4}, WordResult{startIndex=9, endIndex=12}, WordResult{startIndex=18, endIndex=21}]", wordList.toString());

默认的替换策略

final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
String result = SensitiveWordHelper.replace(text);
Assert.assertEquals("****迎风飘扬,***的画像屹立在***前。", result);

指定替换的内容

final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
String result = SensitiveWordHelper.replace(text, '0');
Assert.assertEquals("0000迎风飘扬,000的画像屹立在000前。", result);

自定义替换策略

V0.2.0 支持该特性。

场景说明:有时候我们希望不同的敏感词有不同的替换结果。比如【游戏】替换为【电子竞技】,【失业】替换为【灵活就业】。

诚然,提前使用字符串的正则替换也可以,不过性能一般。

使用例子:

/*** 自定替换策略* @since 0.2.0*/
@Test
public void defineReplaceTest() {final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";ISensitiveWordReplace replace = new MySensitiveWordReplace();String result = SensitiveWordHelper.replace(text, replace);Assert.assertEquals("国家旗帜迎风飘扬,教员的画像屹立在***前。", result);
}

其中 MySensitiveWordReplace 是我们自定义的替换策略,实现如下:

public class MyWordReplace implements IWordReplace {@Overridepublic void replace(StringBuilder stringBuilder, final char[] rawChars, IWordResult wordResult, IWordContext wordContext) {String sensitiveWord = InnerWordCharUtils.getString(rawChars, wordResult);// 自定义不同的敏感词替换策略,可以从数据库等地方读取if("五星红旗".equals(sensitiveWord)) {stringBuilder.append("国家旗帜");} else if("毛主席".equals(sensitiveWord)) {stringBuilder.append("教员");} else {// 其他默认使用 * 代替int wordLength = wordResult.endIndex() - wordResult.startIndex();for(int i = 0; i < wordLength; i++) {stringBuilder.append('*');}}}}

我们针对其中的部分词做固定映射处理,其他的默认转换为 *

IWordResultHandler 结果处理类

IWordResultHandler 可以对敏感词的结果进行处理,允许用户自定义。

内置实现见 WordResultHandlers 工具类:

  • WordResultHandlers.word()

只保留敏感词单词本身。

  • WordResultHandlers.raw()

保留敏感词相关信息,包含敏感词的开始和结束下标。

  • WordResultHandlers.wordTags()

同时保留单词,和对应的词标签信息。

使用实例

所有测试案例参见 SensitiveWordHelperTest

1)基本例子

final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";List<String> wordList = SensitiveWordHelper.findAll(text);
Assert.assertEquals("[五星红旗, 毛主席, 天安门]", wordList.toString());
List<String> wordList2 = SensitiveWordHelper.findAll(text, WordResultHandlers.word());
Assert.assertEquals("[五星红旗, 毛主席, 天安门]", wordList2.toString());List<IWordResult> wordList3 = SensitiveWordHelper.findAll(text, WordResultHandlers.raw());
Assert.assertEquals("[WordResult{startIndex=0, endIndex=4}, WordResult{startIndex=9, endIndex=12}, WordResult{startIndex=18, endIndex=21}]", wordList3.toString());
  1. wordTags 例子

我们在 dict_tag_test.txt 文件中指定对应词的标签信息。

final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";// 默认敏感词标签为空
List<WordTagsDto> wordList1 = SensitiveWordHelper.findAll(text, WordResultHandlers.wordTags());
Assert.assertEquals("[WordTagsDto{word='五星红旗', tags=[]}, WordTagsDto{word='毛主席', tags=[]}, WordTagsDto{word='天安门', tags=[]}]", wordList1.toString());List<WordTagsDto> wordList2 = SensitiveWordBs.newInstance().wordTag(WordTags.file("dict_tag_test.txt")).init().findAll(text, WordResultHandlers.wordTags());
Assert.assertEquals("[WordTagsDto{word='五星红旗', tags=[政治, 国家]}, WordTagsDto{word='毛主席', tags=[政治, 伟人, 国家]}, WordTagsDto{word='天安门', tags=[政治, 国家, 地址]}]", wordList2.toString());

更多特性

后续的诸多特性,主要是针对各种针对各种情况的处理,尽可能的提升敏感词命中率。

这是一场漫长的攻防之战。

样式处理

忽略大小写

final String text = "fuCK the bad words.";String word = SensitiveWordHelper.findFirst(text);
Assert.assertEquals("fuCK", word);

忽略半角圆角

final String text = "fuck the bad words.";String word = SensitiveWordHelper.findFirst(text);
Assert.assertEquals("fuck", word);

忽略数字的写法

这里实现了数字常见形式的转换。

final String text = "这个是我的微信:9⓿二肆⁹₈③⑸⒋➃㈤㊄";List<String> wordList = SensitiveWordHelper.findAll(text);
Assert.assertEquals("[9⓿二肆⁹₈③⑸⒋➃㈤㊄]", wordList.toString());

忽略繁简体

final String text = "我爱我的祖国和五星紅旗。";List<String> wordList = SensitiveWordHelper.findAll(text);
Assert.assertEquals("[五星紅旗]", wordList.toString());

忽略英文的书写格式

final String text = "Ⓕⓤc⒦ the bad words";List<String> wordList = SensitiveWordHelper.findAll(text);
Assert.assertEquals("[Ⓕⓤc⒦]", wordList.toString());

忽略重复词

final String text = "ⒻⒻⒻfⓤuⓤ⒰cⓒ⒦ the bad words";List<String> wordList = SensitiveWordBs.newInstance().ignoreRepeat(true).init().findAll(text);
Assert.assertEquals("[ⒻⒻⒻfⓤuⓤ⒰cⓒ⒦]", wordList.toString());

更多检测策略

邮箱检测

final String text = "楼主好人,邮箱 sensitiveword@xx.com";List<String> wordList = SensitiveWordHelper.findAll(text);
Assert.assertEquals("[sensitiveword@xx.com]", wordList.toString());

连续数字检测

一般用于过滤手机号/QQ等广告信息。

V0.2.1 之后,支持通过 numCheckLen(长度) 自定义检测的长度。

final String text = "你懂得:12345678";// 默认检测 8 位
List<String> wordList = SensitiveWordBs.newInstance().init().findAll(text);
Assert.assertEquals("[12345678]", wordList.toString());// 指定数字的长度,避免误杀
List<String> wordList2 = SensitiveWordBs.newInstance().numCheckLen(9).init().findAll(text);
Assert.assertEquals("[]", wordList2.toString());

网址检测

用于过滤常见的网址信息。

final String text = "点击链接 www.baidu.com查看答案";List<String> wordList = SensitiveWordBs.newInstance().init().findAll(text);
Assert.assertEquals("[链接, www.baidu.com]", wordList.toString());Assert.assertEquals("点击** *************查看答案", SensitiveWordBs.newInstance().init().replace(text));

引导类特性配置

说明

上面的特性默认都是开启的,有时业务需要灵活定义相关的配置特性。

所以 v0.0.14 开放了属性配置。

配置方法

为了让使用更加优雅,统一使用 fluent-api 的方式定义。

用户可以使用 SensitiveWordBs 进行如下定义:

SensitiveWordBs wordBs = SensitiveWordBs.newInstance().ignoreCase(true).ignoreWidth(true).ignoreNumStyle(true).ignoreChineseStyle(true).ignoreEnglishStyle(true).ignoreRepeat(false).enableNumCheck(true).enableEmailCheck(true).enableUrlCheck(true).enableWordCheck(true).numCheckLen(8).wordTag(WordTags.none()).charIgnore(SensitiveWordCharIgnores.defaults()).init();final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
Assert.assertTrue(wordBs.contains(text));

配置说明

其中各项配置的说明如下:

序号方法说明默认值
1ignoreCase忽略大小写true
2ignoreWidth忽略半角圆角true
3ignoreNumStyle忽略数字的写法true
4ignoreChineseStyle忽略中文的书写格式true
5ignoreEnglishStyle忽略英文的书写格式true
6ignoreRepeat忽略重复词false
7enableNumCheck是否启用数字检测。true
8enableEmailCheck是有启用邮箱检测true
9enableUrlCheck是否启用链接检测true
10enableWordCheck是否启用敏感单词检测true
11numCheckLen数字检测,自定义指定长度。8
12wordTag词对应的标签none
13charIgnore忽略的字符none

忽略字符

说明

我们的敏感词一般都是比较连续的,比如【傻帽】

那就有大聪明发现,可以在中间加一些字符,比如【傻!@#$帽】跳过检测,但是骂人等攻击力不减。

那么,如何应对这些类似的场景呢?

我们可以指定特殊字符的跳过集合,忽略掉这些无意义的字符即可。

v0.11.0 开始支持

例子

其中 charIgnore 对应的字符策略,用户可以自行灵活定义。

final String text = "傻@冒,狗+东西";//默认因为有特殊字符分割,无法识别
List<String> wordList = SensitiveWordBs.newInstance().init().findAll(text);
Assert.assertEquals("[]", wordList.toString());// 指定忽略的字符策略,可自行实现。
List<String> wordList2 = SensitiveWordBs.newInstance().charIgnore(SensitiveWordCharIgnores.specialChars()).init().findAll(text);Assert.assertEquals("[傻@冒, 狗+东西]", wordList2.toString());

敏感词标签

说明

有时候我们希望对敏感词加一个分类标签:比如社情、暴/力等等。

这样后续可以按照标签等进行更多特性操作,比如只处理某一类的标签。

支持版本:v0.10.0

入门例子

接口

这里只是一个抽象的接口,用户可以自行定义实现。比如从数据库查询等。

public interface IWordTag {/*** 查询标签列表* @param word 脏词* @return 结果*/Set<String> getTag(String word);}

配置文件

我们可以自定义 dict 标签文件,通过 WordTags.file() 创建一个 WordTag 实现。

  • dict_tag_test.txt
五星红旗 政治,国家

格式如下:

敏感词 tag1,tag2

实现

具体的效果如下,在引导类设置一下即可。

默认的 wordTag 是空的。

String filePath = "dict_tag_test.txt";
IWordTag wordTag = WordTags.file(filePath);SensitiveWordBs sensitiveWordBs = SensitiveWordBs.newInstance().wordTag(wordTag).init();Assert.assertEquals("[政治, 国家]", sensitiveWordBs.tags("五星红旗").toString());;

后续会考虑引入一个内置的标签文件策略。

动态加载(用户自定义)

情景说明

有时候我们希望将敏感词的加载设计成动态的,比如控台修改,然后可以实时生效。

v0.0.13 支持了这种特性。

接口说明

为了实现这个特性,并且兼容以前的功能,我们定义了两个接口。

IWordDeny

接口如下,可以自定义自己的实现。

返回的列表,表示这个词是一个敏感词。

/*** 拒绝出现的数据-返回的内容被当做是敏感词* @author binbin.hou* @since 0.0.13*/
public interface IWordDeny {/*** 获取结果* @return 结果* @since 0.0.13*/List<String> deny();}

比如:

public class MyWordDeny implements IWordDeny {@Overridepublic List<String> deny() {return Arrays.asList("我的自定义敏感词");}}

IWordAllow

接口如下,可以自定义自己的实现。

返回的列表,表示这个词不是一个敏感词。

/*** 允许的内容-返回的内容不被当做敏感词* @author binbin.hou* @since 0.0.13*/
public interface IWordAllow {/*** 获取结果* @return 结果* @since 0.0.13*/List<String> allow();}

如:

public class MyWordAllow implements IWordAllow {@Overridepublic List<String> allow() {return Arrays.asList("五星红旗");}}

配置使用

接口自定义之后,当然需要指定才能生效。

为了让使用更加优雅,我们设计了引导类 SensitiveWordBs

可以通过 wordDeny() 指定敏感词,wordAllow() 指定非敏感词,通过 init() 初始化敏感词字典。

系统的默认配置

SensitiveWordBs wordBs = SensitiveWordBs.newInstance().wordDeny(WordDenys.system()).wordAllow(WordAllows.system()).init();final String text = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。";
Assert.assertTrue(wordBs.contains(text));

备注:init() 对于敏感词 DFA 的构建是比较耗时的,一般建议在应用初始化的时候只初始化一次。而不是重复初始化!

指定自己的实现

我们可以测试一下自定义的实现,如下:

String text = "这是一个测试,我的自定义敏感词。";SensitiveWordBs wordBs = SensitiveWordBs.newInstance().wordDeny(new MyWordDeny()).wordAllow(new MyWordAllow()).init();Assert.assertEquals("[我的自定义敏感词]", wordBs.findAll(text).toString());

这里只有 我的自定义敏感词 是敏感词,而 测试 不是敏感词。

当然,这里是全部使用我们自定义的实现,一般建议使用系统的默认配置+自定义配置。

可以使用下面的方式。

同时配置多个

  • 多个敏感词

WordDenys.chains() 方法,将多个实现合并为同一个 IWordDeny。

  • 多个白名单

WordAllows.chains() 方法,将多个实现合并为同一个 IWordAllow。

例子:

String text = "这是一个测试。我的自定义敏感词。";IWordDeny wordDeny = WordDenys.chains(WordDenys.system(), new MyWordDeny());
IWordAllow wordAllow = WordAllows.chains(WordAllows.system(), new MyWordAllow());SensitiveWordBs wordBs = SensitiveWordBs.newInstance().wordDeny(wordDeny).wordAllow(wordAllow).init();Assert.assertEquals("[我的自定义敏感词]", wordBs.findAll(text).toString());

这里都是同时使用了系统默认配置,和自定义的配置。

注意:我们初始化了新的 wordBs,那么用新的 wordBs 去判断。而不是用以前的 SensitiveWordHelper 工具方法,工具方法配置是默认的!

spring 整合

背景

实际使用中,比如可以在页面配置修改,然后实时生效。

数据存储在数据库中,下面是一个伪代码的例子,可以参考 SpringSensitiveWordConfig.java

要求,版本 v0.0.15 及其以上。

自定义数据源

简化伪代码如下,数据的源头为数据库。

MyDdWordAllow 和 MyDdWordDeny 是基于数据库为源头的自定义实现类。

@Configuration
public class SpringSensitiveWordConfig {@Autowiredprivate MyDdWordAllow myDdWordAllow;@Autowiredprivate MyDdWordDeny myDdWordDeny;/*** 初始化引导类* @return 初始化引导类* @since 1.0.0*/@Beanpublic SensitiveWordBs sensitiveWordBs() {SensitiveWordBs sensitiveWordBs = SensitiveWordBs.newInstance().wordAllow(WordAllows.chains(WordAllows.system(), myDdWordAllow)).wordDeny(myDdWordDeny)// 各种其他配置.init();return sensitiveWordBs;}}

敏感词库的初始化较为耗时,建议程序启动时做一次 init 初始化。

动态变更

为了保证敏感词修改可以实时生效且保证接口的尽可能简化,此处没有新增 add/remove 的方法。

而是在调用 sensitiveWordBs.init() 的时候,根据 IWordDeny+IWordAllow 重新构建敏感词库。

因为初始化可能耗时较长(秒级别),所有优化为 init 未完成时不影响旧的词库功能,完成后以新的为准

@Component
public class SensitiveWordService {@Autowiredprivate SensitiveWordBs sensitiveWordBs;/*** 更新词库** 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法。* 如果需要生效,则调用这个方法。** 说明:重新初始化不影响旧的方法使用。初始化完成后,会以新的为准。*/public void refresh() {// 每次数据库的信息发生变化之后,首先调用更新数据库敏感词库的方法,然后调用这个方法。sensitiveWordBs.init();}}

如上,你可以在数据库词库发生变更时,需要词库生效,主动触发一次初始化 sensitiveWordBs.init();

其他使用保持不变,无需重启应用。

Benchmark

V0.6.0 以后,添加对应的 benchmark 测试。

BenchmarkTimesTest

环境

测试环境为普通的笔记本:

处理器	12th Gen Intel(R) Core(TM) i7-1260P   2.10 GHz
机带 RAM	16.0 GB (15.7 GB 可用)
系统类型	64 位操作系统, 基于 x64 的处理器

ps: 不同环境会有差异,但是比例基本稳定。

测试效果记录

测试数据:100+ 字符串,循环 10W 次。

序号场景耗时备注
1只做敏感词,无任何格式转换1470ms,约 7.2W QPS追求极致性能,可以这样配置
2只做敏感词,支持全部格式转换2744ms,约 3.7W QPS满足大部分场景

后期 road-map

  • 移除单个汉字的敏感词,在中国,要把词组当做一次词,降低误判率。

  • 支持单个的敏感词变化?

remove、add、edit?

  • 敏感词标签接口支持

  • 敏感词处理时标签支持

  • wordData 的内存占用对比 + 优化

  • 用户指定自定义的词组,同时允许指定词组的组合获取,更加灵活

FormatCombine/CheckCombine/AllowDenyCombine 组合策略,允许用户自定义。

  • word check 策略的优化,统一遍历+转换

  • 添加 ThreadLocal 等性能优化

拓展阅读

敏感词工具实现思路

DFA 算法讲解

敏感词库优化流程

java 如何实现开箱即用的敏感词控台服务?

v0.11.0-敏感词新特性及对应标签文件

wechat

NLP 开源矩阵

pinyin 汉字转拼音

pinyin2hanzi 拼音转汉字

segment 高性能中文分词

opencc4j 中文繁简体转换

nlp-hanzi-similar 汉字相似度

word-checker 拼写检测

sensitive-word 敏感词

这篇关于OpenSource - 基于 DFA 算法实现的高性能 java 敏感词过滤工具框架的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/623670

相关文章

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

Spring @Scheduled注解及工作原理

《Spring@Scheduled注解及工作原理》Spring的@Scheduled注解用于标记定时任务,无需额外库,需配置@EnableScheduling,设置fixedRate、fixedDe... 目录1.@Scheduled注解定义2.配置 @Scheduled2.1 开启定时任务支持2.2 创建

SpringBoot中使用Flux实现流式返回的方法小结

《SpringBoot中使用Flux实现流式返回的方法小结》文章介绍流式返回(StreamingResponse)在SpringBoot中通过Flux实现,优势包括提升用户体验、降低内存消耗、支持长连... 目录背景流式返回的核心概念与优势1. 提升用户体验2. 降低内存消耗3. 支持长连接与实时通信在Sp

Conda虚拟环境的复制和迁移的四种方法实现

《Conda虚拟环境的复制和迁移的四种方法实现》本文主要介绍了Conda虚拟环境的复制和迁移的四种方法实现,包括requirements.txt,environment.yml,conda-pack,... 目录在本机复制Conda虚拟环境相同操作系统之间复制环境方法一:requirements.txt方法

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

基于Python开发Windows屏幕控制工具

《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,... 目录概述功能亮点界面展示实现步骤详解1. 环境准备2. 亮度控制模块3. 息屏功能实现4. 息屏时间

Mac系统下卸载JAVA和JDK的步骤

《Mac系统下卸载JAVA和JDK的步骤》JDK是Java语言的软件开发工具包,它提供了开发和运行Java应用程序所需的工具、库和资源,:本文主要介绍Mac系统下卸载JAVA和JDK的相关资料,需... 目录1. 卸载系统自带的 Java 版本检查当前 Java 版本通过命令卸载系统 Java2. 卸载自定

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义