跟着康师傅学的博客 在写文章评论部分的时候
发现回复某个评论的时候 子评论是独立出来的和父评论 不在一个层级 如下

觉得有点难分辨是具体回复谁
后有想改代码写成同一层级的那种评论、也就只是想想而已
到了后面就快写完门户了就差调整UI了、看到别人有留言页面。。
诶、我也想写一个留言 供网友留言的留言板。
就想了一会、在博客里的评论表之上改了一下
效果呈现:


评论表:

留言表:基于评论表改的

后端实现类:
package net.wzfBoke.blog.services.impl;
import lombok.extern.slf4j.Slf4j;
import net.wzfBoke.blog.dao.MessageDao;
import net.wzfBoke.blog.pojo.Message;
import net.wzfBoke.blog.pojo.SobUser;
import net.wzfBoke.blog.response.ResponseResult;
import net.wzfBoke.blog.services.IMessageService;
import net.wzfBoke.blog.services.IUserService;
import net.wzfBoke.blog.utils.Constants;
import net.wzfBoke.blog.utils.IdWorker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import java.util.Date;
import java.util.List;
@Slf4j
@Service
@Transactional
public class MessageServiceImpl extends BaseService implements IMessageService {
@Autowired
private IdWorker idWorker;
@Autowired
private IUserService iUserService;
@Autowired
private MessageDao messageDao;
@Override
public ResponseResult postMessage(Message message) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
SobUser sobUser = iUserService.checkSobUser();
if (sobUser == null) {
String email = message.getEmail();
if (email == null) {
return ResponseResult.SUCCESS_FAILED("邮箱地址不可以为空");
}
String userName = message.getUserName();
if (userName == null) {
return ResponseResult.SUCCESS_FAILED("名字不可以为空");
}
String content = message.getContent();
if (content == null){
return ResponseResult.SUCCESS_FAILED("评论内容不可以为空");
}
message.setRoles("role_tourists");
log.info("没有登录");
}else{
message.setAvatar(sobUser.getAvatar());
message.setEmail(sobUser.getEmail());
message.setUserName(sobUser.getUserName());
if (sobUser.getRoles().equals(Constants.User.ROLE_ADMIN)){
message.setRoles("role_admin");
log.info("管理员");
}else if (sobUser.getRoles().equals(Constants.User.ROLE_NORMAL)){
message.setRoles("role_normal");
log.info("普通用户");
}
log.info("有登录");
}
message.setPostIp(request.getRemoteAddr());
message.setId(idWorker.nextId() + "");
message.setCreateTime(new Date());
messageDao.save(message);
return ResponseResult.SUCCESS("留言提交成功!");
}
@Override
public ResponseResult getMessageList() {
List<Message> messageList = messageDao.findMessageByFuID();
int listSize = messageList.size();
Sort sort = new Sort(Sort.Direction.DESC, "createTime");
for (int i = 0; i < listSize; i++) {
String FId = messageList.get(i).getId();
List<Message> messageChildList = messageDao.findAll(new Specification<Message>() {
@Override
public Predicate toPredicate(Root<Message> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
return cb.equal(root.get("fuId").as(String.class),FId);
}
});
messageList.get(i).setList(messageChildList);
}
return ResponseResult.SUCCESS("获取文章评论列表成功").setData(messageList);
}
@Override
public ResponseResult AdminGetList(int page, int size) {
page = checkPage(page);
size = checkSize(size);
Sort sort = new Sort(Sort.Direction.DESC, "createTime");
Pageable pageable = PageRequest.of(page - 1, size, sort);
Page<Message> all = messageDao.findAll(pageable);
return ResponseResult.SUCCESS("获取留言列表成功").setData(all);
}
@Override
public ResponseResult deleteMessageByIid(String messageId) {
Message message = messageDao.findOneById(messageId);
if (message == null) {
return ResponseResult.SUCCESS_FAILED("该留言不存在");
}
int result = messageDao.deleteAllById(messageId);
if (result == 0) {
return ResponseResult.SUCCESS_FAILED("删除留言失败");
}
return ResponseResult.SUCCESS("删除留言成功");
}
}
前端呈现:
<template>
<div class="message-box">
<!-- <div class="message-part-1 clear-fix">-->
<!-- <img src="https://huangwenyang.cn/static/image/message-1.jpg" class="message-img float-left">-->
<!-- <div class="message-title-box">-->
<!-- <a class="message-title-box-title">留言板</a><br/>-->
<!-- <!–<img src="https://www.myong.top/static/img/timg.94467a8.gif">–>-->
<!-- <div class="message-title-box-content">-->
<!-- <p>欢迎来到这里的朋友!</p>-->
<!-- <p>让我们进行深入灵魂的交流。</p>-->
<!-- <p> 这里是2020年度留言板,如有意见或建议,或交换友链,请在下方留言~</p>-->
<!-- </div>-->
<!-- <a class="gotoMessage" @click="gotoPart3()">去 留 言</a>-->
<!-- </div>-->
<!-- </div>-->
<div class="message-part-3" id="message-part-3">
<div class="message-post-box">
<div class="message-post-box-1">
<span class="input-text float-left">Name:<el-input class="message-userName-input" v-model="message.userName"
placeholder="取你喜欢的名字"></el-input></span>
<span class="input-text2 float-left">Email:<el-input class="message-userName-input" v-model="message.email"
placeholder="能联系到你的邮箱地址"></el-input></span>
<span class="input-text2 float-left">Http:<el-input class="message-http-input" v-model="message.http"
placeholder="博客 如 : www.laowuya.top (选填)"></el-input></span>
<el-input v-model="message.content"
v-loading="loading"
class="ContentInput"
type="textarea"
placeholder="说点你的想法吧"
resize="none"
:rows="3"></el-input>
<div class="message-post-box-1-1 clear-fix">
<el-button class="message-button-post float-right" type="primary" plain @click="postMessage()"> 留 言
</el-button>
<span class="input-text-sex float-left">性别 : </span>
<div class="message-post-box-1-1-1 float-left">
<el-radio-group v-model="message.sex">
<el-radio-button label="男孩纸"></el-radio-button>
<el-radio-button label="女孩纸"></el-radio-button>
</el-radio-group>
</div>
</div>
</div>
</div>
</div>
<div class="message-part-2" id="message-part-2">
<div class="message-list-box">
<div class="message-list-item" v-for="(item,index) in this.messageResultList" :key="index">
<div class="item-one clear-fix">
<img :src=item.avatar class="item-avatar float-left">
<span class="item-name float-left">{{item.userName}}</span>
<el-tag class="tag-role1 float-left" v-if="item.roles === 'role_admin'">博主</el-tag>
<el-tag class="tag-role2 float-left" type="success" v-if="item.roles === 'role_normal'">小站成员</el-tag>
<el-tag class="tag-role3 float-left" type="info" v-if="item.roles === 'role_tourists'">游客</el-tag>
<span class="item-createTime float-left">{{formatDate(item.createTime)}}</span>
<span class="item-reply-button float-right" @click="FuReplyButton(item)">回复</span>
</div>
<span class="item-content">{{item.content}}</span>
<div class="child-message-box">
<div class="child-message-item" v-for="(item,index) in item.list" :key="index">
<div class="child-message-item-1 clear-fix">
<span class="child-item-name float-left">{{item.userName}}</span>
<el-tag class="child-tag-role float-left" v-if="item.roles === 'role_admin'">博主</el-tag>
<el-tag class="child-tag-role float-left" type="success" v-if="item.roles === 'role_normal'">小站成员
</el-tag>
<el-tag class="child-tag-role float-left" type="info" v-if="item.roles === 'role_tourists'">游客</el-tag>
<span class="child-item-reply float-left"> 回复 </span>
<span class="child-item-FuUserName float-left">{{item.fuUserName}}</span>
<span class="child-item-createTime float-left">{{formatDate(item.createTime)}}</span>
<span class="child-item-reply-button float-left " @click="ChildReplyButton(item)" >回复</span>
</div>
<div class="child-message-item-2">
<span class="child-item-content">{{item.content}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="dialog">
<el-dialog
:visible.sync="centerDialogVisible"
width="82%"
center>
<div class="message-post-box">
<div class="message-post-box-1">
<span class="input-text float-left">Name:<el-input class="message-userName-input" v-model="ChildMessage.userName"
placeholder="取你喜欢的名字"></el-input></span>
<span class="input-text2 float-left">Email:<el-input class="message-userName-input" v-model="ChildMessage.email"
placeholder="能联系到你的邮箱地址"></el-input></span>
<span class="input-text2 float-left">Http:<el-input class="message-http-input" v-model="ChildMessage.http"
placeholder="博客 如 : www.laowuya.top (选填)"></el-input></span>
<el-input v-model="ChildMessage.content"
v-loading="loading"
class="ContentInput"
type="textarea"
placeholder="说点你的想法吧"
resize="none"
:rows="3"></el-input>
<div class="message-post-box-1-1 clear-fix">
<el-button class="message-button-post float-right" type="primary" plain @click="postChildMessage()"> 留 言
</el-button>
<span class="input-text-sex float-left">性别 : </span>
<div class="message-post-box-1-1-1 float-left">
<el-radio-group v-model="ChildMessage.sex">
<el-radio-button label="男孩纸"></el-radio-button>
<el-radio-button label="女孩纸"></el-radio-button>
</el-radio-group>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
</div>
</template>
<script>
import * as api from "../../api/api";
import * as dateUtils from "../../utils/date";
export default {
async asyncData() {
let messageResultList = await api.GetMessageList();
return {
messageResultList: messageResultList.data
}
},
data() {
return {
loading: false,
centerDialogVisible: false,
message: {
userName: '',
content: '',
sex: '',
email: '',
http: '',
avatar: ''
},
ChildMessage: {
userName: '',
content: '',
sex: '',
fuUserName: '',
fuId: '',
email: '',
http: '',
avatar: ''
}
}
},
methods: {
postChildMessage(){
if (this.ChildMessage.userName === '') {
this.showWarning("你的名字不可为空噢!");
return;
}
if (this.ChildMessage.email === '') {
this.showWarning("邮箱地址不可为空噢!");
return;
}
if (this.ChildMessage.content === '') {
this.showWarning("留言内容不可为空噢!");
return;
}
if (this.ChildMessage.sex === '') {
this.showWarning("请选一下你的性别");
return;
}
if (this.ChildMessage.sex === '男孩纸') {
this.ChildMessage.avatar = 'portal/image/1602489149994_765240488734228480.jpeg'
} else if (this.ChildMessage.sex === '女孩纸') {
this.ChildMessage.avatar = 'portal/image/1602489149994_765240488734228480.jpeg'
}
this.loading = true;
api.PostMessage(this.ChildMessage).then(result => {
this.loading = false;
if (result.code === api.success_code) {
this.showSuccess("留言好了噢~小站已经帮你通知博主啦!");
this.messageList();
this.resetDataChildMessage();
this.gotoPart2();
}
})
if (this.centerDialogVisible === true){
this.centerDialogVisible = false;
}
this.getUserInfo();
},
ChildReplyButton(item){
this.centerDialogVisible = true;
this.ChildMessage.fuUserName = item.userName;
this.ChildMessage.fuId = item.fuId;
},
FuReplyButton(item) {
this.centerDialogVisible = true;
this.ChildMessage.fuUserName = item.userName;
this.ChildMessage.fuId = item.id;
},
getUserInfo() {
api.GetUserInfoByToken().then(result => {
if (result.code === api.success_code) {
api.GetUserInfo(result.data.id).then(result => {
if (result.code === api.success_code) {
this.message.userName = result.data.userName;
this.message.email = result.data.email;
this.ChildMessage.userName = result.data.userName;
this.ChildMessage.email = result.data.email;
}
})
}
})
},
messageList() {
api.GetMessageList().then(result => {
if (result.code === api.success_code) {
this.messageResultList = result.data;
}
})
},
resetDataChildMessage(){
this.ChildMessage.userName = '';
this.ChildMessage.content = '';
this.ChildMessage.sex = '';
this.ChildMessage.email = '';
this.ChildMessage.http = '';
this.ChildMessage.avatar = '';
this.ChildMessage.fuId = '';
this.ChildMessage.fuUserName = '';
},
resetData() {
this.message.userName = '';
this.message.content = '';
this.message.sex = '';
this.message.email = '';
this.message.http = '';
this.message.avatar = '';
},
postMessage() {
if (this.message.userName === '') {
this.showWarning("你的名字不可为空噢!");
return;
}
if (this.message.email === '') {
this.showWarning("邮箱地址不可为空噢!");
return;
}
if (this.message.content === '') {
this.showWarning("留言内容不可为空噢!");
return;
}
if (this.message.sex === '') {
this.showWarning("请选一下你的性别");
return;
}
if (this.message.sex === '男孩纸') {
this.message.avatar = 'portal/image/1602489158126_765240522838114304.jpeg'
} else if (this.message.sex === '女孩纸') {
this.message.avatar = 'portal/image/1602489149994_765240488734228480.jpeg'
}
this.loading = true;
api.PostMessage(this.message).then(result => {
this.loading = false;
if (result.code === api.success_code) {
this.showSuccess("小站已为你通告博主啦!");
this.messageList();
this.resetData();
this.gotoPart2();
}
})
this.getUserInfo();
},
showWarning(msg) {
this.$message({
message: msg,
type: 'warning',
center: true,
})
},
showSuccess(msg) {
this.$message({
message: msg,
type: 'success',
center: true,
})
},
formatDate(dateStr) {
let date = new Date(dateStr);
return dateUtils.formatDate(date, 'yyyy-MM-dd hh:mm:ss')
},
gotoPart3() {
let topheader = document.getElementById('message-part-3');
if (topheader) {
topheader.scrollIntoView({
block: 'start',
behavior: 'smooth'
})
}
},
gotoPart2() {
let topheader = document.getElementById('message-part-2');
if (topheader) {
topheader.scrollIntoView({
block: 'start',
behavior: 'smooth'
})
}
}
}
,
mounted() {
this.getUserInfo();
}
}
</script>
<style>
.item-one .tag-role1 .el-tag{
color: #fff;
}
.dialog .el-dialog {
border-radius: 32px;
}
.child-message-item-1 {
margin-bottom: 10px;
}
.child-item-reply-button:hover {
color: #bb53e4;
}
.child-item-reply-button {
font-size: 18px;
font-weight: 300;
margin-bottom: 15px;
cursor: pointer;
margin-left: 35px;
margin-top: 4px;
color: #526ff8;
}
.item-reply-button:hover {
color: #bb53e4;
}
.item-reply-button {
font-size: 18px;
font-weight: 300;
margin-bottom: 15px;
cursor: pointer;
margin-left: 35px;
margin-top: 30px;
color: #526ff8;
}
.child-message-item {
margin-bottom: 30px;
padding: 10px;
}
.child-item-content {
font-weight: 300;
font-size: 22px;
background: #ededed;
border-radius: 8px;
padding: 5px 10px;
}
.child-item-createTime {
font-weight: 300;
font-size: 18px;
margin-top: 5px;
margin-left: 35px;
}
.child-item-reply {
font-size: 18px;
font-weight: 300;
margin: 5px 0px 15px 40px;
color: #09c506;
}
.child-item-FuUserName {
font-size: 24px;
font-weight: 300;
margin-bottom: 15px;
margin-right: 15px;
margin-left: 40px;
}
.child-item-name {
font-size: 24px;
font-weight: 300;
margin-bottom: 15px;
margin-right: 15px;
}
.child-message-box {
margin-left: 150px;
margin-top: 35px;
background: #f8f8f8;
border-radius: 8px;
}
.tag-role1{
margin-left: 25px;
margin-top: 20px;
}
.tag-role2{
margin-left: 25px;
margin-top: 20px;
}
.tag-role3{
margin-left: 25px;
margin-top: 20px;
}
.message-button-post {
width: 150px;
margin-left: 25px;
margin-right: 25px;
}
.message-post-box-1-1 {
margin-top: 25px;
}
.ContentInput {
width: 1155px;
margin-top: 25px;
font-size: 18px;
}
.message-post-box {
padding: 25px;
}
.input-text2 {
font-weight: 300;
font-size: 18px;
margin-left: 25px;
}
.message-http-input {
width: 420px;
margin-left: 15px;
}
.input-text-sex {
font-weight: 300;
font-size: 18px;
margin-right: 25px;
margin-top: 8px;
}
.input-text {
font-weight: 300;
font-size: 18px;
}
.message-userName-input {
width: 250px;
margin-left: 15px;
}
.item-content {
background: #f5f5f5;
border-radius: 8px;
padding: 5px 10px;
font-weight: 300;
font-size: 22px;
margin-top: 5px;
margin-left: 110px;
}
.item-name {
font-size: 24px;
font-weight: 300;
margin-bottom: 15px;
margin-left: 35px;
margin-top: 20px;
}
.item-createTime {
font-weight: 300;
font-size: 18px;
margin-top: 28px;
margin-left: 35px;
}
.message-list-item {
/*padding: 25px 25px 25px 25px;*/
padding: 20px 35px;
}
.item-avatar {
width: 75px;
height: 75px;
object-fit: cover;
border-radius: 50%;
}
.gotoMessage {
cursor: pointer;
color: #5958d6;
}
.gotoMessage:hover {
color: #54c8ff;
}
.message-title-box-content {
margin-top: 235px;
margin-bottom: 15px;
}
.message-title-box-title {
font-weight: 400;
font-size: 24px;
color: #42b7ff;
}
.message-title-box p {
font-size: 18px;
font-weight: 300;
margin-top: 5px;
}
.message-title-box {
margin: 15px 15px 15px 0px;
}
.message-img {
width: 600px;
border-radius: 16px;
margin: 15px;
}
.message-box {
margin-top: 15px;
}
.message-part-2 {
border-radius: 16px;
background: #fff;
margin-bottom: 30px;
padding-top: 45px;
padding-bottom: 60px;
}
.message-part-1 {
border-radius: 16px;
background: #fff;
margin-bottom: 10px;
}
.message-part-3 {
border-radius: 16px;
background: #fff;
margin-bottom: 15px;
}
</style>