敏感词

This commit is contained in:
2025-11-21 18:56:14 +08:00
parent 028e748565
commit c2cac51762
23 changed files with 108710 additions and 2 deletions

View File

@@ -0,0 +1,45 @@
package org.xyzh.sensitive.config;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.xyzh.api.sensitive.SensitiveService;
import org.xyzh.common.redis.service.RedisService;
import org.xyzh.sensitive.constants.SensitiveRedisContants;
import org.xyzh.sensitive.mapper.SensitiveMapper;
import org.xyzh.common.dto.sensitive.TbSensitive;
@Component
public class SensitiveWordInitializer implements CommandLineRunner{
private static final Logger logger = LoggerFactory.getLogger(SensitiveWordInitializer.class);
@Autowired
private RedisService redisService;
@Autowired
private SensitiveMapper sensitiveMapper;
@Override
public void run(String... args) throws Exception {
logger.info("敏感词初始化");
// 数据库读取吸入redis
List<TbSensitive> list = sensitiveMapper.selectAll();
Set<String> allowSet = new HashSet<>();
Set<String> denySet = new HashSet<>();
list.stream().forEach(item->{
if (item.getType().equals("allow")) {
allowSet.add(item.getWord());
}else {
denySet.add(item.getWord());
}
});
redisService.sAdd(SensitiveRedisContants.SENSITIVE_WORD_ALLOW, allowSet);
redisService.sAdd(SensitiveRedisContants.SENSITIVE_WORD_DENY, denySet);
}
}

View File

@@ -0,0 +1,36 @@
package org.xyzh.sensitive.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.xyzh.sensitive.word.DynamicAllowWord;
import org.xyzh.sensitive.word.DynamicDenyWord;
import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
import com.github.houbb.sensitive.word.support.allow.WordAllows;
@Configuration
public class SpringSensitiveWordConfig {
@Autowired
private DynamicAllowWord dynamicAllowWord;
@Autowired
private DynamicDenyWord dynamicDenyWord;
/**
* 初始化引导类
* @return 初始化引导类
* @since 1.0.0
*/
@Bean
public SensitiveWordBs sensitiveWordBs() {
SensitiveWordBs sensitiveWordBs = SensitiveWordBs.newInstance()
.wordAllow(WordAllows.chains(WordAllows.defaults(), dynamicAllowWord))
.wordDeny(dynamicDenyWord)
// 各种其他配置
.init();
return sensitiveWordBs;
}
}

View File

@@ -0,0 +1,6 @@
package org.xyzh.sensitive.constants;
public class SensitiveRedisContants {
public static final String SENSITIVE_WORD_ALLOW = "sensitive:word:allow";
public static final String SENSITIVE_WORD_DENY = "sensitive:word:deny";
}

View File

@@ -0,0 +1,18 @@
package org.xyzh.sensitive.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.xyzh.common.dto.sensitive.TbSensitive;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@Mapper
public interface SensitiveMapper extends BaseMapper<TbSensitive> {
public List<TbSensitive> selectAll();
public Integer addSensitiveWord(TbSensitive tbSensitive);
public Integer deleteSensitiveWord(TbSensitive tbSensitive);
}

View File

@@ -0,0 +1,107 @@
package org.xyzh.sensitive.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.xyzh.api.sensitive.SensitiveService;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.dto.sensitive.TbSensitive;
import org.xyzh.common.redis.service.RedisService;
import org.xyzh.sensitive.constants.SensitiveRedisContants;
import org.xyzh.sensitive.mapper.SensitiveMapper;
import java.util.List;
import com.github.houbb.sensitive.word.core.SensitiveWordHelper;
@Service
public class SensitiveServiceImpl implements SensitiveService{
@Autowired
private SensitiveMapper sensitiveMapper;
@Autowired
private SensitiveWordHelper sensitiveWordHelper;
@Autowired
private RedisService redisService;
@Override
public ResultDomain<Boolean> addSensitiveWord(TbSensitive tbSensitive) {
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
String word = tbSensitive.getWord();
String type = tbSensitive.getType();
// 第一次检查Redis中是否已存在
String redisKey = "allow".equals(type) ? SensitiveRedisContants.SENSITIVE_WORD_ALLOW : SensitiveRedisContants.SENSITIVE_WORD_DENY;
if (redisService.sMembers(redisKey).contains(word)) {
resultDomain.fail("敏感词已存在");
return resultDomain;
}
// 加锁
synchronized (this) {
// 第二次检查再次确认Redis中是否已存在
if (redisService.sMembers(redisKey).contains(word)) {
resultDomain.fail("敏感词已存在");
return resultDomain;
}
// 执行数据库插入
int i = sensitiveMapper.addSensitiveWord(tbSensitive);
if (i > 0) {
// 同步到Redis
redisService.sAdd(redisKey, word);
resultDomain.success("添加敏感词成功", true);
} else {
resultDomain.fail("添加敏感词失败");
}
}
return resultDomain;
}
@Override
public ResultDomain<Boolean> deleteSensitiveWord(TbSensitive tbSensitive) {
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
String word = tbSensitive.getWord();
String type = tbSensitive.getType();
// 第一次检查Redis中是否存在
String redisKey = "allow".equals(type) ? SensitiveRedisContants.SENSITIVE_WORD_ALLOW : SensitiveRedisContants.SENSITIVE_WORD_DENY;
if (!redisService.sMembers(redisKey).contains(word)) {
resultDomain.fail("敏感词不存在");
return resultDomain;
}
// 加锁
synchronized (this) {
// 第二次检查再次确认Redis中是否存在
if (!redisService.sMembers(redisKey).contains(word)) {
resultDomain.fail("敏感词不存在");
return resultDomain;
}
// 执行数据库删除
int i = sensitiveMapper.deleteSensitiveWord(tbSensitive);
if (i > 0) {
// 从Redis中移除
redisService.sRemove(redisKey, word);
resultDomain.success("删除敏感词成功", true);
} else {
resultDomain.fail("删除敏感词失败");
}
}
return resultDomain;
}
@Override
public ResultDomain<Boolean> judgeSensitive(String text) {
ResultDomain<Boolean> resultDomain = new ResultDomain<>();
boolean containsSensitive = sensitiveWordHelper.contains(text);
resultDomain.success("敏感词检测完成", containsSensitive);
return resultDomain;
}
}

View File

@@ -0,0 +1,35 @@
package org.xyzh.sensitive.word;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.xyzh.common.redis.service.RedisService;
import org.xyzh.sensitive.constants.SensitiveRedisContants;
import com.github.houbb.sensitive.word.api.IWordAllow;
@Component
public class DynamicAllowWord implements IWordAllow {
@Autowired
private RedisService redisService;
@Override
public List<String> allow() {
Set<Object> members = redisService.sMembers(SensitiveRedisContants.SENSITIVE_WORD_ALLOW);
if (members == null || members.isEmpty()) {
return Collections.emptyList();
}
List<String> list = new ArrayList<>(members.size());
for (Object o : members) {
if (o != null) {
list.add(String.valueOf(o));
}
}
return list;
}
}

View File

@@ -0,0 +1,35 @@
package org.xyzh.sensitive.word;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.xyzh.common.redis.service.RedisService;
import org.xyzh.sensitive.constants.SensitiveRedisContants;
import com.github.houbb.sensitive.word.api.IWordDeny;
@Component
public class DynamicDenyWord implements IWordDeny {
@Autowired
private RedisService redisService;
@Override
public List<String> deny() {
Set<Object> members = redisService.sMembers(SensitiveRedisContants.SENSITIVE_WORD_DENY);
if (members == null || members.isEmpty()) {
return Collections.emptyList();
}
List<String> list = new ArrayList<>(members.size());
for (Object o : members) {
if (o != null) {
list.add(String.valueOf(o));
}
}
return list;
}
}

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.xyzh.sensitive.mapper.SensitiveMapper">
<resultMap id="BaseMap" resultType="org.xyzh.common.dto.sensitive.TbSensitive">
<id column="id" property="id"/>
<result column="word" property="word"/>
<result column="type" property="type"/>
</resultMap>
<sql id="Base_Column_List">
id, word, type
</sql>
<select id="selectAll" resultMap="BaseMap">
SELECT
<include refid="Base_Column_List"/>
FROM tb_sensitive
</select>
<insert id="addSensitiveWord" parameterType="org.xyzh.common.dto.sensitive.TbSensitive" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
INSERT INTO tb_sensitive (word, type)
VALUES (#{word}, #{type})
</insert>
<delete id="deleteSensitiveWord" parameterType="org.xyzh.common.dto.sensitive.TbSensitive">
DELETE FROM tb_sensitive
WHERE word = #{word}
<if test="type != null and type != ''">
AND type = #{type}
</if>
</delete>
</mapper>

View File

@@ -0,0 +1,12 @@
生日快乐
曹操
幸运
幸运儿
17年前
1条
1梯两户
1比1
年检
幸存
恶搞
游戏机

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fuck
duck
shit
chicken
fowl
sex
sexy
prostitute
whore
harlot
hooker
gender

File diff suppressed because it is too large Load Diff