第3章Spring Boot进阶,开发社区核心功能【仿牛客网社区论坛项目】

第3章Spring Boot进阶,开发社区核心功能【仿牛客网社区论坛项目】

  • 前言
  • 推荐
  • 项目总结
    • 第3章Spring Boot进阶,开发社区核心功能
      • 1.过滤敏感词
      • 2.发布帖子
      • 3.帖子详情
      • 4.事务管理
      • 5.显示评论
      • 6.添加评论
      • 7.私信列表
      • 8.发送私信
      • 9.统一处理异常
      • 10.统一记录日志
  • 最后

前言

2023-7-28 21:18:08

以下内容源自【Java面试项目】
仅供学习交流使用

推荐

仿牛客网项目【面试】

项目总结

第3章Spring Boot进阶,开发社区核心功能

1.过滤敏感词

一:构建敏感词的前缀树
二:过滤文本

SensitiveFilter

package com.jsss.community.util;import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.io.*;
import java.util.HashMap;
import java.util.Map;@Component
public class SensitiveFilter {private static final Logger logger= LoggerFactory.getLogger(SensitiveFilter.class);// 替换符private static final String REPLACEMENT="***";//根节点private TrieNode rootNode=new TrieNode();@PostConstructpublic void init(){try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");BufferedReader reader=new BufferedReader(new InputStreamReader(is));){String keyword;while ((keyword = reader.readLine())!=null){//添加到前缀树this.addKeyword(keyword);}} catch (IOException e) {logger.error("加载敏感词文件失败"+e.getMessage());}}//将一个敏感词添加到前缀树中private void addKeyword(String keyword) {TrieNode tempNode=rootNode;for (int i = 0; i < keyword.length(); i++) {char c = keyword.charAt(i);TrieNode subNode = tempNode.getSubNode(c);if (subNode==null){//初始化子节点subNode=new TrieNode();tempNode.addSubNode(c,subNode);}//指针指向子节点,进入下一轮循环tempNode=subNode;//设置结束表示if (i==keyword.length()-1){tempNode.setKeyWordEnd(true);}}}/*** 过滤敏感词* @param text 待过滤的文本* @return 过滤后的文本*/public String filter(String text){if (StringUtils.isBlank(text)){return null;}//指针1TrieNode tempNode = rootNode;//指针2int begin=0;//指针3int position=0;//结果StringBuilder sb=new StringBuilder();while (position<text.length()){char c=text.charAt(position);//跳过符号☆if (isSymbol(c)){//若指针1处于根节点,将符号计入结果,让指针2向下走一步if(tempNode==rootNode){sb.append(c);begin++;}//无论符号在开头或中间,指针3都向下走一步position++;continue;}//检查下级节点tempNode=tempNode.getSubNode(c);if (tempNode==null){//以begin开头的字符不是敏感词sb.append(text.charAt(begin));//进入下一个位置position=++begin;//重新指向根节点tempNode=rootNode;}else if (tempNode.isKeyWordEnd()){//发现敏感词,将begin~position字符串替换掉sb.append(REPLACEMENT);//进入下一个位置begin=++position;//重新指向根节点tempNode=rootNode;}else {//检查下一个字符++position;}}//将最后一批字符计入结果,当指针3提前结束sb.append(text.substring(begin));return sb.toString();}//判断是否为符号private boolean isSymbol(Character c){//0x2E80~0x9FFF 东亚文字范围return !CharUtils.isAsciiAlphanumeric(c) &&(c<0x2E80||c>0x9FFF);}//前缀树private class TrieNode{//关键词结束标识private boolean keyWordEnd =false;//子节点(key是下级字符,value是下级结点)private Map<Character,TrieNode> subNodes =new HashMap<>();public TrieNode() {}public void setKeyWordEnd(boolean keyWordEnd) {this.keyWordEnd = keyWordEnd;}public boolean isKeyWordEnd() {return keyWordEnd;}//添加子节点public void addSubNode(Character c,TrieNode node){subNodes.put(c,node);}//获取子节点public TrieNode getSubNode(Character c){return subNodes.get(c);}}}

测试:

SensitiveTests

package com.jsss.community;import com.jsss.community.util.SensitiveFilter;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class SensitiveTests {@Autowiredprivate SensitiveFilter sensitiveFilter;@Testpublic void testSensitiveFilter(){String text="这里可以唱,可以☆跳☆,可以☆rap☆,可☆以☆篮☆球☆,哈哈哈!";String filter = sensitiveFilter.filter(text);System.out.println(filter);// 这里可以***,可以☆***☆,可以☆***☆,可☆以☆***☆,哈哈哈!}
}

sensitive-words.txt

唱
跳
rap
篮球

2.发布帖子

   @RequestMapping(path = "/add",method = RequestMethod.POST)@ResponseBodypublic String addDiscussPost(String title,String content){User user=hostHolder.getUser();if (user==null){return CommunityUtil.getJSONString(403,"你还没有登录");}DiscussPost post=new DiscussPost();post.setUserId(user.getId());post.setTitle(title);post.setContent(content);post.setCreateTime(new Date());discussPostService.addDiscussPost(post);//报错的情况,将来统一处理return CommunityUtil.getJSONString(0,"发布成功!");}

3.帖子详情

  @RequestMapping(path = "/detail/{discussPostId}", method = RequestMethod.GET)public String getDiscussPost(@PathVariable("discussPostId") int discussPostId, Model model,Page page) {// 帖子DiscussPost post = discussPostService.findDiscussPostById(discussPostId);model.addAttribute("post", post);// 作者User user = userService.findUserById(post.getUserId());model.addAttribute("user", user);//点赞数量long likeCount =likeService.findEntityLikeCount(ENTITY_TYPE_POST,discussPostId);model.addAttribute("likeCount",likeCount);//点赞状态int likeStatus=hostHolder.getUser()==null?0:likeService.findEntityLikeStatus(hostHolder.getUser().getId(),ENTITY_TYPE_POST,discussPostId);model.addAttribute("likeStatus",likeStatus);//评论的分页信息page.setLimit(5);page.setPath("/discuss/detail/"+discussPostId);page.setRows(post.getCommentCount());//评论:给帖子的评论//回复:给评论的评论//评论列表List<Comment> commentList = commentService.findCommentsByEntity(CommunityConstant.ENTITY_TYPE_POST, post.getId(), page.getOffset(), page.getLimit());//评论VO列表List<Map<String,Object>> commentVoList =new ArrayList<>();if (commentVoList !=null){for(Comment comment:commentList){//评论VOMap<String,Object> commentVo =new HashMap<>();//评论commentVo.put("comment",comment);//作者commentVo.put("user",userService.findUserById(comment.getUserId()));//点赞数量likeCount =likeService.findEntityLikeCount(ENTITY_TYPE_COMMENT,comment.getId());commentVo.put("likeCount",likeCount);//点赞状态likeStatus=hostHolder.getUser()==null?0:likeService.findEntityLikeStatus(hostHolder.getUser().getId(),ENTITY_TYPE_COMMENT,comment.getId());commentVo.put("likeStatus",likeStatus);//回复列表List<Comment> replyList = commentService.findCommentsByEntity(CommunityConstant.ENTITY_TYPE_COMMENT, comment.getId(), 0, Integer.MAX_VALUE);//回复VO列表List<Map<String,Object>> replyVoList =new ArrayList<>();if (replyList!=null){for (Comment reply :replyList){Map<String,Object> replyVo=new HashMap<>();// 回复replyVo.put("reply", reply);// 作者replyVo.put("user",userService.findUserById(reply.getUserId()));// 回复的目标User target= reply.getTargetId()==0?null:userService.findUserById(reply.getTargetId());replyVo.put("target",target);//点赞数量likeCount =likeService.findEntityLikeCount(ENTITY_TYPE_COMMENT,reply.getId());replyVo.put("likeCount",likeCount);//点赞状态likeStatus=hostHolder.getUser()==null?0:likeService.findEntityLikeStatus(hostHolder.getUser().getId(),ENTITY_TYPE_COMMENT,reply.getId());replyVo.put("likeStatus",likeStatus);replyVoList.add(replyVo);}}commentVo.put("replys",replyVoList);//回复的数量int replyCount = commentService.findCommentCount(CommunityConstant.ENTITY_TYPE_COMMENT, comment.getId());commentVo.put("replyCount",replyCount);commentVoList.add(commentVo);}}model.addAttribute("comments",commentVoList);return "site/discuss-detail";}

4.事务管理

5.显示评论

6.添加评论

   @RequestMapping(path = "/add/{discussPostId}", method = RequestMethod.POST)public String addComment(@PathVariable("discussPostId") int discussPostId, Comment comment) {comment.setUserId(hostHolder.getUser().getId());comment.setStatus(0);comment.setCreateTime(new Date());commentService.addComment(comment);return "redirect:/discuss/detail/" + discussPostId;}

7.私信列表

  	// 私信列表@RequestMapping(path = "/letter/list", method = RequestMethod.GET)public String getLetterList(Model model, Page page) {User user = hostHolder.getUser();// 分页信息page.setLimit(5);page.setPath("/letter/list");page.setRows(messageService.findConversationCount(user.getId()));// 会话列表List<Message> conversationList = messageService.findConversations(user.getId(), page.getOffset(), page.getLimit());List<Map<String, Object>> conversations = new ArrayList<>();if (conversationList != null) {for (Message message : conversationList) {Map<String, Object> map = new HashMap<>();map.put("conversation", message);map.put("letterCount", messageService.findLetterCount(message.getConversationId()));map.put("unreadCount", messageService.findLetterUnreadCount(user.getId(), message.getConversationId()));int targetId = user.getId() == message.getFromId() ? message.getToId() : message.getFromId();map.put("target", userService.findUserById(targetId));conversations.add(map);}}model.addAttribute("conversations", conversations);// 查询未读消息数量int letterUnreadCount = messageService.findLetterUnreadCount(user.getId(), null);model.addAttribute("letterUnreadCount", letterUnreadCount);int noticeUnreadCount = messageService.findNoticeUnreadCount(user.getId(), null);model.addAttribute("noticeUnreadCount", noticeUnreadCount);return "site/letter";}

8.发送私信

	@RequestMapping(path = "/letter/send", method = RequestMethod.POST)@ResponseBodypublic String sendLetter(String toName, String content) {User target = userService.findUserByName(toName);if (target == null) {return CommunityUtil.getJSONString(1, "目标用户不存在!");}Message message = new Message();message.setFromId(hostHolder.getUser().getId());message.setToId(target.getId());if (message.getFromId() < message.getToId()) {message.setConversationId(message.getFromId() + "_" + message.getToId());} else {message.setConversationId(message.getToId() + "_" + message.getFromId());}message.setContent(content);message.setCreateTime(new Date());messageService.addMessage(message);return CommunityUtil.getJSONString(0);}

9.统一处理异常

package com.jsss.community.controller.advice;import com.jsss.community.util.CommunityUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@ControllerAdvice(annotations = Controller.class)
public class ExceptionAdvice {private static final Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);@ExceptionHandler({Exception.class})public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {logger.error("服务器发生异常: " + e.getMessage());for (StackTraceElement element : e.getStackTrace()) {logger.error(element.toString());}String xRequestedWith = request.getHeader("x-requested-with");if ("XMLHttpRequest".equals(xRequestedWith)) {response.setContentType("application/plain;charset=utf-8");PrintWriter writer = response.getWriter();writer.write(CommunityUtil.getJSONString(1, "服务器异常!"));} else {response.sendRedirect(request.getContextPath() + "/error");}}}

10.统一记录日志

package com.jsss.community.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;//@Component
//@Aspect
public class ServiceLogAspect {private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);@Pointcut("execution(* com.jsss.community.service.*.*(..))")public void pointcut() {}@Before("pointcut()")public void before(JoinPoint joinPoint) {// 用户[1.2.3.4],在[xxx],访问了[com.jsss.community.service.xxx()].ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes == null) {return;}HttpServletRequest request = attributes.getRequest();String ip = request.getRemoteHost();String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();logger.info(String.format("用户[%s],在[%s],访问了[%s].", ip, now, target));}}

最后

这篇博客能写好的原因是:站在巨人的肩膀上

这篇博客要写好的目的是:做别人的肩膀

开源:为爱发电

学习:为我而行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/12705.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用ffmpeg从mp3中删除ID3音频标签图像(或元数据)

本文介绍了如何使用ffmpeg从mp3中删除ID3音频标签图像(或元数据)的处理方法&#xff0c;对大家解决问题具有一定的参考价值&#xff0c;需要的朋友们下面随着小编来一起学习吧&#xff01; 问题描述 FFMPEG确实是一个很棒的工具.我知道它可以编辑ID3标签&#xff0c;甚至可以连…

Date计算年龄:

方法一&#xff1a; Date dateSimpleDateFormat(“yyyy-MM-dd”).parse(“2000-08-19); LocalDate localDateLocalDate.now(); LocalDate localDate1date.toInstant.atZone(ZoneId.systemDefualt()).toLocalDate(); Int ageLocalDate localDate1.getYear()-LocalDate local…

照片误删如何恢复?这些方法帮你重拾回忆!

手机照片是我们记录美好时刻的重要工具。但有时我们会因为不小心或者错误操作而导致珍贵照片的丢失。那些与家人、朋友共度的美好时刻、旅途中的风景、重要的纪念日&#xff0c;一旦删除&#xff0c;就如同从记忆中抹去&#xff0c;令人惋惜不已。幸运的是&#xff0c;随着科技…

Spring AOP(概念,使用)

目录 Spring AOPAOP是什么什么是Spring AOPAOP实际开发流程1. 引入依赖2. 编写AOP程序 Spring AOP详解Spring AOP中的核心概念Spring AOP的通知类型六种类型PointCutOrder(切面优先级) Spring AOP AOP是什么 Aspect Oriented Programminig(面向切面编程)切面指的是某一类特定…

Oceanbase 4.3特性解析:用物化视图来优化复杂查询

如果你是一位数据分析师&#xff0c;需要在包含数百万行数据的数据库中频繁地检索特定信息&#xff0c;而每次这样的查询都伴随着复杂的计算&#xff0c;耗费大量时间和资源。你可以考虑采用物化视图这一功能&#xff0c;提高查询效率。 物化视图是什么&#xff1f; 物化视图…

加快推进新质生产力,利驰牵手央视栏目助推电气行业数字化

利驰成功入围《信用中国》 4月22日&#xff0c;《信用中国》栏目选题会在北京顺利举行。利驰软件(苏州)有限公司创始人令永卓受邀参加此次选题会&#xff0c;并成功入围了《信用中国》栏目&#xff0c;利驰软件借助栏目组进入品牌建设与创新的战略新征程。 《信用中国》是一档…

Java-数据库连接(JDBC小白教学)

&#xff01;文章最后附有完整代码&#xff01; 目录 &#x1f516;JDBC概述 &#x1f516;JDBC连接数据库 &#x1f516;添加数据&#xff08;insert&#xff09; &#x1f516;修改数据&#xff08;Update&#xff09; &#x1f516;删除数据&#xff08;delete&#x…

【千帆AppBuidler】零代码构建AI人工智能应用,全网都在喊话歌手谁能应战,一键AI制作歌手信息查询应用

欢迎来到《小5讲堂》 这是《千帆平台》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景创建应用平台地址随机生成快速创建应用头像应用名称应用描述…

VMware Workstation 17.5.2 Pro 发布,产品订阅模式首个重大变更

VMware Workstation 17.5.2 Pro 发布&#xff0c;产品订阅模式首个重大变更 基于 x86 的 Windows、Linux 桌面虚拟化软件 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-workstation-17/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页…

Python 全栈体系【四阶】(四十三)

第五章 深度学习 九、图像分割 3. 常用模型 3.4 DeepLab 系列 3.4.1 DeepLab v1(2015) 3.4.1.1 概述 图像分割和图像分类不一样&#xff0c;要对图像每个像素进行精确分类。在使用CNN对图像进行卷积、池化过程中&#xff0c;会导致特征图尺寸大幅度下降、分辨率降低&…

全志R128 SDK HAL 模块开发指南之PWM

PWM 模块介绍 脉冲宽度调制&#xff08;PWM&#xff09;是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用&#xff0c;方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM 具有以下特点&#xff1a; 支持脉冲&#xff08;脉冲个数可配&#xf…

【java】异常与错误

Throwable包括Error和Expected。 Error Error错误是程序无法处理的&#xff0c;由JVM产生并抛出的。 举例&#xff1a;StackOverflowError \ ThreadDeath Expected Expected异常包括两类&#xff0c;即受检异常(非运行时异常)和非受检异常(运行时异常)&#xff0c;异常往往…

oracle 临时表 在sql 里面用完要删除吗

临时表 在sql 里面用完要删除吗 在Oracle数据库中&#xff0c;如果您使用的是ON COMMIT DELETE ROWS创建的临时表&#xff0c;那么当当前会话结束或者执行了显式的COMMIT或ROLLBACK操作后&#xff0c;表中的数据会自动被清除。这意味着通常情况下&#xff0c;您不需要手动删除…

阿里云服务器下,部署LNMP环境安装wordpress

目录 1 LNMP部署1、简单说明2、nginx部署3、php8 安装4、mysql8安装5、配置 nginx 实现支持 PHP 程序6、安装 php 组件7、测试 2 wordpress部署1、安装2、配置 总结 1 LNMP部署 1、简单说明 首先需要明白&#xff0c;LNMP指的是Linux、Nginx、MySQL、PHP。而如果使用阿里云服…

数字化应用标杆 | 又两家成套厂效率翻倍,利用率高达93%以上!

利驰 联能 & 利驰 俊郎 近日&#xff0c;利驰数字科技&#xff08;苏州&#xff09;有限公司&#xff08;简称利驰软件&#xff09;成功与俊郎电气有限公司&#xff08;简称俊郎电气&#xff09;、浙江联能电气有限公司&#xff08;简称联能电气&#xff09;成功确立了数字…

【全开源】国际版JAVA同城服务美容美发到店服务上门服务系统源码支持Android+IOS+H5

国际版同城服务美容美发到店与上门服务系统&#xff1a;一站式打造美丽新体验 随着人们生活水平的提高和审美观念的升级&#xff0c;美容美发服务已成为人们日常生活中不可或缺的一部分。为了满足全球消费者的多样化需求&#xff0c;我们推出了“国际版同城服务美容美发到店与…

时间管理的误区:为什么你越高效就越没有时间?

在平衡生活和工作的过程中&#xff0c;时间管理无疑很重要。然而&#xff0c;许多人发现在提高效率后&#xff0c;却发现自己越来越感到时间紧迫&#xff0c;仿佛陷入了一个无解的循环。这背后的原因&#xff0c;往往是由于一系列时间管理的误区所致。 一个常见的误区是&…

在 CLion、Dev-C++ 或 Code::Blocks 下面配置 EasyX

前言 本文提供了将 EasyX 适配到 MinGW 上的库文件&#xff0c;并详细介绍如何将 EasyX 配置到 DevCpp 或 CodeBlocks 等以 MinGW 为编译器的集成开发环境。 库文件下载 点击这里下载 easyx4mingw_20220901 点击这里下载 easyx4mingw_20220610 &#xff08;上个版本&#x…

Php 读取execl

安装PhpSpreadsheet composer require phpoffice/phpspreadsheet <?phprequire vendor/autoload.php; // 引入Composer自动加载文件use PhpOffice\PhpSpreadsheet\IOFactory;// 指定Excel文件路径 $filePath path/to/your/excel/file.xlsx;try {// 加载Excel文件$spreadsh…

C++并发:锁

一、前言 C中的锁和同步原语的多样化选择使得程序员可以根据具体的线程和数据保护需求来选择最合适的工具。这些工具的正确使用可以大大提高程序的稳定性和性能&#xff0c;本文讨论了部分锁。 二、std::lock 在C中&#xff0c;std::lock 是一个用于一次性锁定两个或多个互斥…