大家好,我是宝哥!

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

  1. 搜索栏展示当前登陆的个人用户的搜索历史记录,删除个人历史记录

  2. 用户在搜索栏输入某字符,则将该字符记录下来 以zset格式存储的redis中,记录该字符被搜索的个数以及当前的时间戳 (用了DFA算法,感兴趣的自己百度学习吧)

  3. 每当用户查询了已在redis存在了的字符时,则直接累加个数, 用来获取平台上最热查询的十条数据。(可以自己写接口或者直接在redis中添加一些预备好的关键词)

  4. 最后还要做不雅文字过滤功能。这个很重要不说了你懂的。

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

  1. 向redis 添加热搜词汇(添加的时候使用下面不雅文字过滤的方法来过滤下这个词汇,合法再去存储

  2. 每次点击给相关词热度 +1

  3. 根据key搜索相关最热的前十名

  4. 插入个人搜索记录

  5. 查询个人搜索记录

首先配置好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 代表输入的关键词@Overridepublic 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;}//删除个人历史数据@Overridepublic Long delSearchHistoryByUserId(String userid, String searchkey) {String shistory = RedisKeyUtils.getSearchHistoryKey(userid);return redisSearchTemplate.opsForHash().delete(shistory, searchkey);}//获取个人历史数据列表@Overridepublic List<String> getSearchHistoryByUserId(String userid) {List<String> stringList = null;String shistory = RedisKeyUtils.getSearchHistoryKey(userid);boolean b = redisSearchTemplate.hasKey(shistory);if(b){Cursor<Map.Entry<Object, Object>> cursor = redisSearchTemplate.opsForHash().scan(shistory, ScanOptions.NONE);while (cursor.hasNext()) {Map.Entry<Object, Object> map = cursor.next();String key = map.getKey().toString();stringList.add(key);}return stringList;}return null;}//新增一条热词搜索记录,将用户输入的热词存储下来@Overridepublic int incrementScoreByUserId(String searchkey) {Long now = System.currentTimeMillis();ZSetOperations zSetOperations = redisSearchTemplate.opsForZSet();ValueOperations<String, String> valueOperations = redisSearchTemplate.opsForValue();List<String> 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存储的前十最热词条)@Overridepublic List<String> getHotList(String searchkey) {String key = searchkey;Long now = System.currentTimeMillis();List<String> result = new ArrayList<>();ZSetOperations zSetOperations = redisSearchTemplate.opsForZSet();ValueOperations<String, String> valueOperations = redisSearchTemplate.opsForValue();Set<String> 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 {//时间超过一个月没搜索就把这个词热度归0zSetOperations.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 {//时间超过一个月没搜索就把这个词热度归0zSetOperations.add("title", val, 0);}}}return result;}//每次点击给相关词searchkey热度 +1@Overridepublic int incrementScore(String searchkey) {String key = searchkey;Long now = System.currentTimeMillis();ZSetOperations zSetOperations = redisSearchTemplate.opsForZSet();ValueOperations<String, String> 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<String> wordSet = readSensitiveWordFile();// 将敏感词库加入到HashMap中//确定有穷自动机DFAreturn addSensitiveWordToHashMap(wordSet);}// 读取敏感词库 ,存入HashMap中private Set<String> readSensitiveWordFile() throws IOException {Set<String> wordSet = null;ClassPathResource classPathResource = new ClassPathResource("static/censorword.txt");InputStream inputStream = classPathResource.getInputStream();//敏感词库try {// 读取文件输入流InputStreamReader read = new InputStreamReader(inputStream, ENCODING);// 文件是否是文件 和 是否存在wordSet = new HashSet<String>();// StringBuffer sb = new StringBuffer();// BufferedReader是包装类,先把字符读到缓存里,到缓存满了,再读入内存,提高了读的效率。BufferedReader br = new BufferedReader(read);String txt = null;// 读取文件,将文件内容放入到set中while ((txt = br.readLine()) != null) {wordSet.add(txt);}br.close();// 关闭文件流read.close();} catch (Exception e) {e.printStackTrace();}return wordSet;}// 将HashSet中的敏感词,存入HashMap中private Map addSensitiveWordToHashMap(Set<String> 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<String, String> newMap = new HashMap<String, String>();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<String> getSensitiveWord(String txt, int matchType) {Set<String> sensitiveWordList = new HashSet<String>();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<String> set = getSensitiveWord(txt, matchType);Iterator<String> 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;}/*** 检查文字中是否包含敏感字符,检查规则如下:<br>* 如果存在,则返回敏感词字符的长度,不存在返回0* @param txt* @param beginIndex* @param matchType* @return*/public int CheckSensitiveWord(String txt, int beginIndex, int matchType) {// 敏感词结束标识位:用于敏感词只有1位的情况boolean flag = false;// 匹配标识数默认为0int matchFlag = 0;Map nowMap = sensitiveWordMap;for (int i = beginIndex; i < txt.length(); i++) {char word = txt.charAt(i);// 获取指定keynowMap = (Map) nowMap.get(word);// 存在,则判断是否为最后一个if (nowMap != null) {// 找到相应key,匹配标识+1matchFlag++;// 如果为最后一个匹配规则,结束循环,返回匹配标识数if ("1".equals(nowMap.get("isEnd"))) {// 结束标志位为trueflag = 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 目录中,这个文件就是不雅文字大全,也需要您与时俱进的更新,项目启动的时候会加载该文件。

精彩推荐:

从实现原理来讲,Nacos 为什么这么强

大文件上传最全方案:秒传、断点续传、分片上传

老板要我开发一个简单的工作流引擎

Spring+websocket+quartz实现消息定时推送

一口气说出 6 种实现延时消息的方案

SpringBoot+Redis 实现一个微博热搜!相关推荐

  1. python热搜排行功能_用Python做一个微博热搜榜的语音播报

    微博是一个社交平台,有高效的信息流,几乎所有人能在这上面找到自己感兴趣的内容.经常使用微博的小伙伴,大家对微博热搜榜应该都不会很陌生.每天发生了什么新闻呢,谁谁谁又上热搜了. 在这个信息社会,每天发生 ...

  2. SpringBoot+Redis 搞定搜索栏热搜、不雅文字过滤功能

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/qq_25838777/article/ details/109489767 使用java和redis实现一个简单的热搜功能,具 ...

  3. 新手开发记录:把ListView、Adapter的逻辑捋顺,做一个微博热搜吧

    首先声明:本人只是一个喜欢钻研的安卓新手,很多地方理解会不到位,欢迎大佬批评指正

  4. 微博热搜榜爬虫2.0

    微博热搜榜爬虫2.0 6月份出了一个微博热搜爬虫,在我电脑上设置了自动化12点爬取,结果到了9月份,执行不了. 一直没时间弄,今天来更新一下: 解决了两个问题, 1 >之前的话请求头比较单一,只 ...

  5. springboot+redis实现微博热搜排行榜

    springboot+redis实现微博热搜排行榜 技术模拟思路: 采用26个英文字母来实现排行,随机为每个字母生成一个随机数作为score 为了更好的体验,先做几件事: 先初始化1个月的历史数据 定 ...

  6. 一个比微博热搜更适合吃瓜的平台——即时热榜

    一个比微博热搜更适合吃瓜的平台--即时热榜.在这个信息爆炸的时代,我们的爱好(吃瓜)越来越多,对于信息量(八卦)的需求越来越大.要说平时,咱们追热点一般最常去的一定是微博,热点及时还有话题性,可参与讨 ...

  7. ig夺冠后服务器不稳定,IG夺冠,王思聪上微博热搜,网友:一个让服务器瘫痪的男人...

    11月3日,LPL等了七年,终于等到了这一天. IG3:0 打败FNC赢得了S8冠军.比赛结束后,IG赢得冠军的消息传遍了整个网络.这次不仅让LOL又火了一把,也让校长王思聪成为大家的终极偶像,正在观 ...

  8. 同为高并发,微博热搜、天猫秒杀、12306 抢票有什么不同?

    同为高并发,微博热搜.天猫秒杀.12306 抢票有什么不同呢? 那接下来我们就来分别聊聊他们有什么特性~ 1.微博热搜 「微博热搜」是一个典型的读多写少场景,读今日的热点新闻,写自己的微博评论. 作为 ...

  9. Python爬取微博热搜数据之炫酷可视化

    可视化展示 看完记得点个赞哟 微博炫酷可视化音乐组合版来了! 项目介绍 背景 现阶段,微博.抖音.快手.哗哩哗哩.微信公众号已经成为不少年轻人必备的"生活神器".在21世纪的今天, ...

最新文章

  1. 过来人的肺腑之言,攻读CV和ML硕士给我带来了什么?
  2. Xcode iOS9.3 配置包 iOS10.0 配置包 iOS10.2 配置包 could not find developer disk image
  3. maven 批量docker_Spring Boot 整合 docker
  4. Mongodb 数据模型概念
  5. Ubuntu 设置程序开机启动(以指定用户身份)
  6. TypeError: Cannot red property 'style' of null 错误解决
  7. 【数据竞赛】5行代码检测分布不一致,代码少效果好!
  8. POSIX 消息队列相关问题
  9. linux强大功能,linux grep和find 的强大功能
  10. 大熊君大话NodeJS之------Net模块
  11. 高光谱数据集_基于飞桨实现高光谱反演:通过遥感数据获取土壤某物质含量
  12. 深度学习如何有效攻克鲁棒性的场景重建难题?
  13. WordPress Platinum SEO插件跨站脚本漏洞
  14. 将MSHFlexGrid1中记录导出为Excel
  15. linux穷举pppoe密码,Ubuntu/Linux下如何用rp-pppoe3.8通过ADSL上网
  16. 郑州大学计算机专业国际学院,郑州大学国际学院怎么样?郑州大学国际学院好吗?(历年分数、专业设置、校园环境、教学实力、名人校友) - 职友集...
  17. Centos7配置ssh、rsh免密互信集群服务
  18. html5单位转换器,液体单位在线换算工具
  19. photoshop2021补丁版v22.3.1完美兼容m1
  20. fatal: protocol ‘(https‘ is not supported解决git问题

热门文章

  1. java tts开源,程序员罗杰-开源的TTS软件Flite从安装到使用
  2. 学习笔记_OSI模型
  3. 1. 使用 while/for 循环:计算 1-100 之间所有数字的和,所有偶数的和,所有奇数的和
  4. python求对数_python中取对数
  5. R手册(Time Series)--zoo
  6. git之合并分支|git如何合并分支
  7. Xcode创建c语言方案及调试
  8. AlibabaProtect 卸载 windows系统
  9. php控制输出数量,PHP 输出控制
  10. NOI题库 数论 相关的题目 汇总-2022.01.22