摘要:以上就是对评论模块的设计与功能实现,欢迎各位大佬提出代码优化建议,共同成长代码出自开源项目,致力于打造全平台型全栈精品开源项目。
评论模块在很多系统中都有,CodeRiver河码 作为类似程序员客栈的沟通协作平台自然也不会少。
前端界面是参考了简书的评论模块,专门写了一篇文章介绍实现步骤:
vue + element-ui + scss 仿简书评论模块
感兴趣的可以看看。
项目地址:https://github.com/cachecats/...
代码在 根目录/java/comments-service
文章将分三部分介绍:
前端界面分析
数据库设计
功能实现
一、前端界面分析先看看前端界面长什么样,知道了前端需要什么数据,就知道数据库该怎么设计了。
首先评论的主体可以是人、项目、资源,所以要有一个 type 字段标明这条评论的类型。
以项目为例,一个项目下面可能会有多条评论。每条评论其实分为两种,一种是直接对项目的评论,称之为父评论吧;另一种是对已有评论的评论,称为子评论。
梳理一下关系,每个项目可能有多个父评论,每个父评论可能有多个子评论。项目与父评论,父评论与子评论,都是一对多的关系。
由此可知数据库应该分为两个表,一个存储父评论,一个存储子评论。
再看都需要什么字段,先分析主评论。必须要有的是项目id,得知道是对谁评论的,叫 ownerId 吧。还有评论者的头像、昵称、id,还有评论时间、内容、点赞个数等。
子评论跟父评论的字段差不多,只是不要点赞数量。
二、数据库设计分析了界面,知道需要什么字段,就开始设计数据库吧。
评论主表(父评论表)
CREATE TABLE `comments_info` ( `id` varchar(32) NOT NULL COMMENT "评论主键id", `type` tinyint(1) NOT NULL COMMENT "评论类型:对人评论,对项目评论,对资源评论", `owner_id` varchar(32) NOT NULL COMMENT "被评论者id,可以是人、项目、资源", `from_id` varchar(32) NOT NULL COMMENT "评论者id", `from_name` varchar(32) NOT NULL COMMENT "评论者名字", `from_avatar` varchar(512) DEFAULT "" COMMENT "评论者头像", `like_num` int(11) DEFAULT "0" COMMENT "点赞的数量", `content` varchar(512) DEFAULT NULL COMMENT "评论内容", `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT "创建时间", `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT "修改时间", PRIMARY KEY (`id`), KEY `owner_id` (`owner_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT="评论主表";
评论回复表(子评论表)
CREATE TABLE `comments_reply` ( `id` int(11) NOT NULL AUTO_INCREMENT, `comment_id` varchar(32) NOT NULL COMMENT "评论主表id", `from_id` varchar(32) NOT NULL COMMENT "评论者id", `from_name` varchar(32) NOT NULL COMMENT "评论者名字", `from_avatar` varchar(512) DEFAULT "" COMMENT "评论者头像", `to_id` varchar(32) NOT NULL COMMENT "被评论者id", `to_name` varchar(32) NOT NULL COMMENT "被评论者名字", `to_avatar` varchar(512) DEFAULT "" COMMENT "被评论者头像", `content` varchar(512) DEFAULT NULL COMMENT "评论内容", `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT "创建时间", `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT "修改时间", PRIMARY KEY (`id`), KEY `comment_id` (`comment_id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT="评论回复表";三、功能实现
项目采用 SpringCloud 微服务架构,评论模块跟其他模块的关联性不强,可以抽出为一个多带带的服务 comments-service 。
数据实体对象数据实体对象 CommentsInfo
package com.solo.coderiver.comments.dataobject; import lombok.Data; import org.hibernate.annotations.DynamicUpdate; import javax.persistence.Entity; import javax.persistence.Id; import java.util.Date; /** * 评论表主表 */ @Entity @Data @DynamicUpdate public class CommentsInfo { //评论主键id @Id private String id; //评论类型。1用户评论,2项目评论,3资源评论 private Integer type; //被评论者的id private String ownerId; //评论者id private String fromId; //评论者名字 private String fromName; //评论者头像 private String fromAvatar; //获得点赞的数量 private Integer likeNum; //评论内容 private String content; //创建时间 private Date createTime; //更新时间 private Date updateTime; }
数据实体对象 CommentsReply
package com.solo.coderiver.comments.dataobject; import lombok.Data; import org.hibernate.annotations.DynamicUpdate; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import java.util.Date; /** * 评论回复表 */ @Entity @Data @DynamicUpdate public class CommentsReply { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; //评论主表id private String commentId; //评论者id private String fromId; //评论者名字 private String fromName; //评论者头像 private String fromAvatar; //被评论者id private String toId; //被评论者名字 private String toName; //被评论者头像 private String toAvatar; //评论内容 private String content; //创建时间 private Date createTime; //更新时间 private Date updateTime; }数据库操作仓库 repository
操作数据库暂时用的是 Jpa ,后期可能会增加一份 mybatis 的实现。
CommentsInfoRepository
package com.solo.coderiver.comments.repository; import com.solo.coderiver.comments.dataobject.CommentsInfo; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface CommentsInfoRepository extends JpaRepository{ List findByOwnerId(String ownerId); }
CommentsReplyRepository
package com.solo.coderiver.comments.repository; import com.solo.coderiver.comments.dataobject.CommentsReply; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface CommentsReplyRepository extends JpaRepositoryService 接口封装{ List findByCommentId(String commentId); }
为了代码更健壮,要把数据库的操作封装一下
CommentsInfoService
package com.solo.coderiver.comments.service; import com.solo.coderiver.comments.dataobject.CommentsInfo; import java.util.List; public interface CommentsInfoService { /** * 保存评论 * @param info * @return */ CommentsInfo save(CommentsInfo info); /** * 根据被评论者的id查询评论列表 * @param ownerId * @return */ ListfindByOwnerId(String ownerId); }
CommentsReplyService
package com.solo.coderiver.comments.service; import com.solo.coderiver.comments.dataobject.CommentsReply; import java.util.List; public interface CommentsReplyService { /** * 保存评论回复 * @param reply * @return */ CommentsReply save(CommentsReply reply); /** * 根据评论id查询回复 * @param commentId * @return */ ListfindByCommentId(String commentId); }
接口的实现类
CommentsInfoServiceImpl
package com.solo.coderiver.comments.service.impl; import com.solo.coderiver.comments.dataobject.CommentsInfo; import com.solo.coderiver.comments.repository.CommentsInfoRepository; import com.solo.coderiver.comments.service.CommentsInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class CommentsInfoServiceImpl implements CommentsInfoService { @Autowired CommentsInfoRepository repository; @Override public CommentsInfo save(CommentsInfo info) { return repository.save(info); } @Override public ListfindByOwnerId(String ownerId) { return repository.findByOwnerId(ownerId); } }
CommentsReplyServiceImpl
package com.solo.coderiver.comments.service.impl; import com.solo.coderiver.comments.dataobject.CommentsReply; import com.solo.coderiver.comments.repository.CommentsReplyRepository; import com.solo.coderiver.comments.service.CommentsReplyService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class CommentsReplyServiceImpl implements CommentsReplyService { @Autowired CommentsReplyRepository repository; @Override public CommentsReply save(CommentsReply reply) { return repository.save(reply); } @Override public List控制层 ControllerfindByCommentId(String commentId) { return repository.findByCommentId(commentId); } }
Controller 层分发请求,并返回前端需要的数据
package com.solo.coderiver.comments.controller; @RestController @Api(description = "评论相关接口") public class CommentsController { @Autowired CommentsInfoService infoService; @Autowired CommentsReplyService replyService; @PostMapping("/save") @ApiOperation("保存评论") @Transactional public ResultVO saveComments(@Valid CommentsInfoForm form, BindingResult bindingResult) { if (bindingResult.hasErrors()) { throw new CommentsException(ResultEnums.PARAMS_ERROR.getCode(), bindingResult.getFieldError().getDefaultMessage()); } //将 CommentsInfoForm 里的数据拷贝到 CommentsInfo CommentsInfo info = new CommentsInfo(); BeanUtils.copyProperties(form, info); // 生成并设置评论的主键id info.setId(KeyUtils.genUniqueKey()); CommentsInfo result = infoService.save(info); if (result == null) { throw new CommentsException(ResultEnums.SAVE_COMMENTS_FAIL); } return ResultVOUtils.success(); } @GetMapping("/get/{ownerId}") @ApiOperation("根据 ownerId 查询评论") @ApiImplicitParam(name = "ownerId", value = "被评论者id") public ResultVO getCommentsByOwnerId(@PathVariable("ownerId") String ownerId) { ListinfoList = infoService.findByOwnerId(ownerId); //将 CommentsInfo 转换为 CommentsInfoDTO List infoDTOS = infoList.stream().map(info -> { CommentsInfoDTO dto = new CommentsInfoDTO(); BeanUtils.copyProperties(info, dto); return dto; }).collect(Collectors.toList()); return ResultVOUtils.success(infoDTOS); } @PostMapping("/save-reply") @ApiOperation("保存评论回复") @Transactional public ResultVO saveReply(@Valid CommentsReplyForm form, BindingResult bindingResult) { if (bindingResult.hasErrors()) { throw new CommentsException(ResultEnums.PARAMS_ERROR.getCode(), bindingResult.getFieldError().getDefaultMessage()); } CommentsReply reply = new CommentsReply(); BeanUtils.copyProperties(form, reply); CommentsReply result = replyService.save(reply); if (result == null) { throw new CommentsException(ResultEnums.SAVE_COMMENTS_FAIL); } return ResultVOUtils.success(); } @GetMapping("/get-reply/{commentId}") @ApiOperation("通过commentId获取评论回复") public ResultVO getReplyByCommentId(@PathVariable("commentId") String commentId) { List replyList = replyService.findByCommentId(commentId); //将 CommentsReply 转换为 CommentsReplyDTO List replyDTOS = replyList.stream().map(reply -> { CommentsReplyDTO dto = new CommentsReplyDTO(); BeanUtils.copyProperties(reply, dto); return dto; }).collect(Collectors.toList()); return ResultVOUtils.success(replyDTOS); } }
代码中工具类和枚举类请到 github 上查看源码。
以上就是对评论模块的设计与功能实现,欢迎各位大佬提出代码优化建议,共同成长~
代码出自开源项目 CodeRiver,致力于打造全平台型全栈精品开源项目。
coderiver 中文名 河码,是一个为程序员和设计师提供项目协作的平台。无论你是前端、后端、移动端开发人员,或是设计师、产品经理,都可以在平台上发布项目,与志同道合的小伙伴一起协作完成项目。
coderiver河码 类似程序员客栈,但主要目的是方便各细分领域人才之间技术交流,共同成长,多人协作完成项目。暂不涉及金钱交易。
计划做成包含 pc端(Vue、React)、移动H5(Vue、React)、ReactNative混合开发、Android原生、微信小程序、java后端的全平台型全栈项目,欢迎关注。
项目地址:https://github.com/cachecats/...
您的鼓励是我前行最大的动力,欢迎点赞,欢迎送小星星✨ ~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/17825.html
摘要:无论你是前端后端移动端开发人员,或是设计师产品经理,都可以在平台上发布项目,与志同道合的小伙伴一起协作完成项目。 全平台全栈开源项目 coderiver 今天终于开始前后端联调了~ 首先感谢大家的支持,coderiver 在 GitHub 上开源两周,获得了 54 个 Star,9 个 Fork,5 个 Watch。 这些鼓励和认可也更加坚定了我继续写下去的决心~ 再次感谢各位大佬! ...
摘要:前段时间设计了系统的评论模块,并写了篇文章评论模块后端数据库设计及功能实现讲解。下面就对评论模块进行优化改造,首先更改表结构,合成一张表。评论表不存用户头像的话,需要从用户服务获取。用户服务提供获取头像的接口,两个服务间通过通信。 前段时间设计了系统的评论模块,并写了篇文章 评论模块 - 后端数据库设计及功能实现 讲解。 大佬们在评论区提出了些优化建议,总结一下: 之前评论一共分...
摘要:个人认为单页面应用的优势相当明显前后端职责分离,架构清晰前端进行交互逻辑,后端负责数据处理。上面的这种单页面应用也有其相应的一种开发工作流,当然这种工作流也适合非单页面应用进行产品功能原型设计。 未经允许,请勿转载。本文同时也发布在我的博客。 (如果对SPA概念不清楚的同学可以先自行了解相关概念) 平时喜欢做点小页面来玩玩,并且一直采用单页面应用(Single Page Appl...
阅读 3042·2021-09-22 15:52
阅读 2912·2019-08-30 15:55
阅读 2707·2019-08-30 15:53
阅读 2460·2019-08-30 13:21
阅读 1627·2019-08-30 13:10
阅读 2486·2019-08-26 12:09
阅读 2572·2019-08-26 10:33
阅读 1809·2019-08-23 18:06