java 评论回复_评论回复功能设计

本文介绍了如何使用Java JPA设计评论和回复表,通过链表形式存储评论回复,实现类似CSDN的评论显示模式。项目包括Topic和Replay两个实体类,以及相应的DAO和服务层。通过递归方式插入和遍历链表,实现评论和回复的树状展示。
摘要由CSDN通过智能技术生成

以评论为主的显示模式,类似于下面的CSDN的评论显示模式

ac8afb7c9c75

最终效果图

ac8afb7c9c75

效果图

将评论拆分为评论表和回复表,评论挂在各种主题下面,而回复挂在评论下面

我是采用的Jpa建表,所以只需要把实体对象写好就行

ac8afb7c9c75

评论表

ac8afb7c9c75

回复表

先上项目结构图

ac8afb7c9c75

项目结构图

说一下我的思路

1.建立俩张表,回复表回复的id分为回复评论还是回复,用一个int标志判断。

2.想像树状那样显示出来,这里就采取链表的形式存储,一条评论下可能有多人回复,所以存储下一个对象我们使用List来存储,开始的List初始化为private List replays = new ArrayList<>();不然replays.add()的时候会报空指针.

3.因为评论和回复是分开建表的,所以我们还需要单独设置一个评论节点,分别对应上面项目结构图的TopicNode和ReplayNode

4.插入链表和遍历链表都是采用递归方式,有更好的方式欢迎指教。

5.thymeleaf写递归方式和java一样的思路,就是改变了语法而已

每个文件源码和注释

Topic

package com.wg.springdemo.model;

import javax.persistence.*;

@Entity

@Table(name = "topic")

public class Topic {

@Id

@GeneratedValue(strategy = GenerationType.SEQUENCE)

private Long tid;//主键ID

private Long uid;//用户ID

@Column(length = 50)

private String uname;//用户名

@Column(length = 255)

private String uheadurl;//用户头像

@Column(length = 800)

private String tcontent;//评论内容

@Column(length = 20)

private String ttime;//评论时间

public Topic() {

}

public Topic(Long uid, String uname, String uheadurl, String tcontent, String ttime) {

this.uid = uid;

this.uname = uname;

this.uheadurl = uheadurl;

this.tcontent = tcontent;

this.ttime = ttime;

}

public Long getTid() {

return tid;

}

public void setTid(Long tid) {

this.tid = tid;

}

public Long getUid() {

return uid;

}

public void setUid(Long uid) {

this.uid = uid;

}

public String getUname() {

return uname;

}

public void setUname(String uname) {

this.uname = uname;

}

public String getUheadurl() {

return uheadurl;

}

public void setUheadurl(String uheadurl) {

this.uheadurl = uheadurl;

}

public String getTcontent() {

return tcontent;

}

public void setTcontent(String tcontent) {

this.tcontent = tcontent;

}

public String getTtime() {

return ttime;

}

public void setTtime(String ttime) {

this.ttime = ttime;

}

@Override

public String toString() {

return "Topic{" +

"tid=" + tid +

", uid=" + uid +

", uname='" + uname + '\'' +

", uheadurl='" + uheadurl + '\'' +

", tcontent='" + tcontent + '\'' +

", ttime='" + ttime + '\'' +

'}';

}

}

Replay

package com.wg.springdemo.model;

import javax.persistence.*;

@Entity

@Table(name = "replay")

public class Replay {

@Id

@GeneratedValue(strategy = GenerationType.SEQUENCE)

private Long rid;

private Long torrid;//评论id或者回复id 就是有可能是回复评论,也可能是给回复的回复

private int torr;//用来判断上面的哪种情况:1表示回复评论 0表示回复回复

private Long uid;//用户ID

private Long touid;//目标用户id 给谁回复

@Column(length = 50)

private String uname;//用户名

@Column(length = 50)

private String touname;//目标用户名

@Column(length = 255)

private String uheadurl;//用户头像

@Column(length = 800)

private String rcontent;//回复内容

@Column(length = 20)

private String rtime;//回复时间

public Replay() {

}

public Replay(Long torrid, int torr, Long uid, Long touid, String uname, String touname, String uheadurl, String rcontent, String rtime) {

this.torrid = torrid;

this.torr = torr;

this.uid = uid;

this.touid = touid;

this.uname = uname;

this.touname = touname;

this.uheadurl = uheadurl;

this.rcontent = rcontent;

this.rtime = rtime;

}

public Long getRid() {

return rid;

}

public void setRid(Long rid) {

this.rid = rid;

}

public Long getTorrid() {

return torrid;

}

public void setTorrid(Long torrid) {

this.torrid = torrid;

}

public int getTorr() {

return torr;

}

public void setTorr(int torr) {

this.torr = torr;

}

public Long getUid() {

return uid;

}

public void setUid(Long uid) {

this.uid = uid;

}

public Long getTouid() {

return touid;

}

public void setTouid(Long touid) {

this.touid = touid;

}

public String getUname() {

return uname;

}

public void setUname(String uname) {

this.uname = uname;

}

public String getTouname() {

return touname;

}

public void setTouname(String touname) {

this.touname = touname;

}

public String getUheadurl() {

return uheadurl;

}

public void setUheadurl(String uheadurl) {

this.uheadurl = uheadurl;

}

public String getRcontent() {

return rcontent;

}

public void setRcontent(String rcontent) {

this.rcontent = rcontent;

}

public String getRtime() {

return rtime;

}

public void setRtime(String rtime) {

this.rtime = rtime;

}

@Override

public String toString() {

return "Replay{" +

"rid=" + rid +

", torrid=" + torrid +

", torr=" + torr +

", uid=" + uid +

", touid=" + touid +

", uname='" + uname + '\'' +

", touname='" + touname + '\'' +

", uheadurl='" + uheadurl + '\'' +

", rcontent='" + rcontent + '\'' +

", rtime='" + rtime + '\'' +

'}';

}

}

TopicDao

package com.wg.springdemo.dao;

import com.wg.springdemo.model.Topic;

import org.springframework.data.jpa.repository.JpaRepository;

import org.springframework.stereotype.Repository;

@Repository

public interface TopicDao extends JpaRepository {

}

ReplayDao

package com.wg.springdemo.dao;

import com.wg.springdemo.model.Replay;

import org.springframework.data.jpa.repository.JpaRepository;

import org.springframework.stereotype.Repository;

import java.util.List;

@Repository

public interface ReplayDao extends JpaRepository {

//找到所有对某评论的回复 或者对 某回复 的所有回复

List findByTorridAndTorr(Long torrid,int tr);

}

TopicService

package com.wg.springdemo.service;

import com.wg.springdemo.dao.TopicDao;

import com.wg.springdemo.model.Topic;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.util.List;

@Service

public class TopicService {

@Autowired

TopicDao topicDao;

//存入一条评论

public Topic InsertOneTopic(Topic t){

return topicDao.save(t);

}

//查找所有评论

public List FindAllTopic(){

return topicDao.findAll();

}

}

ReplayService

package com.wg.springdemo.service;

import com.wg.springdemo.dao.ReplayDao;

import com.wg.springdemo.model.Replay;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.util.List;

@Service

public class ReplayService {

@Autowired

ReplayDao replayDao;

//插入一条回复

public Replay InsertOneReplay(Replay r){

return replayDao.save(r);

}

//找到对某个评论的所有回复

public List FindAllByTid(Long tid){

return replayDao.findByTorridAndTorr(tid,1);

}

//找到对某个回复的所有回复

public List FindAllByRid(Long rid){

return replayDao.findByTorridAndTorr(rid,0);

}

}

TopicNode

package com.wg.springdemo.util;

import com.wg.springdemo.model.Replay;

import com.wg.springdemo.model.Topic;

import java.util.ArrayList;

import java.util.List;

public class TopicNode {

private Topic topic;

private List replays = new ArrayList<>();

public TopicNode() {

}

public Topic getTopic() {

return topic;

}

public void setTopic(Topic topic) {

this.topic = topic;

}

public List getReplays() {

return replays;

}

public void setReplays(List replays) {

this.replays = replays;

}

}

ReplayNode

package com.wg.springdemo.util;

import com.wg.springdemo.model.Replay;

import java.util.ArrayList;

import java.util.List;

public class ReplayNode {

private Replay replay;

private List listreplay = new ArrayList<>();

public ReplayNode() {

}

public Replay getReplay() {

return replay;

}

public void setReplay(Replay replay) {

this.replay = replay;

}

public List getListreplay() {

return listreplay;

}

public void setListreplay(List listreplay) {

this.listreplay = listreplay;

}

}

ac8afb7c9c75

添加测试数据

package com.wg.springdemo;

import com.wg.springdemo.model.Replay;

import com.wg.springdemo.model.Topic;

import com.wg.springdemo.service.ReplayService;

import com.wg.springdemo.service.TopicService;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)

@SpringBootTest

public class SpringdemoApplicationTests {

@Autowired

ReplayService replayService;

@Autowired

TopicService topicService;

@Test

public void contextLoads() {

topicService.InsertOneTopic(new Topic( 1L,"小红","1.jpg","这是第一个评论","2018-01-02"));

topicService.InsertOneTopic(new Topic( 2L,"小黄","1.jpg","这是第二个评论","2018-01-02"));

topicService.InsertOneTopic(new Topic( 3L,"小绿","1.jpg","这是第三个评论","2018-01-02"));

topicService.InsertOneTopic(new Topic( 4L,"小黑","1.jpg","这是第四个评论","2018-01-02"));

topicService.InsertOneTopic(new Topic( 1L,"小红","1.jpg","这是第五个评论","2018-01-02"));

replayService.InsertOneReplay(new Replay(1L,1,2L,1L,"小黄","小红","1.jpg","这是第一条回复","2018-01-02"));

replayService.InsertOneReplay(new Replay(1L,1,3L,1L,"小绿","小红","1.jpg","这是第二条回复","2018-01-02"));

replayService.InsertOneReplay(new Replay(1L,0,4L,2L,"小黑","小黄","1.jpg","这是第一.一条回复","2018-01-02"));

replayService.InsertOneReplay(new Replay(3L,0,2L,4L,"小黄","小黑","1.jpg","这是第一.一.一条回复","2018-01-02"));

replayService.InsertOneReplay(new Replay(4L,0,4L,2L,"小黑","小黄","1.jpg","这是第一.一.一.一条回复","2018-01-02"));

replayService.InsertOneReplay(new Replay(4L,0,1L,1L,"小红","小黄","1.jpg","这也是第一.一.一.一条回复","2018-01-02"));

replayService.InsertOneReplay(new Replay(3L,1,2L,3L,"小黄","小绿","1.jpg","这是第三条回复","2018-01-02"));

}

}

HomeController

package com.wg.springdemo.controller;

import com.wg.springdemo.model.Replay;

import com.wg.springdemo.model.Topic;

import com.wg.springdemo.service.ReplayService;

import com.wg.springdemo.service.TopicService;

import com.wg.springdemo.util.ReplayNode;

import com.wg.springdemo.util.TopicNode;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import java.util.ArrayList;

import java.util.List;

@Controller

public class HomeController {

@Autowired

ReplayService replayService;

@Autowired

TopicService topicService;

//插入链表 参数分别代表需要待插入的节点list 和这些节点的父亲是谁

public boolean AddReplayNode(List relists,ReplayNode freplay){

//为空就直接返回

if(relists.size()==0)return false;

//挨个遍历list中的节点信息,然后如果节点还有孩子就继续递归

for(Replay re:relists){

ReplayNode newreplaynode = new ReplayNode();

newreplaynode.setReplay(re);

freplay.getListreplay().add(newreplaynode);

List replayList = new ArrayList<>();

replayList = replayService.FindAllByRid(re.getRid());

//有孩子就继续递归,有没有孩子这里是统一进入递归才判断,也可以来个if else

AddReplayNode(replayList,newreplaynode);

}

return false;

}

//展示出来 参数表示需要展示的节点list

public void ShowReplayNodes(List replayNodes){

if(replayNodes.size()==0)return;

for(ReplayNode temp: replayNodes){

System.out.println(temp.getReplay().toString());

ShowReplayNodes(temp.getListreplay());

}

}

@RequestMapping(value = "/", method = RequestMethod.GET)

public String getHomePostsByPage(Model model) {

List topics = new ArrayList<>();

topics = topicService.FindAllTopic();//得到所有评论

List topicNodes = new ArrayList<>();//装下所有评论的List

for(Topic temp : topics){

TopicNode topicNode = new TopicNode();

topicNode.setTopic(temp);//把每个Topic变成TopicNode

Long tid = temp.getTid();

//找到是这个评论的所有回复

List thisreplays = new ArrayList<>();

thisreplays = replayService.FindAllByTid(tid);

//遍历每个第一层回复

for(Replay re:thisreplays){

ReplayNode replayNode = new ReplayNode();

replayNode.setReplay(re);

topicNode.getReplays().add(replayNode);

//得到回复的回复

List replayList = new ArrayList<>();

replayList = replayService.FindAllByRid(re.getRid());

//递归

AddReplayNode(replayList,replayNode);

}

topicNodes.add(topicNode);

}

//输出

for(TopicNode tnode:topicNodes){

//得到评论

System.out.println(tnode.getTopic().toString());

ShowReplayNodes(tnode.getReplays());

}

model.addAttribute("topics",topicNodes);

return "index";

}

}

index.html

Index

1.jpg

小虎2018-01-02

这是留言内容

digui.html

1.jpg

小灰2018-01-02

回复 小虎 :这是回复内容

index.css

.onetopic{

margin: 10px 0;

}

.userhead{

width: 50px;

border: 1px solid #e8cfcf;

border-radius: 30px;

}

.name{

position: relative;

top: -18px;

}

.tr-time{

position: relative;

top: -18px;

left: 18px;

font-size: 12px;

}

.tr-content{

padding: 0 0 20px 0;

border-bottom: 1px solid #b1a5a5;

margin: 0;

margin-left:52px;

}

.onereplay{

margin: 10px 0 10px 40px;

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值