1. 业务开发
下面是核心的前端调用代码,具体页面效果根据自身模版的风格进行调整。
[!tip] dataType是字典的评论类型,前台在对接业务时需注意,请传递字典label值。
1.1. 前端开发
后台需要在自定义字典中增加字典值;找到评论类型,再添加新的字典,如(名称label:文章,数据值value:content)数据值作为数据保存,名称作为展示;
1.1.1. 游客查看评论
代码片段参考
下面提供的是展示方法是将获取所有评论数据,然后根据top_id(顶级评论id)comment_id(父评论id)和自身id的关系来处理形成评论层级关系
//vue代码片段
...
<div v-for="comment in commentDataList">
{{comment.peopleName?comment.peopleName:'游客'}}
{{comment.commentTime}}
{{comment.commentContent}}
<div v-for="childComment in comment.childCommentDataLists">
{{comment.peopleName?comment.peopleName:'游客'}}
{{comment.commentTime}}
{{comment.commentContent}}
</div>
</div>
...
...
ms.http.get('/comment/list.do', that.form).then(function (res) {
if (res.result) {
that.total = res.data.total; //总数
that.commentList = res.data.rows; //评论记录
// 第一级评论
var topComment = that.commentList.filter(c => !c.topId || c.topId==0)
topComment.forEach(function (data) {
// 如果当前这条评论存在图片
...
if (data.commentPicture){
var commentPicture = JSON.parse(data.commentPicture)
// 存储当前评论的图片
data['pictureList'] = []
commentPicture.forEach(function (picture){
data['pictureList'].push(picture.path)
})
}
...
//初始化子评论列表
data.childCommentDataLists = [];
// 当前遍历到评论的所有子评论
var childComments = allComment.filter(item => item.topId && item.topId==data.id)
childComments.forEach(function (childData) {
// 如果父评论为顶级评论则直接赋值
if (childData.commentId == data.id){
childData.parentName = data.peopleName;
} else {
// 找到当前遍历子评论的父评论
var parentComment = childComments.find(function (item) {
return item.id = childData.commentId;
})
if (parentComment){
childData.parentName = parentComment.peopleName;
}
}
// 将处理完的数据push到顶级评论的子集中
data.childCommentDataLists.push(childData);
});
// 存放顶级评论
that.commentDataList.push(data)
}
}
})
...
[!tip] 上面的案例比较适合处理层级关系不深的评论列表,三层及以上则需要去维护一大串的代码逻辑,如果要处理多层,推荐"懒加载"的方式,第一次只查询顶级评论,当用户点击某个评论的下拉列表再次去请求该评论下的子评论,以此类推。
1.1.2. 发布评论
代码片段
//vue代码片段
...
form: {
commentId:'',//父评论编号
commentContent: '',//评论内容
dataTitle: '${field.title}',//文章标题
dataId: '${field.id}',//文章id
dataType: "文章", //业务类型
commentPicture: [],// 评论图片JSON
commentFileJson: [],// 附件JSON
commentPoints: 0// 评论打分
},
...
...
ms.http.post('/people/comment/save.do', that.form).then(function (res) {
if (res.result) {
this.$message({
title: '成功',
message: '评论成功',
type: 'success'
});
} else {
this.$message({
title: '失败',
message: '评论失败',
type: 'error'
});
}
})
...
[!tip] 父子评论需注意正确传递commentId参数; 游客模式和会员有一些差异,参考http://doc.mingsoft.net/plugs/ping-lun-cha-jian/jie-shao.html#%E6%8E%A5%E5%8F%A3
1.1.3. 参数
图片、附件等参数需要json格式,其他参数正常处理即可 参考如下代码片段 代码片段:
···
that.form.commentFileJson.push({
url: file.url?file.url:file.path,
name: file.name,
path: response.data,
uid: file.uid,
status: 'success'
});
that.form.commentFileJson.push({
url: file.url?file.url:file.path,
name: file.name,
path: response.data,
uid: file.uid,
status: 'success'
});
···
// 将封装好的图片数据转为JSON
if (that.form.commentPicture && that.form.commentPicture != '[]'){
that.form.commentPicture = JSON.stringify(that.form.commentPicture)
}
// 将封装好的附件数据转为JSON
if (that.form.commentFileJson && that.form.commentFileJson != '[]'){
that.form.commentFileJson = JSON.stringify(that.form.commentFileJson)
}
···
1.2. 后端开发
在业务开发时注意查看biz.ICommentBiz中的方法注释,有些参数校验或者字段默认赋值等操作已经在业务层统一处理。
下面以业务层saveComment为例 biz.impl.commentBizImpl中saveComment方法代码片段
··· 基本数据校验
// 是否开启评论
if (!ConfigUtil.getBoolean("评论配置","enableComment")){
throw new BusinessException(BundleUtil.getBaseString("fail",
BundleUtil.getString(net.mingsoft.comment.constant.Const.RESOURCES,"comment")));
}
···
// 评论类型
comment.setDataType(dataType);
// 涉及评论是否审核,开启取到配置为true,需要取反,false为未审核
comment.setCommentAudit(!ConfigUtil.getBoolean("评论配置", "enableAudit"));
// 评论ip
HashMap<String, String> map = new HashMap<>();
map.put("ipv4",BasicUtil.getIp());
map.put("addr",IpUtils.getRealAddressByIp(BasicUtil.getIp()));
comment.setCommentIp(JSONUtil.toJsonStr(map));
//评论时间
comment.setCommentTime(new Date());
comment.setUpdateDate(new Date());
comment.setCreateDate(new Date());
// 初始化评论点赞数
comment.setCommentLike(0);
// 附件及图片
if (StringUtils.isBlank(comment.getCommentPicture()) || !comment.getCommentPicture().matches("^\\[.{1,}]$")) {
comment.setCommentPicture("");
}
if (StringUtils.isBlank(comment.getCommentFileJson()) || !comment.getCommentFileJson().matches("^\\[.{1,}]$")) {
comment.setCommentFileJson("");
}
// 设置顶级评论id 判断当前回复的评论是否是顶级评论,不是则将top_id设置为当前回复评论的top_id
setTopId(comment);
return commentDao.insert(comment);
1.2.1. 保存评论
保存时需注意,一些参数需要按指定格式传参,如peopleInfo字段需要json结构。
处理完参数调用统一的业务层方法即可。
下面是action.people.commentAction save方法的代码片段:
// 判断登陆设置peopleId
PeopleEntity people = this.getPeopleBySession();
PeopleUserEntity peopleUserEntity = (PeopleUserEntity) peopleUserBiz.getEntity(people.getIntId());
// 设置会员相关信息
if (peopleUserEntity != null){
Map commentPeopleInfo = new HashMap();
// 这里可以根据业务需求填充用户数据
commentPeopleInfo.put("puIcon",peopleUserEntity.getPuIcon());
String peopleInfo = JSONUtil.toJsonStr(commentPeopleInfo);
comment.setPeopleInfo(peopleInfo);
comment.setPeopleName(peopleUserEntity.getPuNickname());
comment.setPeopleId(peopleUserEntity.getPeopleId());
}
// 业务层再对评论数据做处理 如 ip、时间、评论关系等
commentBiz.saveComment(comment);
1.2.2. 删除评论
后台管理可以批量删除评论,默认代码中前台只允许用户删除自己的评论,注意如果重写action的代码要对用户的id进行校验
代码参考:
PeopleEntity people = this.getPeopleBySession();
if (StringUtils.isBlank(id)){
return ResultData.build().error(getResString("err.not.exist",this.getResString("comment")));
}
CommentEntity comment = commentBiz.getById(id);
if (comment==null || people.getIntegerId().equals(comment.getPeopleId())){
return ResultData.build().error(getResString("err.not.exist",this.getResString("comment")));
}
级联删除: 从产品角度来讲,可以允许父评论删除后保留子评论,增加逻辑删除业务,界面则不显示评论内容; 如果需要级联删除业务,建议在数据库设置外键关联,在数据库层面级联删除评论
附件、图片等处理:推荐使用我们的清理插件,可以清理一些删除评论后遗留的无用文件http://doc.mingsoft.net/plugs/qing-li-cha-jian/jie-shao.html
在默认代码中,评论log表中统计数量会随评论表中记录数增加,但是不会随着删除而减少,这是我们觉得比较合理的一个设计;当然如果并不需要这么做的话,请在删除时参考如下代码处理记录数。
//查询评论记录是否有该评论
CommentsLogEntity data = commentsLogBiz.getOne(new QueryWrapper<CommentsLogEntity>().eq("data_id",dataId).eq("data_type",dataType));
//评论数-1
data.setCommentsCount(data.getCommentsCount()-1);
commentsLogBiz.updateById(data);
1.2.3. 修改评论
不支持修改评论
1.2.4. 查询评论
建议调用web端查询接口,people目录下的action接口需要会员登陆
web代码参考:
//只显示审核通过的评论
comment.setCommentAudit(true);
// 确保第一次只查询出父评论
List<CommentEntity> list = commentBiz.query(comment);
return ResultData.build().success().data(new EUListBean(list,(int)BasicUtil.endPage(list).getTotal()));
1.2.5. 业务对接
在开发时,对接其他业务如文章评论、商品评论等
在这些业务删除时,可以考虑aop处理同时删除相关联的评论数据