仿牛客网项目---社区首页的开发实现

从今天开始我们来写一个新项目,这个项目是一个完整的校园论坛的项目。主要功能模块:用户登录注册,帖子发布和热帖排行,点赞关注,发送私信,消息通知,社区搜索等。这篇文章我们先试着写一下用户的登录注册功能。

我们做web项目,一般web项目是主要解决浏览器和服务器之间交互的问题。而浏览器和服务器是由一次一次的请求交互的。因此,任何功能都可拆解成若干次请求,其实只要掌握好每次请求的执行过程,按照步骤开发每一次请求,基本上项目就可以逐步完善起来。

一次请求的执行过程:

其实最好是可以把功能做拆解,第一步先实现什么效果,第二步再完善这个效果。因为你不可能一下子就一步到位写出完整的代码的,是吧?

所以这就是我的思路,我是想着一个功能一个功能的搞定。这篇文章来搞定开发社区首页。

首页有什么?不就是帖子,还有用户头像,还有分页嘛,因此接下来我们就实现这三个功能。

社区首页模块大致结构

entity文件夹:Page.java

DAO层:DiscussionMapper

Service层:DiscussionPostMapper

Controller层:HomeController

Dao层---DiscussPostMapper

@Mapper
public interface DiscussPostMapper {List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit, int orderMode);// @Param注解用于给参数取别名,// 如果只有一个参数,并且在<if>里使用,则必须加别名.int selectDiscussPostRows(@Param("userId") int userId);int insertDiscussPost(DiscussPost discussPost);DiscussPost selectDiscussPostById(int id);int updateCommentCount(int id, int commentCount);int updateType(int id, int type);int updateStatus(int id, int status);int updateScore(int id, double score);}

这是一个名为DiscussPostMapper的接口,用于定义帖子相关的数据库操作方法 :

  1. selectDiscussPosts(int userId, int offset, int limit, int orderMode):根据用户ID、偏移量、限制数量和排序方式从数据库中查询帖子列表。

  2. selectDiscussPostRows(int userId):查询帖子总数。根据用户ID统计数据库中的帖子数量。

  3. insertDiscussPost(DiscussPost discussPost):将帖子信息插入数据库。

  4. selectDiscussPostById(int id):根据帖子ID从数据库中查询帖子信息。

  5. updateCommentCount(int id, int commentCount):更新帖子的评论数量。根据帖子ID更新帖子的评论数量信息。

  6. updateType(int id, int type):更新帖子的类型。根据帖子ID更新帖子的类型信息。

  7. updateStatus(int id, int status):更新帖子的状态。根据帖子ID更新帖子的状态信息。

  8. updateScore(int id, double score):更新帖子的分数。根据帖子ID更新帖子的分数信息。

Service层---DiscussPostService

@Service
public class DiscussPostService {@PostConstructpublic void init() {// 初始化帖子列表缓存postListCache = Caffeine.newBuilder().maximumSize(maxSize).expireAfterWrite(expireSeconds, TimeUnit.SECONDS).build(new CacheLoader<String, List<DiscussPost>>() {@Nullable@Overridepublic List<DiscussPost> load(@NonNull String key) throws Exception {if (key == null || key.length() == 0) {throw new IllegalArgumentException("参数错误!");}String[] params = key.split(":");if (params == null || params.length != 2) {throw new IllegalArgumentException("参数错误!");}int offset = Integer.valueOf(params[0]);int limit = Integer.valueOf(params[1]);// 二级缓存: Redis -> mysqllogger.debug("load post list from DB.");return discussPostMapper.selectDiscussPosts(0, offset, limit, 1);}});// 初始化帖子总数缓存postRowsCache = Caffeine.newBuilder().maximumSize(maxSize).expireAfterWrite(expireSeconds, TimeUnit.SECONDS).build(new CacheLoader<Integer, Integer>() {@Nullable@Overridepublic Integer load(@NonNull Integer key) throws Exception {logger.debug("load post rows from DB.");return discussPostMapper.selectDiscussPostRows(key);}});}public List<DiscussPost> findDiscussPosts(int userId, int offset, int limit, int orderMode) {if (userId == 0 && orderMode == 1) {return postListCache.get(offset + ":" + limit);}logger.debug("load post list from DB.");return discussPostMapper.selectDiscussPosts(userId, offset, limit, orderMode);}public int findDiscussPostRows(int userId) {if (userId == 0) {return postRowsCache.get(userId);}logger.debug("load post rows from DB.");return discussPostMapper.selectDiscussPostRows(userId);}public int addDiscussPost(DiscussPost post) {if (post == null) {throw new IllegalArgumentException("参数不能为空!");}// 转义HTML标记post.setTitle(HtmlUtils.htmlEscape(post.getTitle()));post.setContent(HtmlUtils.htmlEscape(post.getContent()));// 过滤敏感词post.setTitle(sensitiveFilter.filter(post.getTitle()));post.setContent(sensitiveFilter.filter(post.getContent()));return discussPostMapper.insertDiscussPost(post);}public DiscussPost findDiscussPostById(int id) {return discussPostMapper.selectDiscussPostById(id);}public int updateCommentCount(int id, int commentCount) {return discussPostMapper.updateCommentCount(id, commentCount);}public int updateType(int id, int type) {return discussPostMapper.updateType(id, type);}public int updateStatus(int id, int status) {return discussPostMapper.updateStatus(id, status);}public int updateScore(int id, double score) {return discussPostMapper.updateScore(id, score);}}

这是一个名为DiscussPostService的服务类,用于处理帖子相关的业务逻辑。这段代码是真的烦,一大堆东西,不过我总结了一下,大概这段代码的功能差不多是这样的:

  1. 通过DiscussPostMapper进行数据库操作,包括查询帖子列表、帖子总数,插入帖子,根据帖子ID查询帖子信息,以及更新帖子的评论数量、类型、状态和分数。

  2. 使用SensitiveFilter进行敏感词过滤,对帖子的标题和内容进行转义和过滤。

  3. 使用Caffeine缓存库对帖子列表和帖子总数进行缓存,提高访问性能。缓存设置了最大容量和过期时间。

  4. 在初始化方法init()中,配置了帖子列表缓存和帖子总数缓存的加载方式,当缓存中不存在数据时,会从数据库中加载数据。

  5. 提供了方法如findDiscussPosts()findDiscussPostRows()来获取帖子列表和帖子总数,如果缓存中有数据,则直接从缓存中获取,否则从数据库中获取。

  6. 提供了方法如addDiscussPost()来添加帖子,对帖子的标题和内容进行处理后插入数据库。

  7. 该服务类使用了注解@Service,表示该类是一个Spring的服务组件。

Controller层---HomeController

@Controller
public class HomeController implements CommunityConstant {@RequestMapping(path = "/", method = RequestMethod.GET)public String root() {return "forward:/index";}@RequestMapping(path = "/index", method = RequestMethod.GET)public String getIndexPage(Model model, Page page,@RequestParam(name = "orderMode", defaultValue = "0") int orderMode) {// 方法调用前,SpringMVC会自动实例化Model和Page,并将Page注入Model.// 所以,在thymeleaf中可以直接访问Page对象中的数据.page.setRows(discussPostService.findDiscussPostRows(0));page.setPath("/index?orderMode=" + orderMode);List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit(), orderMode);List<Map<String, Object>> discussPosts = new ArrayList<>();if (list != null) {for (DiscussPost post : list) {Map<String, Object> map = new HashMap<>();map.put("post", post);User user = userService.findUserById(post.getUserId());map.put("user", user);long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId());map.put("likeCount", likeCount);discussPosts.add(map);}}model.addAttribute("discussPosts", discussPosts);model.addAttribute("orderMode", orderMode);return "/index";}@RequestMapping(path = "/error", method = RequestMethod.GET)public String getErrorPage() {return "/error/500";}@RequestMapping(path = "/denied", method = RequestMethod.GET)public String getDeniedPage() {return "/error/404";}
}

这是一个名为HomeController的控制器类,用于处理主页相关的请求。

  1. 通过DiscussPostService获取帖子相关的信息,包括帖子列表和帖子总数。

  2. 通过UserService获取用户相关的信息,包括发帖用户的信息。

  3. 通过LikeService获取帖子的点赞数量。

  4. 提供了root()方法,将根路径的请求转发到"/index"路径。

  5. 提供了getIndexPage()方法,处理主页的GET请求,根据页面参数orderMode获取帖子列表,并将数据添加到Model中供前端页面渲染。

entity文件夹---Page

/*** 封装分页相关的信息.*/
public class Page {// 当前页码private int current = 1;// 显示上限private int limit = 10;// 数据总数(用于计算总页数)private int rows;// 查询路径(用于复用分页链接)private String path;public int getCurrent() {return current;}public void setCurrent(int current) {if (current >= 1) {this.current = current;}}public int getLimit() {return limit;}public void setLimit(int limit) {if (limit >= 1 && limit <= 100) {this.limit = limit;}}public int getRows() {return rows;}public void setRows(int rows) {if (rows >= 0) {this.rows = rows;}}public String getPath() {return path;}public void setPath(String path) {this.path = path;}/*** 获取当前页的起始行** @return*/public int getOffset() {// current * limit - limitreturn (current - 1) * limit;}/*** 获取总页数** @return*/public int getTotal() {// rows / limit [+1]if (rows % limit == 0) {return rows / limit;} else {return rows / limit + 1;}}/*** 获取起始页码** @return*/public int getFrom() {int from = current - 2;return from < 1 ? 1 : from;}/*** 获取结束页码** @return*/public int getTo() {int to = current + 2;int total = getTotal();return to > total ? total : to;}}

这个实体类用于在分页查询中保存分页相关的信息,例如当前页码、每页显示的数量、数据总数等,以便在前端页面进行分页展示和生成分页链接。

至此,社区首页的一些简单的功能就实现了。其实这并不复杂,就是代码有点多而已。

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

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

相关文章

个人玩航拍,如何申请无人机空域?

我们在《年会不能停》一文中&#xff0c;有分享我们在西岭雪山用无人机拍摄的照片和视频&#xff0c;有兴趣可以去回顾。 春节的时候&#xff0c;趁着回老家一趟&#xff0c;又将无人机带了回去&#xff0c;计划拍一下老家的风景。 原本以为穷乡僻壤的地方可以随便飞&#xf…

Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析

3. SpringBoot原理 SpringBoot使我们能够集中精力地去关注业务功能的开发&#xff0c;而不用过多地关注框架本身的配置使用。而我们前面所讲解的都是面向应用层面的技术&#xff0c;接下来我们开始学习SpringBoot的原理&#xff0c;这部分内容偏向于底层的原理分析。 在剖析Sp…

Go开发 入门以VSCode为例

一、Go环境搭建 1.1 安装 进入Golang官网 https://go.dev&#xff0c;点击 Download 若无法打开网页可以使用国内的Go语言中文网 https://studygolang.com/dl 进入下载 找到合适的平台点击链接下载即可&#xff08;这里以Windows距离&#xff09; 下载完成后 Next Next 安…

threejs 大场景下,对小模型进行贴图处理

接上篇小模型的删除☞threeJS 大模型中对小模型进行删除-CSDN博客 针对已有模型&#xff0c;根据数据状态进行贴图处理&#xff0c;例如&#xff1a;机房内电脑告警状态、电脑开关机状态下的不同状态贴图等 示例模型还是以丛林小屋为例&#xff1a;针对该模型中的树干进行贴图…

Android进阶之路 - RecyclerView停止滑动后Item自动居中(SnapHelper辅助类)

之前一直没注意 SnapHelper 辅助类的功能&#xff0c;去年的时候看到项目中仅通过俩行代码设置 RecyclerView 后就提升了用户体验&#xff0c;觉得还是很有必要了解一下&#xff0c;尝试过后才发现其 PagerSnapHelper、LinearSnapHelper 子类可以作用于不同场景&#xff0c;且听…

加速AI测试领域的进化,顶尖专家与名校教授强强联合,助你快速成为人工智能测试领域的精英

随着人工智能在各行各业的广泛应用&#xff0c;学习并掌握AI技术在软件测试中的应用变得至关重要。不仅能使你跟上行业的发展趋势&#xff0c;还能提升你的竞争力。而且&#xff0c;市场对具备AI测试技能的测试工程师的需求正日益增长&#xff0c;这使得掌握这些技能能够帮助你…

走进中国电车领跑企业“NI蔚来”丨共谋商业,共话ESG

期盼与热望将冬季的寒冷拂去&#xff0c;复旦大学-华盛顿大学EMBA项目迎来了一位新朋友——美国圣路易斯华盛顿大学奥林商学院的新任院长Michael Mazzeo教授。Mazzeo院长在上海进行了为期3天的访问。这里是 Mazzeo院长上任后国际访问交流之旅的第一站。      漫步校园&…

【Python_Zebra斑马打印机编程学习笔记(四)】ZPL的一些简单指令

ZPL的一些简单指令 ZPL的一些简单指令前言一、ZPL 介绍二、ZPL 语法解析1、标签开始、标签结束2、标签原点位置设置3、标签长度设置4、标签文本打印深度设置5、标签打印宽度设置6、标签方向设置7、标签元素定位8、标签绘制矩形9、标签输入字段10、标签设置字段字体、大小11、标…

Go 互斥锁的实现原理?

Go sync包提供了两种锁类型&#xff1a;互斥锁sync.Mutex 和 读写互斥锁sync.RWMutex&#xff0c;都属于悲观锁。 概念 Mutex是互斥锁&#xff0c;当一个 goroutine 获得了锁后&#xff0c;其他 goroutine 不能获取锁&#xff08;只能存在一个写者或读者&#xff0c;不能同时…

STM32 IIC协议基础概念

文章目录 前言一、IIC协议介绍二、IIC硬件框图和程序层次三、IIC协议1.IIC协议通信流程2.IIC的引脚为什么需要加入上拉电阻3.IIC的引脚为什么需要配置为开漏输出 四、STM32 IIC硬件结构总结 前言 本篇文章将带大家学习IIC通信协议的一些基础概念和使用。 一、IIC协议介绍 I2…

jsjiami.v7关于js加密运行环境的探索

浏览器环境、Node.js 环境和 vm2 环境之间存在一些区别&#xff0c;包括全局对象、核心模块和一些环境特定的 API。下面是一些区别的简要概述&#xff0c;以及一些代码示例来突显它们之间的不同。 1. 浏览器环境&#xff1a; 全局对象&#xff1a; 浏览器环境&#xff1a; 全…

数据结构·栈和队列

1. 栈 1.1 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一段称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵守 后进先出 LIFO(Last In First Out)的原则&#xff0c;后进来的数…

YOLOv8 DeepSORT实现智能交通监控-改进yolo单目测距及速度测量-流量计数

YOLOv8 DeepSORT是一种基于目标检测和跟踪技术的智能交通监控系统。它基于YOLOv8&#xff0c;通过加入DeepSORT算法实现目标跟踪&#xff0c;同时还改进了YOLOv8的单目测距及速度测量技术和流量计数功能。 该系统可以通过摄像头或视频源实时捕获图像&#xff0c;并自动检测和跟…

web安全学习笔记【20】——信息打点(10)

信息打点-公众号服务&Github监控&供应链&网盘泄漏&证书图标邮箱资产 #知识点&#xff1a; 1、业务资产-应用类型分类 2、Web单域名获取-接口查询 3、Web子域名获取-解析枚举 4、Web架构资产-平台指纹识别 ------------------------------------ 1、开源-CMS指纹…

【刷题】 Leetcode 1022.从根到叶的二进制数之和

刷题 1022.从根到叶的二进制数之和题目描述&#xff1a;思路一&#xff08;dfs深搜万能版&#xff09;思路二 &#xff08;栈迭代巧解版&#xff09;总结 Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff01;下一篇文章见&#xff…

SpringBoot 自定义注解实现操作日志记录

文章目录 前言正文一、项目结构介绍二、核心类2.1 核心注解2.1.1 CLog 日志注解2.1.2 ProcessorBean 处理器bean 2.2 切面类2.3 自定义线程池2.4 工具类2.4.1 管理者工具类 2.5 测试2.5.1 订单创建处理器2.5.2 订单管理者2.5.3 订单控制器2.5.4 测试报文2.5.5 测试结果 附录1、…

【Java题】调整奇数位于偶数之前(超简单版)

题目&#xff1a; 调整数组顺序使得奇数位于偶数之前。调整之后&#xff0c;不关心大小顺序。 如数组&#xff1a;[1,2,3,4,5,6,7,8,9] 调整后可能是&#xff1a;[1, 9,3,7,5, 6, 4, 8, 2] 代码&#xff1a; import java.util.Arrays;public class Main {public static voi…

将python程序打包为exe格式

1. 安装pyinstaller winr打开命令窗口 输入&#xff1a; pip install pyinstaller输入命令后会自动安装pyinstaller 2. 打包 进入你的代码所在位置&#xff0c;输入cmd 在弹出的窗口中输入 pyinstaller --onefile your_script.pyyour_script.py修改为你需要打包的程序名字 …

ElasticSearch架构介绍及原理解析

ElasticSearch架构介绍及原理解析文章目录 一、Elasticsearch是什么&#xff1f;1.简介2.历史与发展3.有关概念1.cluster2.shards3.replicas4.recovery5.river6.gateway7.discovery.zen8.Transport 4.安装 二、ElasticSearch架构介绍及原理解析1.基本架构1.1 进程节点1.2 负载均…

简述操作系统内存管理

这篇可是真枯涩啊&#xff0c;哈哈&#xff0c;老早在学操作系统的时候整理的文章&#xff0c;没加润色&#xff0c;单纯从个人网站迁移过来。 操作系统内存管理的目的是将线性物理地址用抽象的逻辑地址空间&#xff0c;从而保护物理地址。此外&#xff0c;可以独立地址空间&am…