diff --git a/pom.xml b/pom.xml
index 8cadc5d3..96a16d5f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -316,6 +316,13 @@
ruoyi-cai
${ruoyi-vue-plus.version}
+
+
+
+ com.ruoyi
+ ruoyi-sensitive-word
+ ${ruoyi-vue-plus.version}
+
@@ -331,6 +338,7 @@
ruoyi-cai
ruoyi-yunxin
ruoyi-websocket-boot
+ ruoyi-sensitive-word
pom
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 6a726227..70141561 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -88,6 +88,11 @@
test
+
+ com.ruoyi
+ ruoyi-sensitive-word
+
+
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sensitive/WordController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sensitive/WordController.java
new file mode 100644
index 00000000..98746eb7
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/sensitive/WordController.java
@@ -0,0 +1,109 @@
+package com.ruoyi.web.controller.sensitive;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.annotation.RepeatSubmit;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.PageQuery;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.core.validate.AddGroup;
+import com.ruoyi.common.core.validate.EditGroup;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.sensitive.domain.Word;
+import com.ruoyi.sensitive.service.WordService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 敏感词
+ *
+ * @author 77
+ * @date 2024-02-19
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/sensitive/word")
+public class WordController extends BaseController {
+
+ private final WordService wordService;
+
+ /**
+ * 查询敏感词列表
+ */
+ @SaCheckPermission("sensitive:word:list")
+ @GetMapping("/list")
+ public TableDataInfo list(Word bo, PageQuery pageQuery) {
+ Page page = wordService.page(pageQuery.build(), Wrappers.lambdaQuery(bo));
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 导出敏感词列表
+ */
+ @SaCheckPermission("sensitive:word:export")
+ @Log(title = "敏感词", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(Word bo, HttpServletResponse response) {
+ List list = wordService.list(Wrappers.lambdaQuery(bo));
+ ExcelUtil.exportExcel(list, "敏感词", Word.class, response);
+ }
+
+ /**
+ * 获取敏感词详细信息
+ *
+ * @param id 主键
+ */
+ @SaCheckPermission("sensitive:word:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Integer id) {
+ return R.ok(wordService.getById(id));
+ }
+
+ /**
+ * 新增敏感词
+ */
+ @SaCheckPermission("sensitive:word:add")
+ @Log(title = "敏感词", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody Word bo) {
+ return toAjax(wordService.saveWord(bo));
+ }
+
+ /**
+ * 修改敏感词
+ */
+ @SaCheckPermission("sensitive:word:edit")
+ @Log(title = "敏感词", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R edit(@Validated(EditGroup.class) @RequestBody Word bo) {
+ return toAjax(wordService.updateWordById(bo));
+ }
+
+ /**
+ * 删除敏感词
+ *
+ * @param ids 主键串
+ */
+ @SaCheckPermission("sensitive:word:remove")
+ @Log(title = "敏感词", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R remove(@NotEmpty(message = "主键不能为空")
+ @PathVariable Integer[] ids) {
+ return toAjax(wordService.removeWordBatchByIds(Arrays.asList(ids)));
+ }
+}
diff --git a/ruoyi-sensitive-word/pom.xml b/ruoyi-sensitive-word/pom.xml
new file mode 100644
index 00000000..51a561e7
--- /dev/null
+++ b/ruoyi-sensitive-word/pom.xml
@@ -0,0 +1,32 @@
+
+
+ 4.0.0
+
+ com.ruoyi
+ ruoyi-vue-plus
+ 4.8.2
+
+
+ ruoyi-sensitive-word
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ com.github.houbb
+ sensitive-word
+ 0.12.0
+
+
+ com.ruoyi
+ ruoyi-common
+
+
+
+
diff --git a/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/cache/LastUpdateTimeCache.java b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/cache/LastUpdateTimeCache.java
new file mode 100644
index 00000000..6b027612
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/cache/LastUpdateTimeCache.java
@@ -0,0 +1,28 @@
+package com.ruoyi.sensitive.cache;
+
+import org.redisson.api.RBucket;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+
+@Component
+public class LastUpdateTimeCache {
+ @Autowired
+ private RedissonClient redissonClient;
+ private String getKey(){
+ return "sensitive-lastRefreshTime";
+ }
+ public LocalDateTime getTime(){
+ String key = getKey();
+ RBucket bucket = redissonClient.getBucket(key);
+ return bucket.get();
+ }
+
+ public void setTime(){
+ String key = getKey();
+ RBucket bucket = redissonClient.getBucket(key);
+ bucket.set(LocalDateTime.now());
+ }
+}
diff --git a/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/MyDdWordAllow.java b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/MyDdWordAllow.java
new file mode 100644
index 00000000..8cdf4dfa
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/MyDdWordAllow.java
@@ -0,0 +1,38 @@
+package com.ruoyi.sensitive.config;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.github.houbb.heaven.support.handler.IHandler;
+import com.github.houbb.heaven.util.util.CollectionUtil;
+import com.github.houbb.sensitive.word.api.IWordAllow;
+import com.ruoyi.sensitive.domain.Word;
+import com.ruoyi.sensitive.service.WordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @author binbin.hou
+ * @since 1.1.0
+ */
+@Component
+public class MyDdWordAllow implements IWordAllow {
+
+ @Autowired
+ private WordService wordService;
+
+ @Override
+ public List allow() {
+ List wordList = wordService.list(Wrappers.lambdaQuery(Word.class)
+ .select(Word::getWord)
+ .eq(Word::getEnableStatus,1)
+ .eq(Word::getType, 1));
+ return CollectionUtil.toList(wordList, new IHandler() {
+ @Override
+ public String handle(Word word) {
+ return word.getWord();
+ }
+ });
+ }
+
+}
diff --git a/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/MyDdWordDeny.java b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/MyDdWordDeny.java
new file mode 100644
index 00000000..b1c36548
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/MyDdWordDeny.java
@@ -0,0 +1,39 @@
+package com.ruoyi.sensitive.config;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.github.houbb.heaven.support.handler.IHandler;
+import com.github.houbb.heaven.util.util.CollectionUtil;
+import com.github.houbb.sensitive.word.api.IWordDeny;
+import com.ruoyi.sensitive.domain.Word;
+import com.ruoyi.sensitive.service.WordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @author binbin.hou
+ * @since 1.1.0
+ */
+@Component
+public class MyDdWordDeny implements IWordDeny {
+
+ @Autowired
+ private WordService wordService;
+
+ @Override
+ public List deny() {
+ List wordList = wordService.list(Wrappers.lambdaQuery(Word.class)
+ .select(Word::getWord)
+ .eq(Word::getEnableStatus,1)
+ .eq(Word::getType, 2));
+
+ return CollectionUtil.toList(wordList, new IHandler() {
+ @Override
+ public String handle(Word word) {
+ return word.getWord();
+ }
+ });
+ }
+
+}
diff --git a/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/MySensitiveWordScheduleRefresh.java b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/MySensitiveWordScheduleRefresh.java
new file mode 100644
index 00000000..bd3e195d
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/MySensitiveWordScheduleRefresh.java
@@ -0,0 +1,47 @@
+package com.ruoyi.sensitive.config;
+
+import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
+import com.ruoyi.sensitive.cache.LastUpdateTimeCache;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.time.LocalDateTime;
+import java.util.concurrent.TimeUnit;
+
+@Component
+@Slf4j
+public class MySensitiveWordScheduleRefresh {
+
+ @Autowired
+ private SensitiveWordBs sensitiveWordBs;
+ @Autowired
+ private LastUpdateTimeCache lastUpdateTimeCache;
+
+ @Scheduled(fixedDelay = 20,timeUnit = TimeUnit.SECONDS)
+ public void job(){
+ try {
+ log.info("MySensitiveWordScheduleRefresh start");
+ LocalDateTime time = lastUpdateTimeCache.getTime();
+ LocalDateTime now = LocalDateTime.now();
+ if(time == null || time.isBefore(now)){
+ return;
+ }
+ refresh();
+ log.info("MySensitiveWordScheduleRefresh end");
+ } catch (Exception e) {
+ log.error("MySensitiveWordScheduleRefresh meet ex", e);
+ }
+ }
+
+ @PostConstruct
+ public void init() {
+ }
+
+ private void refresh() {
+ sensitiveWordBs.init();
+ }
+
+}
diff --git a/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/SensitiveWordConfig.java b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/SensitiveWordConfig.java
new file mode 100644
index 00000000..9c85b764
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/config/SensitiveWordConfig.java
@@ -0,0 +1,38 @@
+package com.ruoyi.sensitive.config;
+
+import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
+import com.github.houbb.sensitive.word.support.allow.WordAllows;
+import com.github.houbb.sensitive.word.support.deny.WordDenys;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author binbin.hou
+ * @since 1.1.0
+ */
+@Configuration
+public class SensitiveWordConfig {
+
+ @Autowired
+ private MyDdWordAllow myDdWordAllow;
+
+ @Autowired
+ private MyDdWordDeny myDdWordDeny;
+
+ /**
+ * 初始化引导类
+ * @return 初始化引导类
+ * @since 1.0.0
+ */
+ @Bean
+ public SensitiveWordBs sensitiveWordBs() {
+ return SensitiveWordBs.newInstance()
+ .wordAllow(WordAllows.chains(WordAllows.defaults(), myDdWordAllow))
+ .wordDeny(WordDenys.chains(WordDenys.defaults(), myDdWordDeny))
+ .ignoreRepeat(false)
+ // 各种其他配置
+ .init();
+ }
+
+}
diff --git a/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/domain/Word.java b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/domain/Word.java
new file mode 100644
index 00000000..0f1908c0
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/domain/Word.java
@@ -0,0 +1,51 @@
+package com.ruoyi.sensitive.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 敏感词对象 cai_word
+ *
+ * @author 77
+ * @date 2024-02-19
+ */
+@Data
+@TableName("cai_word")
+public class Word implements Serializable {
+
+ private static final long serialVersionUID=1L;
+
+ /**
+ * 应用自增主键
+ */
+ @TableId(value = "id")
+ private Integer id;
+ /**
+ * 单词
+ */
+ private String word;
+ /**
+ * 1-白名单 2-黑名单
+ */
+ private Integer type;
+ /**
+ * 启用状态
+ */
+ private Integer enableStatus;
+ /**
+ * 配置描述
+ */
+ private String remark;
+ /**
+ * 操作员名称
+ */
+ private String operatorId;
+
+ private LocalDateTime updateTime;
+ private LocalDateTime createTime;
+
+}
diff --git a/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/mapper/WordMapper.java b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/mapper/WordMapper.java
new file mode 100644
index 00000000..be649216
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/mapper/WordMapper.java
@@ -0,0 +1,14 @@
+package com.ruoyi.sensitive.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.sensitive.domain.Word;
+
+/**
+ * 敏感词Mapper接口
+ *
+ * @author 77
+ * @date 2024-02-19
+ */
+public interface WordMapper extends BaseMapper {
+
+}
diff --git a/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/service/WordService.java b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/service/WordService.java
new file mode 100644
index 00000000..8ee3eb84
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/service/WordService.java
@@ -0,0 +1,21 @@
+package com.ruoyi.sensitive.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.sensitive.domain.Word;
+
+import java.util.List;
+
+/**
+ * 敏感词Service接口
+ *
+ * @author 77
+ * @date 2024-02-19
+ */
+public interface WordService extends IService {
+
+ boolean removeWordBatchByIds(List asList);
+
+ boolean updateWordById(Word bo);
+
+ boolean saveWord(Word bo);
+}
diff --git a/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/service/impl/WordServiceImpl.java b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/service/impl/WordServiceImpl.java
new file mode 100644
index 00000000..425f9213
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/java/com/ruoyi/sensitive/service/impl/WordServiceImpl.java
@@ -0,0 +1,46 @@
+package com.ruoyi.sensitive.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.houbb.sensitive.word.support.allow.WordAllows;
+import com.ruoyi.sensitive.cache.LastUpdateTimeCache;
+import com.ruoyi.sensitive.domain.Word;
+import com.ruoyi.sensitive.mapper.WordMapper;
+import com.ruoyi.sensitive.service.WordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 敏感词Service业务层处理
+ *
+ * @author 77
+ * @date 2024-02-19
+ */
+@Service
+public class WordServiceImpl extends ServiceImpl implements WordService {
+
+ @Autowired
+ private LastUpdateTimeCache lastUpdateTimeCache;
+
+ @Override
+ public boolean removeWordBatchByIds(List asList) {
+ boolean re = this.removeBatchByIds(asList);
+ lastUpdateTimeCache.setTime();
+ return re;
+ }
+
+ @Override
+ public boolean updateWordById(Word bo) {
+ boolean re = this.updateById(bo);
+ lastUpdateTimeCache.setTime();
+ return re;
+ }
+
+ @Override
+ public boolean saveWord(Word bo) {
+ boolean re = this.save(bo);
+ lastUpdateTimeCache.setTime();
+ return re;
+ }
+}
diff --git a/ruoyi-sensitive-word/src/main/resources/mapper/sensitive/WordMapper.xml b/ruoyi-sensitive-word/src/main/resources/mapper/sensitive/WordMapper.xml
new file mode 100644
index 00000000..6ef0ccc4
--- /dev/null
+++ b/ruoyi-sensitive-word/src/main/resources/mapper/sensitive/WordMapper.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+