仿牛客网项目---社区首页的开发实现
从今天开始我们来写一个新项目,这个项目是一个完整的校园论坛的项目。主要功能模块:用户登录注册,帖子发布和热帖排行,点赞关注,发送私信,消息通知,社区搜索等。这篇文章我们先试着写一下用户的登录注册功能。
我们做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的接口,用于定义帖子相关的数据库操作方法 :
-
selectDiscussPosts(int userId, int offset, int limit, int orderMode):根据用户ID、偏移量、限制数量和排序方式从数据库中查询帖子列表。 -
selectDiscussPostRows(int userId):查询帖子总数。根据用户ID统计数据库中的帖子数量。 -
insertDiscussPost(DiscussPost discussPost):将帖子信息插入数据库。 -
selectDiscussPostById(int id):根据帖子ID从数据库中查询帖子信息。 -
updateCommentCount(int id, int commentCount):更新帖子的评论数量。根据帖子ID更新帖子的评论数量信息。 -
updateType(int id, int type):更新帖子的类型。根据帖子ID更新帖子的类型信息。 -
updateStatus(int id, int status):更新帖子的状态。根据帖子ID更新帖子的状态信息。 -
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的服务类,用于处理帖子相关的业务逻辑。这段代码是真的烦,一大堆东西,不过我总结了一下,大概这段代码的功能差不多是这样的:
-
通过
DiscussPostMapper进行数据库操作,包括查询帖子列表、帖子总数,插入帖子,根据帖子ID查询帖子信息,以及更新帖子的评论数量、类型、状态和分数。 -
使用
SensitiveFilter进行敏感词过滤,对帖子的标题和内容进行转义和过滤。 -
使用Caffeine缓存库对帖子列表和帖子总数进行缓存,提高访问性能。缓存设置了最大容量和过期时间。
-
在初始化方法
init()中,配置了帖子列表缓存和帖子总数缓存的加载方式,当缓存中不存在数据时,会从数据库中加载数据。 -
提供了方法如
findDiscussPosts()和findDiscussPostRows()来获取帖子列表和帖子总数,如果缓存中有数据,则直接从缓存中获取,否则从数据库中获取。 -
提供了方法如
addDiscussPost()来添加帖子,对帖子的标题和内容进行处理后插入数据库。 -
该服务类使用了注解
@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的控制器类,用于处理主页相关的请求。
-
通过
DiscussPostService获取帖子相关的信息,包括帖子列表和帖子总数。 -
通过
UserService获取用户相关的信息,包括发帖用户的信息。 -
通过
LikeService获取帖子的点赞数量。 -
提供了
root()方法,将根路径的请求转发到"/index"路径。 -
提供了
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;}}
这个实体类用于在分页查询中保存分页相关的信息,例如当前页码、每页显示的数量、数据总数等,以便在前端页面进行分页展示和生成分页链接。
至此,社区首页的一些简单的功能就实现了。其实这并不复杂,就是代码有点多而已。
相关文章:
仿牛客网项目---社区首页的开发实现
从今天开始我们来写一个新项目,这个项目是一个完整的校园论坛的项目。主要功能模块:用户登录注册,帖子发布和热帖排行,点赞关注,发送私信,消息通知,社区搜索等。这篇文章我们先试着写一下用户的…...
虚拟机部署Sentry步骤,国内地址
Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC 👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资源分…...
[Android View] 可绘制形状 (Shape Xml)
一切以官方文档为主 官方文档https://developer.android.com/guide/topics/resources/drawable-resource?hlzh-cn#Shape 什么是可绘制形状 可以理解为用xml文件来描述一个简单的Drawable图形,比如说以下这段xml就可以用来描述一个白色的圆形: <?…...
[游戏开发][虚幻5]新建项目注意事项
鼠标右键点击Client.uproject文件,可以看到三个比较关键的选项, 启动游戏,生成sln解决方案,切换引擎版本 断点调试 C代码重要步骤 如果你想断点调试C代码,则必须使用使用代码编译启动引擎,你需要做几个操作…...
防考试作弊切屏
防考试作弊切屏 方法一:监听页面失焦聚焦事件:防止任何操作 监听考试页面失焦事件记录切出时间页面聚焦时累积记录切入时间,累积时间大于1分钟自动交卷并移除时间页面销毁移出事件***bug:必须把事件回调定义为方法,在…...
浅析能耗监测系统在大型数据中心的应用
彭姝麟 Acrelpsl 1总体设计 大型数据中心能耗监测系统包含硬件和软件两大部分,其硬件组成主要包括监控服务器、主机设备、网络设备、环境参数传感器、通风模块等,总体采集逻辑采用三级监控体系。一级为主机设备,作为系统的应用层,…...
robotframework-去除字符串左侧的0的方法
参考文章:https://www.cnblogs.com/xiaodouzhou-123/p/10333759.html...
【Linux C | 网络编程】getaddrinfo 函数详解及C语言例子
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
深度学习主流开源框架:Caffe、TensorFlow、Pytorch、Theano、Keras、MXNet、Chainer
2.6 深度学习主流开源框架 表2.1 深度学习主流框架参数对比 框架关键词总结 框架关键词基本数据结构(都是高维数组)Caffe“在工业中应用较为广泛”,“编译安装麻烦一点”BlobTensorFlow“安装简单pip”TensorPytorch“定位:快…...
[Linux] vim及gdb的使用
Linux工具使用 Vim编辑器使用Vim的基本概念vim的基本操作vim正常模式命令集vim底行模式命令集 gdb调试器使用背景使用 Vim编辑器使用 Vim的基本概念 vim我们所需要掌握的有三种模式,分别是命令模式、插入模式、底行模式。 正常/普通/命令模式 控制屏幕光标移动&a…...
Android WebView访问网页+自动播放视频+自动全屏+切换横屏
一、引言 近期,我发现电视家、火星直播等在线看电视直播的软件都已倒闭,而我奶奶也再无法通过这些平台看电视了。她已六十多岁,快七十岁啦。这些平台的倒下对我来说其实没有多大的影响,但是对于文化不多的她而言,生活中…...
php PhpSpreadsheet 读取日期变数字问题解决
问题描述: 使用PhpSpreadsheet 读取表格数据,日期格式读取后变成数字,如下图: 解决方案: $cell $sheet->getCell(H . $row)->getValue(); $toTimestamp \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimes…...
前端架构: 脚手架包管理工具之lerna的全流程开发教程
Lerna 1 )文档 Lerna 文档 https://www.npmjs.com/package/lernahttps://lerna.js.org [请直达这个链接] 使用 Lerna 帮助我们做包管理,并不复杂,中间常用的命令并不是很多这里是命令直达:https://lerna.js.org/docs/api-referen…...
[安洵杯 2019]easy_serialize_php1
打开题目 题目源码: <?php$function $_GET[f];function filter($img){$filter_arr array(php,flag,php5,php4,fl1g);$filter /.implode(|,$filter_arr)./i;return preg_replace($filter,,$img); }if($_SESSION){unset($_SESSION); }$_SESSION["user&q…...
【前端素材】推荐优质在线通用果蔬商城电商网页eStore平台模板(附源码)
一、需求分析 1、系统定义 通用果蔬网站是指专门提供各类果蔬产品展示和销售的在线平台。它将不同种类的新鲜水果、蔬菜、干果、坚果等聚集在一起,为消费者提供方便、快捷的购物渠道。 2、功能需求 通用果蔬网站是指专门提供各类果蔬产品展示和销售的在线平台。…...
开源软件的商业模式探析:开放与盈利的平衡
写在开头 开源软件的概念和应用已经成为了现代科技领域中的一个重要组成部分。然而,虽然开源软件的价值和影响力得到了广泛认可,但如何在开放的环境中找到商业盈利的平衡却是一个颇具挑战性的问题。本文将深入探讨开源软件的商业模式,从基本…...
使用全局事件总线实现任意组件间的通讯
本文以vue2中爷孙组件通讯为例,需求是点击孙组件的按钮,实现关闭爷组件的弹窗。 全局事件总线是通过Vue实例的事件系统来实现组件之间的通讯,可以方便地在任何组件中进行事件的触发和监听。 以下是使用全局事件总线实现爷孙组件通讯的步骤&a…...
文件基础和文件fd
文章目录 预备知识C语言的文件接口系统调用文件fd 正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能学习网站, 通俗易懂,风趣幽默,忍不住分享一下给大家。 点击跳转到网站。 预备知识 我们平时说文件就是说文件里…...
3dgs学习(二)—— 3d高斯与协方差矩阵及其几何意义
协方差矩阵与3d高斯 3d高斯与椭球与协方差矩阵 3d高斯,及3维空间内的正态分布。 通过一元正态分布的坐标系图像不难想象,3维空间中的正态分布点集中在一片椭球空间中,各方向长轴取决于各方向正态分布的方差。 而协方差矩阵通过计算多元之…...
ZStack Cube超融合入选IDC《中国超融合基础架构市场评估》报告
近日,IDC发布了《中国超融合基础架构市场评估,2023》。IDC针对中国超融合基础架构市场的发展现状展开了调研,明确了最终用户构建融合型云平台的痛点和难点,阐述了市场中各技术服务提供商的服务方案和优势,并对未来中国…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案
一、延迟敏感行业面临的DDoS攻击新挑战 2025年,金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征: AI驱动的自适应攻击:攻击流量模拟真实用户行为,差异率低至0.5%,传统规则引…...
Linux基础开发工具——vim工具
文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...
leetcode_69.x的平方根
题目如下 : 看到题 ,我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历,我们是整数的平方根,所以我们分两…...
