网络规划设计 网站建设,大连市住建局官方网,汉服网站的建设,做网站赚钱从今天开始我们来写一个新项目#xff0c;这个项目是一个完整的校园论坛的项目。主要功能模块#xff1a;用户登录注册#xff0c;帖子发布和热帖排行#xff0c;点赞关注#xff0c;发送私信#xff0c;消息通知#xff0c;社区搜索等。这篇文章我们先试着写一下用户的…从今天开始我们来写一个新项目这个项目是一个完整的校园论坛的项目。主要功能模块用户登录注册帖子发布和热帖排行点赞关注发送私信消息通知社区搜索等。这篇文章我们先试着写一下用户的登录注册功能。
我们做web项目一般web项目是主要解决浏览器和服务器之间交互的问题。而浏览器和服务器是由一次一次的请求交互的。因此任何功能都可拆解成若干次请求其实只要掌握好每次请求的执行过程按照步骤开发每一次请求基本上项目就可以逐步完善起来。
一次请求的执行过程 其实最好是可以把功能做拆解第一步先实现什么效果第二步再完善这个效果。因为你不可能一下子就一步到位写出完整的代码的是吧
所以这就是我的思路我是想着一个功能一个功能的搞定。这篇文章来搞定开发社区首页。 首页有什么不就是帖子还有用户头像还有分页嘛因此接下来我们就实现这三个功能。 社区首页模块大致结构
entity文件夹Page.java
DAO层DiscussionMapper
Service层DiscussionPostMapper
Controller层HomeController Dao层---DiscussPostMapper
Mapper
public interface DiscussPostMapper {ListDiscussPost 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 CacheLoaderString, ListDiscussPost() {NullableOverridepublic ListDiscussPost 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 CacheLoaderInteger, Integer() {NullableOverridepublic Integer load(NonNull Integer key) throws Exception {logger.debug(load post rows from DB.);return discussPostMapper.selectDiscussPostRows(key);}});}public ListDiscussPost 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);ListDiscussPost list discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit(), orderMode);ListMapString, Object discussPosts new ArrayList();if (list ! null) {for (DiscussPost post : list) {MapString, 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;}}这个实体类用于在分页查询中保存分页相关的信息例如当前页码、每页显示的数量、数据总数等以便在前端页面进行分页展示和生成分页链接。 至此社区首页的一些简单的功能就实现了。其实这并不复杂就是代码有点多而已。