Java+MySQL实现评论功能设计开发

一、背景

项目初始版本上线,有时间写点东西记录一下项目中的心得体会,通过这个项目学习了很多,要写下来的有很多,先从评论功能开始吧。由于项目需要增加评论功能,之前并无此方面的经验,因此项目开始的一段时间都在寻思着如何进行评论功能的设计。上网搜索一波发现有很多优秀的第三方评论插件可以使用,本来准备直接采用的,但是心里始终有点疙瘩,可能是评论数据放在别人那里不放心的原因,或可能是想一探这些评论系统的究竟,因此最终决定自行设计开发这么一套评论功能。效果截图如下所示,采用的是MySQL数据库,编程语言用的Java。

二、评论系统的概述:

评论功能是用户表达对某一主题的想法的很好的一种方式,优秀的评论系统能很好地提高社区的活跃度。各大主流网站也都提供了相应的评论支持。比如:贴吧,新闻类门户网站(APP),UC浏览器等等。

各大网站侧重点不同,对评论功能的要求就不一样,设计出来的评论系统自然就不一样。可能会有:①只可以进行评论,不可以回复,②既可以进行评论,也可以进行回复,然后在这个基础上可能会增加一些额外的功能,比如评论的折叠,审核,优选等。另外,一个良好的UI显示也是非常重要的,能给用户一个直观的视觉上的体验也是评论功能不可或缺的一个要素,毕竟用户都是具有很强的审美能力的,用户的使用体验决定了项目的需求。

对于本项目,设计的是,既可以评论,也可以进行回复,评论和回复分开存储。在显示上,评论和回复显示的位置不同,回复相较于评论向右靠一些,这样,看起来比较舒适,当然也可以设置成其他的样式。评论会显示评论者头像,回复不会。

评论的管理:后台系统应该具备基本的评论管理功能,比如:删除,折叠,优选,排序。这些功能的实现依赖于数据库表的设计,所以,在开始设计的时候,要想清楚自己的项目需要哪些功能。

三、数据库表的设计:

本评论功能采用评论和回复分离的方式进行存储,一共设计了两张表,一张用户评论表(comment),一张针对评论的回复表(comment_reply)。评论表主要保存对文章或者回答的评论,回复表保存对每一条评论的回复。

评论表(comment)如下图:主要包括了:评论ID(作为回复表的主键),回答(文章)ID,评论者ID,评论内容,点赞数,评论时间,审核状态

评论回复表(comment_reply)如下图:主要包括了:评论ID,用户ID,被回复人ID,回复内容,点赞数,回复时间。

两张表通过comment_id联系起来(并没有设置主外键,主要是不想维护起来太麻烦),获取某一答案的评论及回复步骤:根据answer_id找到所有的评论,然后,遍历所有的评论,根据comment_id查询到所有的回复(评论者的基本信息,例如头像,名称等需要额外查询)。需要注意的是,在评论和回复数据较多的情况下做好分页处理。

四、程序的实现:

采用Java语言进行编程的实现,使用的SSM框架。主要的功能代码如下所示(因为项目有通知功能,看的时候可以略过这部分,跟单纯的评论功能没有太大关系,但是一般要有通知,后面有时间会写站内通知的设计与开发博客):

4.1 添加评论代码如下:(获取到评论相关的参数,然后进行向数据库表插入)

public int addComment(Comment comment) {

try {

Answer commentAnswer = answerMapper.selectByPrimaryKey(comment.getAnswerId());

Long commentId = IDUtils.genItemId();//评论ID

Date createtime = new Date();

//1,填补comment对象的其他参数,进行插入

comment.setCommentId(commentId);

comment.setState(1);//状态: 0 待审核,1通过,2不通过

comment.setPraseCount(0);//一开始插入的点赞数设置为0

comment.setCreatetime(createtime);

comment.setUpdatetime(createtime);

commentMapper.insert(comment);//插入comment记录

//2,跟新Answer的相关一条数据,提示评论数+1

commentAnswer.setCommentNum((commentAnswer.getCommentNum()==null?0:commentAnswer.getCommentNum()) + 1);

answerMapper.updateByPrimaryKeySelective(commentAnswer);

//3,向提醒表插一条数据。这条评论是发给谁的,通知表里面的userId就是谁

if (comment.getUserId() != commentAnswer.getUserId()) { //自己评论自己不会有通知

Remind remind = new Remind();

remind.setRemindId(commentId);

remind.setUserId(commentAnswer.getUserId());

remind.setFromUserId(comment.getUserId());

//commentType:1评论回答,2评论别人的评论,3关注,4支持,5反对,6添加回答

remind.setRemindType(1);

//已读:0否,1是

remind.setReadStatus(0);//否

remind.setCreatetime(createtime);

//插入通知内容,以json的形式存储

RemindContent remindComment = new RemindContent();

remindComment.setContentId(commentAnswer.getAnswerId());

remind.setContent(JsonUtils.objectToJson(remindComment));//通知内容。回答问题的Id

remindMapper.insert(remind);

}

//返回1代表成功

return 1;

} catch (Exception e) {

e.printStackTrace();

return 2;

}

}

4.2 添加回复代码:(前台会传来评论的ID,然后,封装成回复对象进行插入,一个评论ID会对应很多回复)

public int addCommentReply(CommentReply commentReply) {

Long commentId = IDUtils.genItemId();//评论ID

Date createtime = new Date();

commentReply.setPraseCount(0);

commentReply.setCreatetime(createtime);

int retVal = commentReplyMapper.insert(commentReply);

//3,向提醒表插一条数据。这条评论是发给谁的,通知表里面的userId就是谁

if (commentReply.getReplyuserId() != commentReply.getUserId()) {

Remind remind = new Remind();

remind.setRemindId(commentId);

remind.setUserId(commentReply.getReplyuserId());

remind.setFromUserId(commentReply.getUserId());

//commentType:1评论回答,2评论别人的评论,3关注,4支持,5反对,6添加回答

remind.setRemindType(2);

//已读:0是,1否

remind.setReadStatus(1);

remind.setCreatetime(createtime);

remind.setContent(commentReply.getCommentId()+"");

remindMapper.insert(remind);

}

return retVal;

}

4.3获取某一回答的评论和回复(评论分页返回,但是回复没有分页,后面会优化,使用的是pagehelper插件):

public PageBean listAnswerComments(Long answerId,Integer pageNum,Integer pageSize) {

try {

CommentExample commentExample = new CommentExample();

commentExample.setOrderByClause("createtime DESC");

Criteria commentCriteria = commentExample.createCriteria();

commentCriteria.andAnswerIdEqualTo(answerId);

PageHelper.startPage(pageNum, pageSize);

List commentList = commentMapper.selectByExampleWithBLOBs(commentExample);//获取具有分页结果的评论数据

List commentStatusList = new ArrayList<>();

for (Comment comment : commentList) {

CommentStatus commentStatus = new CommentStatus(); //评论返回的具体对象

CommentReplyExample example = new CommentReplyExample();

com.pn.mini.model.CommentReplyExample.Criteria criteria = example.createCriteria();

criteria.andCommentIdEqualTo(comment.getCommentId());

List commentReplyList = commentReplyMapper.selectByExample(example);

List commentReplyStatusList = new ArrayList<>();

for (CommentReply commentReply2 : commentReplyList) {

UserBaseInfo commentUser = userBaseInfoMapper.selectByPrimaryKey(commentReply2.getUserId());

UserBaseInfo commentReplyUser = userBaseInfoMapper.selectByPrimaryKey(commentReply2.getReplyuserId());

CommentReplyStatus commentReplyStatus = new CommentReplyStatus();

commentReplyStatus.setCommentId(commentReply2.getCommentId());

commentReplyStatus.setContent(commentReply2.getContent());

commentReplyStatus.setCreatetime(commentReply2.getCreatetime());

commentReplyStatus.setPraseCount(commentReply2.getPraseCount());

commentReplyStatus.setReplyuserId(commentReply2.getReplyuserId());

commentReplyStatus.setReplyuserName(commentReplyUser.getUserName());

commentReplyStatus.setUserId(commentUser.getUserId());

commentReplyStatus.setUserName(commentUser.getUserName());

commentReplyStatusList.add(commentReplyStatus);

}

UserBaseInfo commentUserBaseInfo = userBaseInfoMapper.selectByPrimaryKey(comment.getUserId());

CommentIntegrate commentIntegrate = new CommentIntegrate();

commentIntegrate.setAnswerId(comment.getAnswerId());

commentIntegrate.setAvatar(commentUserBaseInfo.getAvatar());

commentIntegrate.setCommentId(comment.getCommentId());

commentIntegrate.setContent(comment.getContent());

commentIntegrate.setCreatetime(comment.getCreatetime());

commentIntegrate.setPraseCount(comment.getPraseCount());

commentIntegrate.setState(comment.getState());

commentIntegrate.setUpdatetime(comment.getUpdatetime());

commentIntegrate.setUserId(comment.getUserId());

commentIntegrate.setUserName(commentUserBaseInfo.getUserName());

//拼接一条评论的返回对象

commentStatus.setCommentIntegrate(commentIntegrate);

commentStatus.setCommentReplyStatusList(commentReplyStatusList);

commentStatusList.add(commentStatus);

}

PageBean recCommentItemBean = null;//接口返回的对象

PageInfo pageInfo = new PageInfo<>(commentList);

recCommentItemBean = new PageBean<>(commentStatusList);

recCommentItemBean.setDataList(commentStatusList);

recCommentItemBean.setPageNum(pageInfo.getPageNum());

recCommentItemBean.setPages(pageInfo.getPages());

recCommentItemBean.setPageSize(pageInfo.getPageSize());

recCommentItemBean.setSize(pageInfo.getSize());

recCommentItemBean.setTotal(pageInfo.getTotal());

return recCommentItemBean;

} catch (Exception e) {

e.printStackTrace(); //出现异常返回null,controller根据此判断此处调用是否成功

return null;

}

}

4.4  优化思考:

① 回复没有分页返回,回复数据量大的时候需要分页,在在获取回复的时候分页一下即可。

② 获取一条信息,需要再去查询用户表,获取用户的信息,这样就会导致获取一条回答的评论和回复需要查询N次数据表,思考的是增加冗余字段(用户名,用户头像),然后减少这方面的查询开销,当用户头像和名称更改的时候,同步更改这里面的数据,但是一般用户的这方面信息更改较少,总的来说,增加这个冗余字段还是能很大程度提高效率的。

③优化后的数据库表如下(忽略hot_value这样的字段,不同项目有不同需求):

五:总结与反思(后续优化的方向):

虽然评论功能开发完毕,在目前也可以正常的使用,待使用程序的用户的增加,流量的扩大后仍需要继续优化,不然在用户的使用体验上可能会很糟糕,尤其是当数据量大的时候,用户访问可能会感觉到有些慢。不足之处其一:在于获取评论的回复,每次读取数据的时候,需要遍历每一条评论,然后去查找这个评论下的所有回复,之后返回这些数据,这样就会造成获取一片文章的评论需要多次查找数据库,效率就会很低,下一步准备从数据库设计和程序实现两个方面去思考如何优化;其二在于:所有文章的评论都在一张表里面,评论的回复也都在一张表里面,这样就会导致表的条目很多,下一步优化的思路集中于分表操作,具体的实现还在思考中。。。。

评论功能的设计还有很多需要优化的地方,欢迎对这方面有了解的小伙伴一起交流。

mysql制作评论功能_Java+MySQL实现评论功能设计开发相关推荐

  1. mysql制作学生成绩单_java+mysql做的学生成绩管理系统

    [实例简介] java+ mysql 学生 成绩 管理 系统 完整版 [实例截图] [核心代码] 成绩管理系统 └── 成绩管理系统 ├── bin │   └── wyf │   └── cgq │ ...

  2. html页面中加入评论功能,JavaScript实现简单评论功能

    本文实例为大家分享了JavaScript实现简单评论功能的具体代码,供大家参考,具体内容如下 body{ /*background-image: url(../img/91R58PIC3n2_1024 ...

  3. mysql中文乱码解决_java+mysql中文乱码问题

    乱码问题原因有多种,其中有一种是由于MySQL默认使用 ISO-8859-1 ( 即Latin1 ) 字符集,而JAVA内部使用Unicode编码,因此在JAVA中向MYSQL数据库插入数据时,或者读 ...

  4. mysql查找附近算法_Java+MySQL实现附近功能

    [TOC] 其实对于那种地理位置不会变的两个主体之间的距离,最好是直接将结果静态化.也就是直接写死在配置里. 比如,找自己家附近的地铁站. 这种情况下,一般而言"家"这个主体是不会 ...

  5. Java mysql获取行数_java – MySQL查询获取球体中的行(X,Y,Z坐标)?

    我正在制作一个名为Minecraft with Bukkit API的游戏插件. 我有一个名为Reinforcements的数据库表,其中包含以下字段:x integer,y integer,z in ...

  6. mysql数据推荐算法_Java+Mysql实现简单在线电影、音乐、图书推荐系统 基于用户的协同过滤推荐算法实现 源代码下载...

    # Java+Mysql实现简单在线电影.音乐.图书等推荐系统(基于用户的协同过滤推荐算法) 一.项目简介 1.开发工具和实现技术 MyEclipse10,jdk1.7,mysql5.5,tomca ...

  7. java点击上传上传mysql并显示图片_java + mysql + jdbc实现图片上传

    首先在数据库中用mediumblob来保存图片的位置 Mysql中可以存储大文件数据,一般使用的BLOB对象.如图片,视频等等. BLOB是一个二进制大对象,可以容纳可变数量的数据.因为是二进制对象, ...

  8. mysql odbc连接池_Java Mysql连接池配置和案例分析--超时异常和处理

    前言: 最近在开发服务的时候, 发现服务只要一段时间不用, 下次首次访问总是失败. 该问题影响虽不大, 但终究影响用户体验. 观察日志后发现, mysql连接因长时间空闲而被关闭, 使用时没有死链检测 ...

  9. mysql jdbc连接 优化_java+mysql连接的优化

    作者通过经历的一个项目实例,介绍Java代码优化的过程,总结了优化Java程序的一些最佳实践,分析了进行优化的方法,并解释了性能提升的原因.作者从多个角度分析导致性能低的原因,并逐个进行优化,最终使得 ...

最新文章

  1. 高并发下的秒杀系统架构设计实战!
  2. stm32影子寄存器、预装载寄存器,TIM_OC1PreloadConfig和TIM_ARRPreloadConfig的作用
  3. CMakeLists.txt
  4. 【解决办法】你目前是以 ***的身份登录。请注销,然后使用你用于阅读组织电子邮件的帐户登录 Outlook
  5. loading怎么关闭 vant_vant-ui组件调用Dialog弹窗异步关闭操作
  6. 【图像超分辨率】RS Image SR Based on Visual Saliency Analysis
  7. linux防火墙ddos,Linux iptables防火墙详解 + 配置抗DDOS***策略实战
  8. html中el表达式遍历list,使用EL表达式访问集合
  9. Android Studio Error:Connection timed out: connect.解决方案
  10. 【特别版】计算机哲学对学习生活借鉴的几个例子
  11. arraylist/vector add()方法诡异之---多次add进去的对象最终都变成最后一次add进去的对象值...
  12. PowerPoint媒体更加适合这样的场合
  13. RegCleanPro (微软认证-注册表清理软件)
  14. 麒麟服务器开启多个终端,厉害:麒麟多开同步器
  15. Java Web开发技术应用——监听器
  16. 降维(Dimensionality Reduction) 是机器学习中的一种重要的特征处理手段
  17. 老马闲评数字化(4)做数字化会不会被供应商拿捏住
  18. Double 判断小数位数
  19. Vim配置及使用技巧
  20. 计算机考研自我介绍大概多少字,1分钟自我介绍多少字

热门文章

  1. python毕业设计作品基于django框架校园网站系统毕设成品(3)后台管理功能
  2. 【读书笔记】精通正则表达式
  3. 51单片机摇摇棒改字原理详解
  4. POP3协议命令原始码及工作原理-PHP教程,邮件处理
  5. FFMPEG之 Ubuntu系统上配置MP3和AMR编解码工具
  6. CAXA三维CAD教程:简单几步设计房屋
  7. TP4056/4057/4054充电不转灯闪FAE技术
  8. 网络安全工程师-①文件共享服务器
  9. [Tool] 常用开发工具注册码(持续更新)
  10. 医学影像组学之病理切片分割(免费训练数据,标注数据,免费代码,免费教程)三天走完影像组学全部流程