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

最終效果圖

效果圖
将評論拆分為評論表和回複表,評論挂在各種主題下面,而回複挂在評論下面
我是采用的Jpa建表,是以隻需要把實體對象寫好就行

評論表

回複表
先上項目結構圖

項目結構圖
說一下我的思路
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;
}
}

添加測試資料
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
小虎2018-01-02
這是留言内容
digui.html
小灰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;
}