評論回復(fù)功能設(shè)計

以評論為主的顯示模式,類似于下面的CSDN的評論顯示模式

最終效果圖

效果圖

將評論拆分為評論表和回復(fù)表,評論掛在各種主題下面,而回復(fù)掛在評論下面
我是采用的Jpa建表,所以只需要把實體對象寫好就行

評論表

回復(fù)表

先上項目結(jié)構(gòu)圖

項目結(jié)構(gòu)圖

說一下我的思路

1.建立倆張表,回復(fù)表回復(fù)的id分為回復(fù)評論還是回復(fù),用一個int標(biāo)志判斷。
2.想像樹狀那樣顯示出來,這里就采取鏈表的形式存儲,一條評論下可能有多人回復(fù),所以存儲下一個對象我們使用List來存儲,開始的List初始化為private List<ReplayNode> replays = new ArrayList<>();不然replays.add()的時候會報空指針.
3.因為評論和回復(fù)是分開建表的,所以我們還需要單獨設(shè)置一個評論節(jié)點,分別對應(yīng)上面項目結(jié)構(gòu)圖的TopicNodeReplayNode
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;//評論內(nèi)容
    @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或者回復(fù)id  就是有可能是回復(fù)評論,也可能是給回復(fù)的回復(fù)
    private int torr;//用來判斷上面的哪種情況:1表示回復(fù)評論 0表示回復(fù)回復(fù)
    private Long uid;//用戶ID
    private Long touid;//目標(biāo)用戶id 給誰回復(fù)
    @Column(length = 50)
    private String uname;//用戶名
    @Column(length = 50)
    private String touname;//目標(biāo)用戶名
    @Column(length = 255)
    private String uheadurl;//用戶頭像
    @Column(length = 800)
    private String rcontent;//回復(fù)內(nèi)容
    @Column(length = 20)
    private String rtime;//回復(fù)時間
    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<Topic,Long> {
}

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<Replay,Long> {
    //找到所有對某評論的回復(fù) 或者對 某回復(fù) 的所有回復(fù)
    List<Replay> 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<Topic> 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;
    //插入一條回復(fù)
    public Replay InsertOneReplay(Replay r){
        return replayDao.save(r);
    }
    //找到對某個評論的所有回復(fù)
    public List<Replay> FindAllByTid(Long tid){
        return replayDao.findByTorridAndTorr(tid,1);
    }
    //找到對某個回復(fù)的所有回復(fù)
    public List<Replay> 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<ReplayNode> replays = new ArrayList<>();
    public TopicNode() {
    }
    public Topic getTopic() {
        return topic;
    }
    public void setTopic(Topic topic) {
        this.topic = topic;
    }
    public List<ReplayNode> getReplays() {
        return replays;
    }
    public void setReplays(List<ReplayNode> 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<ReplayNode> listreplay = new ArrayList<>();
    public ReplayNode() {
    }
    public Replay getReplay() {
        return replay;
    }
    public void setReplay(Replay replay) {
        this.replay = replay;
    }
    public List<ReplayNode> getListreplay() {
        return listreplay;
    }
    public void setListreplay(List<ReplayNode> listreplay) {
        this.listreplay = listreplay;
    }
}
添加測試數(shù)據(jù)
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","這是第一條回復(fù)","2018-01-02"));
        replayService.InsertOneReplay(new Replay(1L,1,3L,1L,"小綠","小紅","1.jpg","這是第二條回復(fù)","2018-01-02"));
        replayService.InsertOneReplay(new Replay(1L,0,4L,2L,"小黑","小黃","1.jpg","這是第一.一條回復(fù)","2018-01-02"));
        replayService.InsertOneReplay(new Replay(3L,0,2L,4L,"小黃","小黑","1.jpg","這是第一.一.一條回復(fù)","2018-01-02"));
        replayService.InsertOneReplay(new Replay(4L,0,4L,2L,"小黑","小黃","1.jpg","這是第一.一.一.一條回復(fù)","2018-01-02"));
        replayService.InsertOneReplay(new Replay(4L,0,1L,1L,"小紅","小黃","1.jpg","這也是第一.一.一.一條回復(fù)","2018-01-02"));
        replayService.InsertOneReplay(new Replay(3L,1,2L,3L,"小黃","小綠","1.jpg","這是第三條回復(fù)","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;
    //插入鏈表 參數(shù)分別代表需要待插入的節(jié)點list 和這些節(jié)點的父親是誰
    public boolean AddReplayNode(List<Replay> relists,ReplayNode freplay){
        //為空就直接返回
        if(relists.size()==0)return false;
        //挨個遍歷list中的節(jié)點信息,然后如果節(jié)點還有孩子就繼續(xù)遞歸
        for(Replay re:relists){
            ReplayNode newreplaynode = new ReplayNode();
            newreplaynode.setReplay(re);
            freplay.getListreplay().add(newreplaynode);
            List<Replay> replayList = new ArrayList<>();
            replayList = replayService.FindAllByRid(re.getRid());
            //有孩子就繼續(xù)遞歸,有沒有孩子這里是統(tǒng)一進(jìn)入遞歸才判斷,也可以來個if else
            AddReplayNode(replayList,newreplaynode);
        }
        return false;
    }
    //展示出來 參數(shù)表示需要展示的節(jié)點list
    public void ShowReplayNodes(List<ReplayNode> 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<Topic> topics = new ArrayList<>();
        topics = topicService.FindAllTopic();//得到所有評論
        List<TopicNode> topicNodes = new ArrayList<>();//裝下所有評論的List
        for(Topic temp : topics){
            TopicNode topicNode = new TopicNode();
            topicNode.setTopic(temp);//把每個Topic變成TopicNode
            Long tid = temp.getTid();
            //找到是這個評論的所有回復(fù)
            List<Replay> thisreplays = new ArrayList<>();
            thisreplays = replayService.FindAllByTid(tid);
            //遍歷每個第一層回復(fù)
            for(Replay re:thisreplays){
                ReplayNode replayNode = new ReplayNode();
                replayNode.setReplay(re);
                topicNode.getReplays().add(replayNode);
                //得到回復(fù)的回復(fù)
                List<Replay> 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

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
    <link rel="stylesheet" href="/css/index.css">
</head>
<body>
<div class="onetopic" th:each="tp : ${topics}">
<img src="/imgs/1.jpg" class="userhead" th:src="|/imgs/${tp.getTopic().getUheadurl()}|">
    <span class="name" th:text="${tp.getTopic().getUname()}">小虎</span><span class="tr-time" th:text="${tp.getTopic().getTtime()}">2018-01-02</span>
    <p class="tr-content" th:text="${tp.getTopic().getTcontent()}">這是留言內(nèi)容</p>
    <div th:include="digui::digui(${tp.getReplays()},1)">
        <!--<div class="onereplay" th:each="tr : ${tp.getReplays()}">-->
            <!--<img src="/imgs/1.jpg" class="userhead">-->
            <!--<span class="name">小灰</span><span class="tr-time">2018-01-02</span>-->
            <!--<p class="tr-content">回復(fù) 小虎 :這是回復(fù)內(nèi)容</p>-->
            <!--<div class="onereplay">-->
                <!--<img src="/imgs/1.jpg" class="userhead">-->
                <!--<span class="name">小灰</span><span class="tr-time">2018-01-02</span>-->
                <!--<p class="tr-content">回復(fù) 小虎 :這是回復(fù)內(nèi)容</p>-->
            <!--</div>-->
        <!--</div>-->
    </div>
    <!--<div class="onereplay">-->
        <!--<img src="/imgs/1.jpg" class="userhead">-->
        <!--<span class="name">小灰</span><span class="tr-time">2018-01-02</span>-->
        <!--<p class="tr-content">回復(fù) 小虎 :這是回復(fù)內(nèi)容</p>-->
    <!--</div>-->
</div>
</body>
</html>

digui.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div th:fragment="digui(lists,level)">
    <div class="onereplay" th:each="tr : ${lists}">
        <img src="/imgs/1.jpg" class="userhead" th:src="|/imgs/${tr.getReplay().getUheadurl()}|">
        <span class="name" th:text="${tr.getReplay().getUname()}">小灰</span><span class="tr-time" th:text="${tr.getReplay().getRtime()}">2018-01-02</span>
        <p class="tr-content" th:text="'回復(fù) '+${tr.getReplay().getTouname()}+' :'+${tr.getReplay().getRcontent()}">回復(fù) 小虎 :這是回復(fù)內(nèi)容</p>
        <div th:unless="${tr.getListreplay().size()==0}" th:include="this::digui(${tr.getListreplay()},${level+1})"></div>
    </div>
</div>
</body>
</html>

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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容