1.前言
这是本人课程设计中其中一个功能点,就是用户在使用unapp中的首页模块中可以对发表的文章进行评论。
2.实现效果
3.实现思路
(1)首先,在前端页码编写好一个循环评论组件,把它看成一个List列表,因为需要在大List里面去渲染小List列表。
(2)其次,就是需要在服务端编写一个接口,查询数据库中所有的相关评论,让后端把它构造成里面大List带着小List的数据,我用是的springboot编写的后端逻辑代码。
4.实现代码
4.1Uniapp实现代码
<template>
<view>
<scroll-view scroll-y="true" >
<uni-card :title="items.title">
<view class="flex-space u-m-5">
<view class="flex">
<u-avatar :src="items.userPic"></u-avatar>
<view class="" style="">
<view class="">{{items.username}}</view>
<view class="">
<u-tag text="原创" type="error"></u-tag>
</view>
</view>
</view>
<view class="" style="align-content: center;text-align: right;">
<view class="">{{items.state}}</view>
<text class="ts">{{items.createTime}}</text>
</view>
</view>
<image :src="items.coverImg" style="width: 100%;" mode="aspectFill"></image>
<u-read-more ref="uReadMore" :toggle="true">
<rich-text :nodes="items.content"></rich-text>
</u-read-more>
</uni-card>
<view class="u-flex-col" style=" width: 100%; left: 0;">
<view class="u-m-l-40 u-m-b-20 u-m-r-20" style="height: 30px;">
<u-section title="评论列表" sub-title="评论" @click="openDialog"></u-section>
</view>
<u-empty :show="list.length==0"
mode="list"
icon="http://cdn.uviewui.com/uview/empty/list.png">
</u-empty>
<uni-list>
<uni-list-item v-for="(item,index) in list">
<view class="" slot="header">
<view class="">
<view class="flex-row" @click="toReply(item)">
<u-avatar :src="item.userPic"></u-avatar>
<!-- <image :src="item.userPic" mode="aspectFill" style="width: 100upx;height: 100upx;border-radius: 50dp;"></image> -->
<view class="">
<view class="" style="color: #999;font-size: 30upx;">{{item.username}}</view>
<view class="" >{{item.content}}</view>
<view class="" style="color: #999;font-size: 18upx;">{{item.createTime}}</view>
</view>
</view>
</view>
<uni-list-item v-for="(item1,index1) in item.commentList.slice(0,(item.status==1?item.status:item.commentList.length))">
<view class="" slot="header" @click="toReply(item1)">
<view class="flex-center">
<u-avatar :src="item1.userPic"></u-avatar>
<!-- <image :src="item1.userPic" mode="aspectFill" style="width: 100upx;height: 100upx;border-radius: 50dp;"></image> -->
<view class="">
<view class="" style="color: #999;font-size: 30upx;">{{item1.username}}
<u-icon name="play-right-fill"></u-icon>
{{item1.replyName}}</view>
<view class="" >{{item1.content}}</view>
<view class="" style="color: #999;font-size: 18upx;">{{item1.createTime}}</view>
</view>
</view>
</view>
</uni-list-item>
<view class="" v-if="item.commentList.length-1>0" @click="toMore(index)">
<text>{{item.status==0?"收起":`展开${item.commentList.length-1}条回复`}}</text>
</view>
</view>
</uni-list-item>
<u-divider class="u-m-t-40" v-if="list.length!=0" style="bottom: 35px;width: 100%;">已显示全部评论</u-divider>
</uni-list>
</view>
<view class="u-m-l-20" style="position: fixed; width: 100%;height: 50px;bottom: -14px;
background-color: #FFFFFF;">
<view class="flex-row u-m-r-50">
<view class="" style="width: 70%;" @click="openDialog">
<uni-easyinput disabled prefixIcon="compose" placeholder="写评论..." />
</view>
<view class="u-m-l-40 flex-space" style="width: 80px;">
<uni-icons type="hand-up" size="30" :color="thumbState?'#2979ff':'#d5d5d5'" >
<uni-badge :text="items.thumbNum" @click="addThumb"/>
</uni-icons>
<uni-icons type="star" size="30" :color="collectState?'#2979ff':'#d5d5d5'" >
<uni-badge :text="items.collectNum" @click="addCollect"></uni-badge>
</uni-icons>
</view>
</view>
</view>
</scroll-view>
<uni-popup ref="addDialog" type="bottom" maskClick>
<uni-popup-dialog mode="input" :duration="2000" style="width: 100%;"
:before-close="true" @close="addClose" @confirm="addConfirm" :title="`添加回复${replyname}`">
</uni-popup-dialog>
</uni-popup>
<uni-popup ref="Dialog" type="dialog" maskClick>
<uni-popup-dialog mode="input" :duration="2000"
:before-close="true" @close="close" @confirm="confirm" title="添加评论对话框">
</uni-popup-dialog>
</uni-popup>
</view>
</template>
<script>
export default {
data() {
return {
items:{},
form:{
articleId:'',
content:'',
replyUser:'',
commentId:'',
treeId:''
},
list:[],
replyname:'',
collectState:false,
thumbState:false,
itemId:0
}
},
onLoad(e) {
this.itemId = e.id
this.getDetail()
},
methods: {
getDetail(){
this.request('/article/detail?id='+this.itemId).then(res=>{
console.log(res)
this.items = res.data
this.form.articleId = this.items.id
console.log(this.items)
this.getList()
this.$nextTick(() => {
this.$refs.uReadMore.init();
})
this.request(`/collect/myLike?articleId=${this.itemId}`).then(res=>{
if(res.code==200)
this.collectState = res.data
console.log(res)
})
this.request(`/thumb/myLike?articleId=${this.itemId}`).then(res=>{
if(res.code==200)
this.thumbState = res.data
console.log(res)
})
})
},
getList(){
this.request(`/comment?articleId=${this.form.articleId}`).then(res=>{
this.list = res.data
console.log(res.data)
})
},
openDialog(){
this.$refs.Dialog.open()
},
toReply(item){
console.log(item)
this.replyname = item.username
this.form.replyUser = item.usersId
this.form.commentId = item.id
if(item.treeId)this.form.treeId = item.treeId //有根给根
else this.form.treeId = item.id //无根给自己id
console.log(this.form)
this.$refs.addDialog.open()
},
addConfirm(e){
this.form.content = e
this.toAddRequest(1)
},
addClose(){
this.$refs.addDialog.close()
this.clear()
},
confirm(e){
this.form.content = e
this.toAddRequest(0)
},
close(){
this.$refs.Dialog.close()
this.clear()
},
toAddRequest(idx){
this.request('/comment','post',{...this.form}).then(res=>{
uni.showToast({
title:res.message
})
this.getList()
if(idx==0)this.close()
else this.addClose()
this.clear()
})
},
clear(){
this.replyname = ''
this.form.content = ''
this.form.replyUser = ''
this.form.commentId = ''
this.form.treeId = ''
},
toMore(index){
console.log('你点击了'+index)
if(this.list[index].status){
this.list[index].status = 0
}
else {
this.list[index].status = 1
}
},
addCollect(){
console.log('你点击了收藏')
if(!this.collectState)this.request(`/collect/add?categoryId=${this.items.categoryId}&articleId=${this.itemId}`).then(res=>{
console.log(res)
if(res.code==200){
uni.showToast({
title:'收藏成功'
})
this.getDetail()
}
})
else {
this.request(`/collect/delete?articleId=${this.itemId}`,'delete').then(res=>{
if(res.code==200){
uni.showToast({
title:'取消收藏成功'
})
this.getDetail()
}
})
}
},
addThumb(){
console.log('你点击了点赞')
if(!this.thumbState)this.request(`/thumb/add?categoryId=${this.items.categoryId}&articleId=${this.itemId}`).then(res=>{
if(res.code==200){
uni.showToast({
title:'点赞成功'
})
this.getDetail()
}
})
else {
this.request(`/thumb/delete?articleId=${this.itemId}`,'delete').then(res=>{
if(res.code==200){
uni.showToast({
title:'取消点赞成功'
})
this.getDetail()
}
})
}
}
}
}
</script>
<style>
</style>
4.2Java实现代码
(1)entity层
@Data
@Schema(description = "评论实体")
public class Comment {
@NotEmpty
@Schema(description = "评论id") //这个是swagger里面的定义,建议删除
private Integer id;//主键ID
@Schema(description = "评论内容")
private String content;//文章内容
@Schema(description = "文章id")
private Integer articleId;//文章id
@Schema(description = "创建用户id")
private Integer usersId;//创建用户id
@Schema(description = "回复人id")
private Integer replyUser;//回复人id
@Schema(description = "回复评论id")
private Integer commentId;//回复评论id
@Schema(description = "父级评论id")
private Integer treeId;//父级评论id
@Schema(description = "创建人头像")
private String userPic;//创建人头像
@Schema(description = "创建人姓名")
private String username;//创建人姓名
@Schema(description = "回复人姓名")
private String replyName;//回复人姓名
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" )
@Schema(description = "创建时间")
private LocalDateTime createTime;//创建时间
}
@Schema(description = "评论列表实体")
@Data
public class CommentBean {
@NotEmpty
@Schema(description = "评论id")
private Integer id;//主键ID
@Schema(description = "评论内容")
private String content;//文章内容
@Schema(description = "文章id")
private Integer articleId;//文章id
@Schema(description = "创建用户id")
private Integer usersId;//创建用户id
@Schema(description = "回复人id")
private Integer replyUser;//回复人id
@Schema(description = "回复评论id")
private Integer commentId;//回复评论id
@Schema(description = "父级评论id")
private Integer treeId;//父级评论id
@Schema(description = "创建人头像")
private String userPic;//创建人头像
@Schema(description = "创建人姓名")
private String username;//创建人姓名
@Schema(description = "回复人姓名")
private String replyName;//回复人姓名
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" )
@Schema(description = "创建时间")
private LocalDateTime createTime;//创建时间
@Schema(description = "评论列表折叠状态")
private Integer status; //1,表示显示1个,0表示显示全部
private List<Comment> commentList;
}
@Schema表示swagger生成在线文档里面的定义,如果没有用到建议删掉
(2)controller层
@Operation(summary = "获取评论列表接口",operationId = "获取评论列表接口")
@GetMapping
public Result<List<CommentBean>> list(@RequestParam(required = false) Integer articleId){
List<CommentBean> commentList = commentService.list(articleId);
return Result.success(commentList);
}
@Operation(summary = "获取评论列表接口",operationId = "获取评论列表接口")表示swagger生成在线文档里面的定义,如果没有用到建议删掉
(3)service接口
public interface CommentService {
//获取评论列表
List<CommentBean> list(Integer id);
}
(4)service实现类
@Service
public class CommentServiceImpl implements CommentService {
@Autowired
private CommentMapper commentMapper;
@Override
public List<CommentBean> list(Integer articleId) {
List<CommentBean> commentBeanList = new ArrayList<>(); //创建返回的值
List<Comment> commentList = commentMapper.list(articleId); //找到母体的数组
for(Comment comment:commentList){
CommentBean commentBean = new CommentBean();
commentBean.setCommentList(commentMapper.treeList(articleId,comment.getId()));
commentBean.setId(comment.getId());
commentBean.setContent(comment.getContent());
commentBean.setArticleId(comment.getArticleId());
commentBean.setUsersId(comment.getUsersId());
commentBean.setTreeId(comment.getTreeId());
commentBean.setUserPic(comment.getUserPic());
commentBean.setUsername(comment.getUsername());
commentBean.setCreateTime(comment.getCreateTime());
commentBean.setStatus(1);
commentBeanList.add(commentBean);
}
return commentBeanList;
}
}
(5)mapper层
@Mapper
public interface CommentMapper {
//获取根评论
@Select("select comment.id,comment.content,comment.article_id,comment.users_id,comment.create_time,comment.tree_id,users.user_pic,users.username " +
"from users,comment where users.id = comment.users_id and article_id = #{articleId} and comment.tree_id is null")
List<Comment> list(Integer articleId);
//获取父id得到子评论
@Select("select comment.id,comment.content,comment.article_id,comment.users_id,comment.reply_user,comment.comment_id,comment.create_time,comment.tree_id,users.user_pic,users.username," +
"(select users.username from users where users.id=comment.reply_user) as replyname from users,comment where users.id = comment.users_id and article_id = #{articleId} and comment.tree_id = #{Id} ")
List<Comment> treeList(Integer articleId,Integer Id);
}
做完上述步骤即可完成此功能,切记上面有些sql语句采用了多表级联查询的功能,大家根据自己的需求来修改自己的代码,最后祝大家都能解决所有bug。