网易首页 > 网易号 > 正文 申请入驻

【303期】SpringBoot + Redis 实现搜索栏热搜、不雅文字过滤功能

0
分享至

点击上方“Java精选”,选择“设为星标”

别问别人为什么,多问自己凭什么!

下方有惊喜,留言必回,有问必答!

每一天进步一点点,是成功的开始...

使用和实现一个简单的热搜功能,具备以下功能:

代码实现热搜与个人搜索记录功能,主要controller层下几个方法就行了 :

首先配置好redis数据源等等基础

最后贴上核心的 服务层的代码 :

package com.****.****.****.user;

import com.jianlet.service.user.RedisService;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
* @author: mrwanghc
* @date: 2020/5/13
* @description:
*/
@Transactional
@Service("redisService")
public class RedisServiceImpl implements RedisService {

//导入数据源
@Resource(name = "redisSearchTemplate")
private StringRedisTemplate redisSearchTemplate;

//新增一条该userid用户在搜索栏的历史记录
//searchkey 代表输入的关键词
@Override
public int addSearchHistoryByUserId(String userid, String searchkey) {
String shistory = RedisKeyUtils.getSearchHistoryKey(userid);
boolean b = redisSearchTemplate.hasKey(shistory);
if (b) {
Object hk = redisSearchTemplate.opsForHash().get(shistory, searchkey);
if (hk != null) {
return 1;
}else{
redisSearchTemplate.opsForHash().put(shistory, searchkey, "1");
}
}else{
redisSearchTemplate.opsForHash().put(shistory, searchkey, "1");
}
return 1;
}

//删除个人历史数据
@Override
public Long delSearchHistoryByUserId(String userid, String searchkey) {
String shistory = RedisKeyUtils.getSearchHistoryKey(userid);
return redisSearchTemplate.opsForHash().delete(shistory, searchkey);
}

//获取个人历史数据列表
@Override
public List getSearchHistoryByUserId(String userid) {
List stringList = null;
String shistory = RedisKeyUtils.getSearchHistoryKey(userid);
boolean b = redisSearchTemplate.hasKey(shistory);
if(b){
Cursor> cursor = redisSearchTemplate.opsForHash().scan(shistory, ScanOptions.NONE);
while (cursor.hasNext()) {
Map.Entry map = cursor.next();
String key = map.getKey().toString();
stringList.add(key);
}
return stringList;
}
return null;
}

//新增一条热词搜索记录,将用户输入的热词存储下来
@Override
public int incrementScoreByUserId(String searchkey) {
Long now = System.currentTimeMillis();
ZSetOperations zSetOperations = redisSearchTemplate.opsForZSet();
ValueOperations valueOperations = redisSearchTemplate.opsForValue();
List title = new ArrayList<>();
title.add(searchkey);
for (int i = 0, lengh = title.size(); i < lengh; i++) {
String tle = title.get(i);
try {
if (zSetOperations.score("title", tle) <= 0) {
zSetOperations.add("title", tle, 0);
valueOperations.set(tle, String.valueOf(now));
}
} catch (Exception e) {
zSetOperations.add("title", tle, 0);
valueOperations.set(tle, String.valueOf(now));
}
}
return 1;
}

//根据searchkey搜索其相关最热的前十名 (如果searchkey为null空,则返回redis存储的前十最热词条)
@Override
public List getHotList(String searchkey) {
String key = searchkey;
Long now = System.currentTimeMillis();
List result = new ArrayList<>();
ZSetOperations zSetOperations = redisSearchTemplate.opsForZSet();
ValueOperations valueOperations = redisSearchTemplate.opsForValue();
Set value = zSetOperations.reverseRangeByScore("title", 0, Double.MAX_VALUE);
//key不为空的时候 推荐相关的最热前十名
if(StringUtils.isNotEmpty(searchkey)){
for (String val : value) {
if (StringUtils.containsIgnoreCase(val, key)) {
if (result.size() > 9) {//只返回最热的前十名
break;
}
Long time = Long.valueOf(valueOperations.get(val));
if ((now - time) < 2592000000L) {//返回最近一个月的数据
result.add(val);
} else {//时间超过一个月没搜索就把这个词热度归0
zSetOperations.add("title", val, 0);
}
}
}
}else{
for (String val : value) {
if (result.size() > 9) {//只返回最热的前十名
break;
}
Long time = Long.valueOf(valueOperations.get(val));
if ((now - time) < 2592000000L) {//返回最近一个月的数据
result.add(val);
} else {//时间超过一个月没搜索就把这个词热度归0
zSetOperations.add("title", val, 0);
}
}
}
return result;
}

//每次点击给相关词searchkey热度 +1
@Override
public int incrementScore(String searchkey) {
String key = searchkey;
Long now = System.currentTimeMillis();
ZSetOperations zSetOperations = redisSearchTemplate.opsForZSet();
ValueOperations valueOperations = redisSearchTemplate.opsForValue();
zSetOperations.incrementScore("title", key, 1);
valueOperations.getAndSet(key, String.valueOf(now));
return 1;
}

}

核心的部分写完了,剩下的需要你自己将如上方法融入到你自己的代码中就行了。

代码实现过滤不雅文字功能

在springboot 里面写一个配置类加上@Configuration注解,在项目启动的时候加载一下,代码如下:

package com.***.***.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import java.io.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

//屏蔽敏感词初始化
@Configuration
@SuppressWarnings({ "rawtypes", "unchecked" })
public class SensitiveWordInit {
// 字符编码
private String ENCODING = "UTF-8";
// 初始化敏感字库
public Map initKeyWord() throws IOException {
// 读取敏感词库 ,存入Set中
Set wordSet = readSensitiveWordFile();
// 将敏感词库加入到HashMap中//确定有穷自动机DFA
return addSensitiveWordToHashMap(wordSet);
}

// 读取敏感词库 ,存入HashMap中
private Set readSensitiveWordFile() throws IOException {
Set wordSet = null;
ClassPathResource classPathResource = new ClassPathResource("static/censorword.txt");
InputStream inputStream = classPathResource.getInputStream();
//敏感词库
try {
// 读取文件输入流
InputStreamReader read = new InputStreamReader(inputStream, ENCODING);
// 文件是否是文件 和 是否存在
wordSet = new HashSet();
// StringBuffer sb = new StringBuffer();
// BufferedReader是包装类,先把字符读到缓存里,到缓存满了,再读入内存,提高了读的效率。
BufferedReader br = new BufferedReader(read);
String txt = null;
// 读取文件,将文件内容放入到set中
while ((txt = br.readLine()) != null) {
wordSet.add(txt);
}
br.close();
// 关闭文件流,公众号Java精选,有各类面试资料和进阶资料
read.close();
} catch (Exception e) {
e.printStackTrace();
}
return wordSet;
}
// 将HashSet中的敏感词,存入HashMap中
private Map addSensitiveWordToHashMap(Set wordSet) {
// 初始化敏感词容器,减少扩容操作
Map wordMap = new HashMap(wordSet.size());
for (String word : wordSet) {
Map nowMap = wordMap;
for (int i = 0; i < word.length(); i++) {
// 转换成char型
char keyChar = word.charAt(i);
// 获取
Object tempMap = nowMap.get(keyChar);
// 如果存在该key,直接赋值
if (tempMap != null) {
nowMap = (Map) tempMap;
}
// 不存在则,则构建一个map,同时将isEnd设置为0,因为他不是最后一个
else {
// 设置标志位
Map newMap = new HashMap();
newMap.put("isEnd", "0");
// 添加到集合
nowMap.put(keyChar, newMap);
nowMap = newMap;
}
// 最后一个
if (i == word.length() - 1) {
nowMap.put("isEnd", "1");
}
}
}
return wordMap;
}
}

然后这是代码 :

package com.***.***.interceptor;

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

//敏感词过滤器:利用DFA算法 进行敏感词过滤
public class SensitiveFilter {
//敏感词过滤器:利用DFA算法 进行敏感词过滤
private Map sensitiveWordMap = null;

// 最小匹配规则
public static int minMatchType = 1;

// 最大匹配规则
public static int maxMatchType = 2;

// 单例
private static SensitiveFilter instance = null;

// 构造函数,初始化敏感词库
private SensitiveFilter() throws IOException {
sensitiveWordMap = new SensitiveWordInit().initKeyWord();
}

// 获取单例
public static SensitiveFilter getInstance() throws IOException {
if (null == instance) {
instance = new SensitiveFilter();
}
return instance;
}

// 获取文字中的敏感词
public Set getSensitiveWord(String txt, int matchType) {
Set sensitiveWordList = new HashSet();
for (int i = 0; i < txt.length(); i++) {
// 判断是否包含敏感字符
int length = CheckSensitiveWord(txt, i, matchType);
// 存在,加入list中
if (length > 0) {
sensitiveWordList.add(txt.substring(i, i + length));
// 减1的原因,是因为for会自增
i = i + length - 1;
}
}
return sensitiveWordList;
}
// 替换敏感字字符
public String replaceSensitiveWord(String txt, int matchType,
String replaceChar) {
String resultTxt = txt;
// 获取所有的敏感词
Set set = getSensitiveWord(txt, matchType);
Iterator iterator = set.iterator();
String word = null;
String replaceString = null;
while (iterator.hasNext()) {
word = iterator.next();
replaceString = getReplaceChars(replaceChar, word.length());
resultTxt = resultTxt.replaceAll(word, replaceString);
}
return resultTxt;
}

/**
* 获取替换字符串
*
* @param replaceChar
* @param length
* @return
*/
private String getReplaceChars(String replaceChar, int length) {
String resultReplace = replaceChar;
for (int i = 1; i < length; i++) {
resultReplace += replaceChar;
}
return resultReplace;
}

/**
* 检查文字中是否包含敏感字符,检查规则如下:

* 如果存在,则返回敏感词字符的长度,不存在返回0
* @param txt
* @param beginIndex
* @param matchType
* @return
*/
public int CheckSensitiveWord(String txt, int beginIndex, int matchType) {
// 敏感词结束标识位:用于敏感词只有1位的情况
boolean flag = false;
// 匹配标识数默认为0
int matchFlag = 0;
Map nowMap = sensitiveWordMap;
for (int i = beginIndex; i < txt.length(); i++) {
char word = txt.charAt(i);
// 获取指定key
nowMap = (Map) nowMap.get(word);
// 存在,则判断是否为最后一个
if (nowMap != null) {
// 找到相应key,匹配标识+1
matchFlag++;
// 如果为最后一个匹配规则,结束循环,返回匹配标识数
if ("1".equals(nowMap.get("isEnd"))) {
// 结束标志位为true
flag = true;
// 最小规则,直接返回,最大规则还需继续查找
if (SensitiveFilter.minMatchType == matchType) {
break;
}
}
}
// 不存在,直接返回
else {
break;
}
}

if (SensitiveFilter.maxMatchType == matchType){
if(matchFlag < 2 || !flag){ //长度必须大于等于1,为词
matchFlag = 0;
}
}
if (SensitiveFilter.minMatchType == matchType){
if(matchFlag < 2 && !flag){ //长度必须大于等于1,为词
matchFlag = 0;
}
}
return matchFlag;
}
}

在你代码的controller层直接调用方法判断即可:

//非法敏感词汇判断
SensitiveFilter filter = SensitiveFilter.getInstance();
int n = filter.CheckSensitiveWord(searchkey,0,1);
if(n > 0){ //存在非法字符
logger.info("这个人输入了非法字符--> {},不知道他到底要查什么~ userid--> {}",searchkey,userid);
return null;

也可将敏感文字替换*等字符 :

SensitiveFilter filter = SensitiveFilter.getInstance();
String text = "敏感文字";
String x = filter.replaceSensitiveWord(text, 1, "*");

最后刚才的SensitiveWordInit.java里面用到了censorword.text文件,放到你项目里面的 resources 目录下的 static 目录中,这个文件就是不雅文字大全,也需要您与时俱进的更新,项目启动的时候会加载该文件。

可以自己百度下载这个东西,很多的,而且与时俱进~~,我就不贴链接了。

作者:香宝的私房小厨 https://blog.csdn.net/qq_25838777/article/details/109489767

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

------ THE END ------

精品资料,超赞福利!


3000+ 道各类技术面试题在线刷,最新、最全 Java 面试题!

期往精选 点击标题可跳转

技术交流群!

最近有很多人问,有没有读者交流群!想知道如何加入?方式很简单,兴趣相投的朋友,只需要点击下方卡片,回复“加群”,即可无套路入交流群!

文章有帮助的话,在看,转发吧!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
大结局!樊小慧承认陷害前夫,前助理将正式起诉,樊小慧官宣退网

大结局!樊小慧承认陷害前夫,前助理将正式起诉,樊小慧官宣退网

小咪侃娱圈
2024-06-12 11:56:57
标价1.3亿欧!皇马太子翻脸!避免内讧,安帅放人,巴黎曼城竞价

标价1.3亿欧!皇马太子翻脸!避免内讧,安帅放人,巴黎曼城竞价

阿泰希特
2024-06-12 10:41:02
李颖:朱婷李盈莹世界顶级!副攻自由人也不差,但为何女排下滑多

李颖:朱婷李盈莹世界顶级!副攻自由人也不差,但为何女排下滑多

金毛爱女排
2024-06-12 10:17:49
国足的最大功臣,以一己之力让韩国队放弃了打入第二个球的念头

国足的最大功臣,以一己之力让韩国队放弃了打入第二个球的念头

刺头体育
2024-06-12 20:20:54
贾玲高调官宣! 6月2日,消失3个月的贾玲,再次登上热搜!

贾玲高调官宣! 6月2日,消失3个月的贾玲,再次登上热搜!

娱记掌门
2024-06-12 20:05:46
1955年卫立煌应邀回大陆,8位元帅设宴款待,毛主席:你是有功的

1955年卫立煌应邀回大陆,8位元帅设宴款待,毛主席:你是有功的

历史龙元阁
2024-06-12 16:27:30
上海医疗系统又爆出惊天丑闻,人的素质真的和学历无关

上海医疗系统又爆出惊天丑闻,人的素质真的和学历无关

慧翔百科
2024-06-07 12:54:45
2013年男子找干妈通奸时,遇干妈和情人缠绵,他将干妈的情人杀死

2013年男子找干妈通奸时,遇干妈和情人缠绵,他将干妈的情人杀死

汉史趣闻
2024-06-12 07:37:54
中荷爆发短兵相接,荷战机逼近上海附近海域,歼轰七和直-19围攻

中荷爆发短兵相接,荷战机逼近上海附近海域,歼轰七和直-19围攻

番茄说史聊
2024-06-12 21:03:20
安倍晋三是日本人,但为啥他遇刺后,墓碑上却刻的是中国汉字呢?

安倍晋三是日本人,但为啥他遇刺后,墓碑上却刻的是中国汉字呢?

探秘历史
2024-06-11 10:36:10
黄一鸣女儿酷似爷爷王健林,王思聪不要女儿,王健林还要孙女呢

黄一鸣女儿酷似爷爷王健林,王思聪不要女儿,王健林还要孙女呢

综艺拼盘汇
2024-06-12 15:30:46
大S终于在具俊晔的菲律宾商演中,兑现了自己往日的“承诺”?

大S终于在具俊晔的菲律宾商演中,兑现了自己往日的“承诺”?

娱记掌门
2024-06-13 02:00:46
黑龙江一医生被举报出轨患者!妻子出面否认

黑龙江一医生被举报出轨患者!妻子出面否认

鲁中晨报
2024-06-12 08:19:05
库里前队友:18年杜兰特让MVP,库里不中用,拿不到居然哭了

库里前队友:18年杜兰特让MVP,库里不中用,拿不到居然哭了

阿雄侃篮球
2024-06-12 13:59:31
台商代表团访陆,请求绕过ECFA再给优惠政策,宋涛回应开门见山

台商代表团访陆,请求绕过ECFA再给优惠政策,宋涛回应开门见山

说天说地说实事
2024-06-12 20:52:14
来了!新帅正式“空降”AC米兰!顶级中场+嫡系射手当“见面礼”

来了!新帅正式“空降”AC米兰!顶级中场+嫡系射手当“见面礼”

头狼追球
2024-06-12 19:36:51
新加坡门将发声:我把1%的胜利留给中国,感谢主场中国让我们一分

新加坡门将发声:我把1%的胜利留给中国,感谢主场中国让我们一分

建哥说体育
2024-06-12 05:41:07
台军退役“将军”在节目上公然贬低解放军,低劣素质可见一斑!

台军退役“将军”在节目上公然贬低解放军,低劣素质可见一斑!

青年的背包
2024-06-12 21:45:19
千万网红郭有才停播后,最新面貌呈现,穿衣打扮有讲究

千万网红郭有才停播后,最新面貌呈现,穿衣打扮有讲究

你我话娱乐
2024-06-12 12:20:11
顾立雄交出作战指挥权,两岸统一大局已定,美根本来不及调兵

顾立雄交出作战指挥权,两岸统一大局已定,美根本来不及调兵

张殿成
2024-06-12 14:01:39
2024-06-13 05:38:49
Java精选
Java精选
一场永远也演不完的戏
1551文章数 3855关注度
往期回顾 全部

科技要闻

谁是苹果AI的“中国合伙人”?

头条要闻

顶头上司落马3周后退休副省长被查 任内曾被环保问责

头条要闻

顶头上司落马3周后退休副省长被查 任内曾被环保问责

体育要闻

国足,别辜负这场奇迹!

娱乐要闻

黄一鸣再次录视频表态孩子是王思聪的

财经要闻

徽商银行的影子 借基金向地方城投放贷?

汽车要闻

理想汽车周销量突破1万辆 单周销量首超宝马奥迪

态度原创

手机
游戏
旅游
时尚
数码

手机要闻

曝!小米 SU7 性能版在纽北刷圈速/iPhone 16 将砍掉实体键

钢岚:实测分析本月三大专武应该优先做?居然增伤最高的是它?

旅游要闻

日本“黑道大哥”现街道 警察保持随时监控

不会买牛仔裤?4个评判标准相当靠谱

数码要闻

部分采用 N3B,英特尔 Arrow Lake-U/H/HX 移动处理器现身海关

无障碍浏览 进入关怀版