hello大家好,我是卷卷毛,我又回来了

这次给大家带来一个支持回复功能的留言板的设计方案,这个留言板现在就正运行在我的个人博客中,它支持简单的留言回复功能,先来看一下效果图:

欢迎大家来留言板逛逛呀,有意见建议可以留言~【留言板】


还挺简洁大方的对吧,不过这次我们讨论的重点不在前端的页面,而是后端的逻辑。

所以还是先说回留言板的开发。

首先,关于使用的技术:

  • 后端整体框架是Spring Boot
  • 数据库使用的是MySQL
  • ORM框架使用的是Mybatis

设计这个功能的过程,我的顺序是数据库->后端->前端

所以在着手开发后台功能之前,首先要对数据库表进行设计。

如果留言板仅支持留言而不支持回复的话,那设计整体就会简单不少,先记录内容,昵称,留言时间等几个简单信息字段。

而由于加上了回复功能,这就会产生一些难题。

对回复功能的探讨

设计回复功能,一个绕不过去的问题就是回复消息和被回复消息的关联方式。

简单一些,我们可以在每条留言中加上一个字段记录被回复的留言id,像这样:

对于一条回复,该字段是被回复留言的id,对于一条留言,该字段就为0。这样就可以区分留言和回复啦。
于是按照这个设计思路,查询时可以根据这个字段联结表自身,获取到一条留言及其回复。

而如果我们更进一步,需求对回复也能够回复,那么这样的设计就存在问题。

如果需要两层回复,那么就是联结两次自身,三层就是四次。。。。。

可是谁知道用的时候,留言者会回复多少层呢?万一在留言板对开线了,多少层可都不够用的。。。

那么上面的设计有一个问题就是只能满足有限层的回复,究其原因,是因为其数据结构是一棵树,而且没有深度限制,任何一个节点下面都可以扩展新的节点。

我们来简单模拟一段留言:

这样的树形结构,不好查还只是一方面的原因,另一方面,即使将整个树结构查询出来,在评论区也不便于展示。

为了解决这个问题,我们观察各方留言板,评论区的设计方案。会发现他们也在避免出现对树形结构进行嵌套的问题。

一种可行的解决方案,也是博主使用的方案,是在查询时仅保留节点和根节点之间的祖孙关系,节点之间则按照发布时间先后排序成线性结构,并记录父节点

简单点说,就是每个回复除了记录被回复的记录,还要记录下最初的留言id,在查询时,先根据回复记录id获取到被回复记录的信息(主要是昵称),再根据最初留言id进行查询分组,小组内按照时间先后排序。

形象一点,就是:

查出来是这样:

其实就是除了根,其他部分的树都给拍扁了,但是之间的链接关系还在。

数据库表及model设计

于是,加上回复的根留言id以及一个控制字段,最终的表设计如下:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for note
-- ----------------------------
DROP TABLE IF EXISTS `note`;
CREATE TABLE `note`  (`n_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '留言id',`content` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '留言内容',`nickname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '留言昵称',`time` datetime(0) NULL DEFAULT NULL COMMENT '留言时间',`res_id` int(0) NULL DEFAULT NULL COMMENT '回复对象id',`reply_post` int(0) NULL DEFAULT NULL COMMENT '留言所属条目',`is_delete` int(0) NULL DEFAULT 0 COMMENT '是否删除(1删除 0不删除)',PRIMARY KEY (`n_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 52 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

完成了对表的设计,接着就是后台中的对象类:
里面出现了一些新的变量,

  • respondent回复对象的昵称
  • follows回复列表,这个就是拍扁了的树体部分。只有根留言有
import java.util.List;public class Note {private String id;          //idprivate String nickname;    //昵称private String content;     //内容private String time;        //发布时间private String respondent;    //回复对象昵称private String resId;       //回复对象idprivate String replyPost;   //根留言idprivate List<Note> follows; //回复列表,仅根留言有public String getId() {return id;}public void setId(String id) {this.id = id;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String getTime() {return time;}public void setTime(String time) {this.time = time;}public String getRespondent() {return respondent;}public void setRespondent(String respondent) {this.respondent = respondent;}public String getReplyPost() {return replyPost;}public void setReplyPost(String replyPost) {this.replyPost = replyPost;}public List<Note> getFollows() {return follows;}public void setFollows(List<Note> follows) {this.follows = follows;}@Overridepublic String toString() {return "Note [id=" + id + ", nickname=" + nickname + ", content=" + content + ", time=" + time + ", respondent="+ respondent + ", replyPost=" + replyPost + ", follows=" + follows + "]";}public String getResId() {return resId;}public void setResId(String resId) {this.resId = resId;}
}

为了便于演示,mapper接口中,仅放置添加和查询两个接口:

import java.util.List;import org.apache.ibatis.annotations.Param;import com.none.blog.model.Note;public interface NoteMapper {//获取所有未被删除的留言List<Note> getAll();//添加一条留言int addNote(@Param("note")Note note);
}

对应mapper.xml实现:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.none.blog.mapper.NoteMapper"><resultMap type="note" id="noteWithFollows"><!--留言的结果集映射,由于查询结果设计嵌套,字段众多,因此需要为字段定义别名根留言使用note_开头,回复使用follow_开头--><id property="id" column="note_id"/><result property="nickname" column="note_nickname"/><result property="content" column="note_content"/><result property="time" column="note_time"/><collection property="follows" javaType="list" ofType="note" columnPrefix="follow_"><id property="id" column="id"/><result property="nickname" column="nickname"/><result property="content" column="content"/><result property="time" column="time"/><result property="respondent" column="respondent"/><result property="resId" column="res_id"/><result property="replyPost" column="reply_post"/></collection></resultMap><insert id="addNote">insert intonote(content,nickname,time,reply_post,res_id)value(#{note.content},#{note.nickname},#{note.time},#{note.replyPost},#{note.resId})</insert><select id="getAll" resultMap="noteWithFollows">selectn1.n_id      as note_id,n1.content       as note_content,n1.time         as note_time,n1.nickname    as note_nickname,n2.n_id        as follow_id,n2.content         as follow_content,n2.nickname       as follow_nickname,n2.time          as follow_time,n2.res_id        as follow_res_id,n2.reply_post  as follow_reply_post,n2.is_delete   as follow_is_delete,n3.nickname     as follow_respondentfromnote n1LEFT JOIN note n2 on n1.n_id = n2.reply_postLEFT JOIN note n3 on n2.res_id = n3.n_idwheren1.is_delete = 0andn1.reply_post = 0order by n1.time desc,n2.time</select>
</mapper>

后台剩余设计

完成了对mapper层的设计,剩下controller层和service层。

在controller层,我们提供三个对外接口:

  • getAll获取所有未被删除的留言
  • addMetaNote添加一条元留言
  • addFollowNote添加一条回复留言
package com.none.blog.controller;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.none.blog.model.Note;
import com.none.blog.service.NoteService;
import com.none.blog.util.DateUtil;@RestController
@CrossOrigin   //为了便于调试,特别在此开启跨域
@RequestMapping("note")
public class NoteController {@AutowiredNoteService ns;@AutowiredDateUtil date;        //自定义日期工具,获取当前时间戳/*添加一条元留言,需要传递参数:content:内容nickname:昵称    */@RequestMapping("addMetaNote")public int addMetaNote(Note note) {System.out.println("加入一条元留言:" + note);/*为元留言设置基础额外信息*/note.setTime(date.getCurrentDateTime());note.setReplyPost("0");note.setResId("0");note.setRespondent("");return ns.addNote(note);}/*添加一条回复,需要传递参数content:内容nickname:昵称resId:回复对象idreplyPost:根留言id*/@RequestMapping("addFollowNote")public int addFollowNote(Note note) {System.out.println("加入一条回复留言:" + note);note.setTime(date.getCurrentDateTime());return ns.addNote(note);}@RequestMapping("getAll")public List<Note> getAll(){System.out.println("获取所有评论列表");return ns.getAll();}
}

service层:

package com.none.blog.service;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.none.blog.mapper.NoteMapper;
import com.none.blog.model.Note;@Service
public class NoteService {@AutowiredNoteMapper nm;public int addNote(Note note) {// TODO Auto-generated method stubreturn nm.addNote(note);}public List<Note> getAll() {// TODO Auto-generated method stubreturn nm.getAll();}
}

前端部分代码,相信小伙伴们可以在博主的网站中拿到。(F12->source

代码就不贴在这里占篇幅啦,溜了溜了,下回再见~

【JavaWeb】如何实现支持回复功能的留言板相关推荐

  1. php做一个留言回复,php实现留言板功能的方法

    本文主要介绍了php实现留言板功能的步骤方法解析.具有很好的参考价值.下面跟着小编一起来看下吧 简单的PHP留言板制作 做基础的留言板功能 需要三张表: 员工表,留言表,好友表 首先造一个登入页面: ...

  2. android中留言板功能,Android -- 留言板的简单实现

    [实例简介] Android -- 留言板的简单实现,适用于初学者参考demo,交流学习 [实例截图] [核心代码] Android--留言板的简单实现 └── Android -- 留言板的简单实现 ...

  3. 个人博客网站——留言及多级回复功能

    文章目录 新增留言 留言显示 重点:多层留言功能实现 通常情况下,在博客网站中,无论是文章下的评论还是单独的留言,都会有多级的回复功能.这里我们主要介绍多级回复功能的留言实现. 新增留言 在这里的新增 ...

  4. phpcms留言板功能的实现

    文章目录 phpcms如何```实现留言板```功能? 1. 留言板插件下载 及 使用说明: 2. 解压并安装 3. 代码调用教程 4. 参考代码1:(附图) 5. 参考代码2:(附图) 6. 后台接 ...

  5. 微信公众平台开发之留言板

    微信公众平台开发之留言板是方便用户互相之间交流的最好方法.关注微信公号的用户之间是不能进行对话的.为了方便用户之间的交流留言板起到了非常大的作用.当用户进入留言板后能够在上面留言,互相回复,这样全部的 ...

  6. Struts2实现的吊炸天留言板系统(包含完整源+mysql数据库+bootstraps3)源码以及课程报告下载地址!

    javaweb高级编程的课程设计,留言板系统的课程报告,由于在评论区竟然有小伙伴说我源码有很多错误,还给了我很低的评分,我想这是对大家和我是不公平的!我真的是无语,所以把课程报告贴出来让大家看看,源码 ...

  7. 去沸点路上的留言板之旅

    最终成为了计算机专业的学生,出乎意料. 大一上我们结束C语言的学习,虽然结业成绩很优异,但我却有众多的疑惑与迷茫.已学完一门计算机语言,为什么我还是只会做课本上的一些数学算法题,面对计算机这个深奥的黑 ...

  8. 仿空间留言板简易界面设置

    html <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8 ...

  9. JSP+SQL实现留言功能(含留言回复功能),附源码

    注:新版本源码在另一篇博客中:点击跳转 一.开发环境 MyEclipse8.6+WampServer+MySQL 这里用到Apache,是因为我用了他来连接数据库. 项目中还用到了一个jar包,mys ...

最新文章

  1. 深入浅出说编译原理(一)
  2. 汇编语言--串处理指令
  3. 跟我一起写 Makefile(六)
  4. Nacos配置中心-命名空间与配置分组
  5. 配置树莓派linux的内核和编译并将镜像拷贝至树莓派
  6. mmap和munmap对文件进行操作(读写等)
  7. scanf()函数错误把输入缓存里的回车作为一次字符输入
  8. C#LeetCode刷题之#674-最长连续递增序列( Longest Continuous Increasing Subsequence)
  9. 疫情之下,精准测试的智能可信模式正在成为中流砥柱
  10. win10开机,内存占用过高
  11. 超详细步骤 | 如何用小程序 SDK 实现电商评价模
  12. 为什么实验是领英 DNA 的核心部分?
  13. tpcc-mysql安装测试与使用生成对比图
  14. 【HDU7068】 Dota2 Pro Circuit(双端队列,模拟)
  15. 聚类和分类算法的区别
  16. php物料编码生成器,物料编码生成器下载|
  17. 搜款网根据关键词取商品列表 API 返回值说明
  18. ⚡【图像描述】pytorch_image_caption
  19. YTU_3313: Barnicle(模拟)
  20. 美国人在世界各地随意干扰别国内政,发动战争,你认为这样做得对吗?

热门文章

  1. 成为资本顾旋:我们如何成为创新奇智最早外部机构投资者
  2. 逆向分析练习七(反转链表)
  3. error: could not create '/usr/local/lib/python2.7/dist-packages/virtualenv_support': Permission deni
  4. better-scroll的使用
  5. 计算机如何通过命令来打开蓝牙,win7如何运用fsquirt.exe命令来实现蓝牙传输文件...
  6. 马云透露新商机:2018抓住这三大行业将暴富一大批人
  7. Java的数组和Arrays和List
  8. 机械师M7精英版鼠标控制驱动安装教程
  9. Simulink电力电子仿真——(一)概述2
  10. Unity3d-英雄联盟登录界面(1-界面构造)