1.概述
評論回覆功能是社交網站最基本的功能,本文主要講解評論留言的設計及實現。
需求:
- 用戶評論日記,回覆評論
- 顯示所有評論
2.數據庫設計
日記表:diary
用戶表:user
回覆表:reply
字段設計
private int id ; //回覆id (主鍵id) private Integer diaryId; //日記id (關聯日記表) private String text; //回覆內容 private Integer userId; //用戶id (關聯用戶表) private Integer lastId; //上一條回覆id (用於關聯回覆表,維護好每條評論的關係)
外鍵關係
講解:
通過last_id我們就能找到這條回覆是回覆的哪條評論或日記。
3.java實現思路
- 存儲我們使用鏈表,這樣可以一步一步找到最後一條回覆,應爲一條評論下可能有多人回覆,所以存儲下一個對象我們使用List來存儲(對象數組也行)
- 先查詢last_id爲null的數據,last_id爲null則說明這是日記的第一層評論。
- 查詢list_id不爲null的數據,last_id不爲null則說明這是回覆。
- 通過last_id找到對應的評論,回覆。添加到鏈表中。
- 打印
4.實現
示例數據庫數據
示例顯示(在web中顯示)
dao層使用的jpa.
實體類
1.Reply(評論實體類)
package com.ss.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Data
@Table(name = "reply")
public class Reply {
@Id
@GeneratedValue
private int id ; //回覆id
private Integer diaryId; //日記id
private String text; //回覆內容
private Integer userId; //用戶id
private Integer lastId; //上一條回覆id
}
2.Node(鏈表結構)
package com.ss.entity;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class Node {
public Node(){
}
/**
* 構造函數
* @param reply
*/
public Node(Reply reply){
this.id = reply.getId();
this.diaryId = reply.getDiaryId();
this.lastId = reply.getLastId();
this.text = reply.getText();
this.userId = reply.getUserId();
}
private int id ;
private Integer diaryId;
private String text;
private Integer userId;
private Integer lastId;
//下一條回覆
private List<Node> nextNodes = new ArrayList<Node>();
/**
* 將單個node添加到鏈表中
* @param list
* @param node
* @return
*/
public static boolean addNode(List<Node> list,Node node){
for (Node node1 : list) { //循環添加
if (node1.getId()==node.getLastId()){ //判斷留言的上一段是都是這條留言
node1.getNextNodes().add(node); //是,添加,返回true;
System.out.println("添加了一個");
return true;
}else{ //否則遞歸繼續判斷
if (node1.getNextNodes().size()!=0)
if (Node.addNode(node1.getNextNodes(),node)){
return true;
}
}
}
return false;
}
/**
* 將查出來的lastId不爲null的回覆都添加到第一層Node集合中
* @param firstList
* @param thenList
* @return
*/
public static List addAllNode(List<Node> firstList,List<Reply> thenList){
while (thenList.size()!=0){
int size = thenList.size();
for (int i = 0;i<size;i++){
if (Node.addNode(firstList,new Node(thenList.get(i)))){
thenList.remove(i);
i--;
size--;
}
}
}
return firstList;
}
//打印
public static void show(List<Node> list){
for (Node node : list) {
System.out.println(node.getUserId()+" 用戶回覆了你:"+node.getText());
if (node.getNextNodes().size()!=0){
Node.show(node.getNextNodes());
}
}
}
}
3.Test方法
package com.ss.reply;
import com.ss.dao.ReplyRepository;
import com.ss.entity.Node;
import com.ss.entity.Reply;
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;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ReplyApplicationTests {
@Autowired
private ReplyRepository replyRepository;
@Test
public void contextLoads() {
//查詢id爲6且lastId爲null的評論
List firstList = replyRepository.findAllByDiaryIdAndLastIdNull(6);
//查詢id爲6且LastId不爲null的評論
List thenList = replyRepository.findAllByDiaryIdAndLastIdNotNull(6);
//新建一個Node集合。
ArrayList<Node> nodes = new ArrayList<>();
//將第一層評論都添加都Node集合中
for (Object o : firstList) {
nodes.add(new Node((Reply) o));
}
//將回復添加到對應的位置
List list = Node.addAllNode(nodes, thenList);
System.out.println();
//打印回覆鏈表
Node.show(list);
}
}
輸出結果
應爲沒有用關聯查詢,所以沒能顯示誰回覆的誰,但如果你已經能做到這裏,相信對你來說也不是難事了、
(沒有添加縮進符,所以顯示的一排,但和示例顯示的輸出順序是一樣的)
4.總結
在這個demo中,使用了遞歸插入鏈表,遞歸查詢鏈表。可能單看代碼理解有些困難,但主要的是數據庫設計,理解了數據庫設計,你自己也能寫出代碼來。
在web程序中你可以將最終得到的list<Node>鏈表返回給前端,前端通過自己寫一個js工具類,將list<Node>鏈表拆開顯示。
可能還有一個更簡單的方法,採用多對一的映射關係,讓數據庫通過外鍵關聯關係自動幫我們添加鏈表,但是你拆開鏈表的時候還是要用到遞歸。因爲現在對錶的映射關係不是太懂,所以在這先不說。以後有機會在來分享。