springboot+vue前后分离实现仿qq空间评论功能
Java项目开发
共 9468字,需浏览 19分钟
· 2021-01-13
案例功能效果图
前端评论列表页面效果图
环境介绍
前端:vue
后端:springboot
jdk:1.8及以上
数据库:mysql
完整源码获取方式
源码获取方式
扫码关注回复【plgn】获取完整源码
如果你在运行这个代码的过程中有遇到问题,请加小编微信xxf960513,我拉你进对应微信学习群!!帮助你快速掌握这个功能代码!
核心代码介绍
pom.xml
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.1version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.1.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-accessartifactId>
<version>1.1.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.1.3version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.25version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-simpleartifactId>
<version>1.7.25version>
<scope>compilescope>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.swaggergroupId>
<artifactId>swagger-modelsartifactId>
<version>1.5.21version>
dependency>
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>swagger-bootstrap-uiartifactId>
<version>1.9.3version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.62version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
application.properties
server.port=8002
spring.datasource.url=jdbc:mysql://xxx.xxx.xxx.xxx:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=xxxxxx
spring.datasource.password=xxxxxx
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
CommonMapper.java
package com.example.demo.mapper;
import com.example.demo.vo.ReplyVO;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface CommonMapper {
@Select("select * from reply_info where comId = #{comId} order by updateTime")
List<ReplyVO> queryReplyList(@Param("comId")int comId);
@Delete("delete from reply_info where id = #{id}")
int deleteReply(int id);
}
CommonController.java
package com.example.demo.controller;
import com.example.demo.service.CommonService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
public class CommonController {
private CommonService commonService;
public Map getReplyList( int comId) {
List list = commonService.queryReplyList(comId);
Map resMap = new HashMap();
resMap.put("STATUS", "0000");
resMap.put("DATA", list);
return resMap;
}
public Map deleteReply( int id) {
commonService.deleteReply(id);
Map map = new HashMap();
map.put("STATUS", "0000");
return map;
}
}
Home.vue
<template>
<div class="comment-wrap">
<div v-if="myComment.length" class="comment-list">
<h4>热门评论h4>
<div>
<div v-for="(item, index) in myComment" :key="item.id" class="comment-item">
<div class="top-wrap">
<div class="top-left">
<el-image :src="checkImg(item.userId)" alt="" lazy class="top-left-avatar"> el-image>
<div class="top-left-con">
<div class="top-left-con-title">
<h3>{{ item.userName }}h3>
div>
<div class="top-left-con-time">{{ item.updateTime | moment('YYYY-MM-DD HH:mm') }}div>
div>
div>
<div class="top-right" v-if="loginId === item.userId">
<div class="top-right-item" @click="handleDelete(index)">
<img src="@/assets/delete.png" alt="" />
div>
div>
div>
<div class="label">
{{ item.msg }}
div>
<div v-if="item.newSub && item.newSub.length" class="reply-wrap">
<div v-for="(reply, i) in item.newSub" :key="reply.id" class="reply-item">
<div class="top-wrap">
<div class="top-left">
<el-image :src="checkImg(reply.userId)" alt="" lazy class="top-left-avatar"> el-image>
<div class="top-left-con">
<div class="top-left-con-title">
<h3>{{ reply.userName }}h3>
div>
<div class="top-left-con-time">{{ reply.updateTime | moment('YYYY-MM-DD HH:mm') }}div>
div>
div>
<div v-if="loginId === reply.userId" class="top-right">
<div class="top-right-item" @click="handleDelete(index, i + 1)">
<img src="@/assets/delete.png" alt="" />
div>
div>
div>
<div class="label">
{{ reply.msg }}
div>
div>
<div v-if="item.subList.length > 1">
<div v-if="!item.isMoreReply" class="showMoreReply" @click="showMoreReply(true, index)">查看更多回复div>
<div v-else class="showMoreReply" @click="showMoreReply(false, index)">收起div>
div>
div>
div>
div>
div>
<el-pagination
background
:page-size="pageSize"
:page-count="pageNo"
layout="prev, pager, next"
:total="allComment.length"
@current-change="handleChangePage"
@pre-click="handlePrePage"
@next-click="handleNextPage"
>
el-pagination>
div>
template>
<script>
import { mapGetters } from 'vuex';
import axios from 'axios';
export default {
components: {},
props: {},
data() {
return {
textarea: '',
isMoreComment: false,
replyCon: '',
myComment: [],
allComment: [],
loading: false,
pageNo: 1,
pageSize: 5
};
},
computed: {
...mapGetters(['loginId'])
},
watch: {},
created() {},
mounted() {
this.getData();
},
methods: {
checkImg(id) {
if (id === 1) {
return require('@/assets/face.png');
} else {
return require('@/assets/comment.png');
}
},
showMoreReply(type, index) {
this.myComment[index].isMoreReply = type;
if (type) {
this.myComment[index].newSub = this.myComment[index].subList;
} else {
this.myComment[index].newSub = this.myComment[index].subList.slice(0, 1);
}
},
handleDelete(index, i) {
console.log(index, i, this.myComment);
let id = 0;
if (i) {
id = this.myComment[index].newSub[i - 1].id;
this.myComment[index].newSub.splice(i - 1, 1);
} else {
id = this.myComment[index].id;
this.myComment.splice(index, 1);
}
axios({
method: 'post',
url: `http://xxx.xxx.xxx.xxx:8002/common/removeReply/${id}`
}).then(res => {
console.log(res, 'res');
});
},
handleChangePage(val) {
console.log(val, 'val');
this.pageNo = val;
let begin = (val - 1) * this.pageSize;
this.myComment = this.allComment.slice(begin, begin + this.pageSize);
},
handlePrePage() {
if (this.pageNo > 1) {
this.pageNo--;
}
let begin = (this.pageNo - 1) * this.pageSize;
this.myComment = this.allComment.slice(begin, begin + this.pageSize);
},
handleNextPage() {
this.pageNo++;
let begin = (this.pageNo - 1) * this.pageSize;
this.myComment = this.allComment.slice(begin, this.pageSize);
},
getData() {
axios({
method: 'get',
url: `http://xxx.xxx.xxx.xxx:8002/common/replyList/1`
}).then(res => {
console.log(res, 'res');
let data = res.data.DATA;
const list = data.map(item => {
return {
...item,
newSub: item.subList.slice(0, 1),
showReply: false,
isMoreReply: false,
isMoreComment: false
};
});
console.log(list, 'list');
this.allComment = [].concat(list);
this.myComment = list.slice(this.pageNo - 1, this.pageSize);
});
}
}
};
reply_info.sql
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `reply_info`;
CREATE TABLE `reply_info` (
`id` int NOT NULL AUTO_INCREMENT,
`userId` int DEFAULT NULL,
`comId` int DEFAULT NULL,
`msg` varchar(255) DEFAULT NULL,
`updatetime` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`userName` varchar(255) DEFAULT NULL,
`replyId` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
BEGIN;
INSERT INTO `reply_info` VALUES (1, 2, 1, '6', '2020-12-20 22:28:18', '评论人1', NULL);
INSERT INTO `reply_info` VALUES (3, 2, 1, '666', '2020-12-30 22:28:19', '评论人1', 2);
INSERT INTO `reply_info` VALUES (5, 3, 1, '8', '2020-12-20 22:28:29', '评论人2', NULL);
INSERT INTO `reply_info` VALUES (7, 2, 1, '7', '2020-12-20 23:39:19', '评论人1', NULL);
INSERT INTO `reply_info` VALUES (8, 3, 1, '88', '2020-12-30 23:40:12', '评论人2', 7);
INSERT INTO `reply_info` VALUES (11, 3, 1, '8888', '2020-12-31 20:28:21', '评论人2', 10);
INSERT INTO `reply_info` VALUES (12, 1, 1, '88888', '2020-12-31 20:28:35', '发表人', 11);
INSERT INTO `reply_info` VALUES (13, 3, 1, '888888', '2020-12-31 20:28:48', '评论人2', 12);
INSERT INTO `reply_info` VALUES (14, 1, 1, '8888888', '2020-12-31 20:29:06', '发表人', 13);
INSERT INTO `reply_info` VALUES (15, 3, 1, '88888888', '2020-12-31 20:29:22', '评论人2', 14);
INSERT INTO `reply_info` VALUES (17, 4, 1, '4', '2020-12-31 22:08:02', '评论人4', NULL);
INSERT INTO `reply_info` VALUES (19, 5, 1, '5', NULL, '评论人5', NULL);
INSERT INTO `reply_info` VALUES (21, 6, 1, '6', NULL, '评论人6', NULL);
INSERT INTO `reply_info` VALUES (23, 7, 1, '7', NULL, '评论人7', NULL);
INSERT INTO `reply_info` VALUES (24, 1, 1, '77', NULL, '发表人', 23);
INSERT INTO `reply_info` VALUES (25, 8, 1, '8', NULL, '评论人8', NULL);
INSERT INTO `reply_info` VALUES (26, 1, 1, '88', NULL, '发表人', 25);
INSERT INTO `reply_info` VALUES (27, 9, 1, '9', NULL, '评论人9', NULL);
INSERT INTO `reply_info` VALUES (29, 10, 1, '10', NULL, '评论人10', NULL);
INSERT INTO `reply_info` VALUES (31, 11, 1, '11', NULL, '评论人11', NULL);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
推荐案例
温暖提示
请长按识别二维码
想学习更多的java功能案例请关注
Java项目开发
如果你觉得这个案例以及我们的分享思路不错,对你有帮助,请分享给身边更多需要学习的朋友。别忘了《留言+点在看》给作者一个鼓励哦!
评论
15种时间序列预测方法总结(包含多种方法代码实现)
向AI转型的程序员都关注了这个号👇👇👇在这篇文章中,我们将深入探讨时间序列预测的基本概念和方法。我们将首先介绍单元预测和多元预测的概念,然后详细介绍各种深度学习和传统机器学习方法如何应用于时间序列预测,包括循环神经网络(RNN)、一维卷积神经网络(1D-CNN)、Transformer、自回归模型(
机器学习AI算法工程
0
Go 1.22 的新增功能系列之二:reflect.TypeFor
Go 1.22 的第一个候选版本已经发布,这意味着最终版本即将发布,现在是我在博客中介绍我在这个周期中所做工作的时候了。像往常一样,我的贡献很小,但它们是我的,所以我将从幕后的角度来谈谈它们。首先是reflect.TypeFor。这是整个函数:// TypeFor returns the [Type
GoCN
0
SpringBoot 实现图片防盗链功能
程序员的成长之路互联网/程序员/技术/资料共享 关注阅读本文大概需要 4 分钟。来自:blog.csdn.net/weixin_46157208/article/details/138051737前言出于安全考虑,我们需要后端返回的图片只允许在某个网站内展示,不想被爬虫拿到图片地
程序员的成长之路
0
一站式解决方案:基于 Arthas 实现服务发现和权限控制
来源:juejin.cn/post/7281849496983994383👉 欢迎加入小哈的星球 ,你将获得: 专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡 / 赠书福利全栈前后端分离博客项目 2.0 版本完结啦, 演示链接
小哈学Java
0
用 Shader 实现旗帜飘扬动画效果
我觉得对于刚入门 3D 编程的朋友来说,如果能够完成代码创建模型数据->创建材质->编写Shader动画这一系列,想必会有满满的成就感。今天就用 Cocos Creator 的 utils.MeshUtils.createMesh 接口,带大家感受一下这个流程。这个流程不仅可以用于新手学
COCOS
2
Go 1.22 的新增功能系列之一:cmp.Or
截至撰写本文时,Go 1.22 已经发布几个月了。早就该结束我为 1.22 所做的工作的系列了。抱歉耽搁了这么久,我最近忙于生活事务。如果您错过了我关于reflect.TypeFor(https://blog.carlana.net/post/2024/golang-reflect-type-for
GoCN
1
21.3K star!推荐一款可视化自动化测试/爬虫/数据采集神器!功能免费且强大!
【温馨提示】由于公众号更改了推送规则,不再按照时间顺序排列,如果不想错过测试开发技术精心准备的的干货文章,请将测试开发技术设为“星标☆”,看完文章在文尾处点亮“在看”!大家好,我是狂师!在大数据时代,信息的获取与分析变得尤为重要。对于开发者、数据分析师乃至非技术人员来说,能够高效地采集网络数据并进行
测试开发技术
4
知乎高问:程序员有必要知道为什么做某个功能吗?
将Python客栈设为“星标⭐”第一时间收到最新资讯前言知乎上有一个提问:程序员有必要知道为什么做某个功能吗?↓↓↓今天,我们就这个话题一起来做个讨论。不知道程序员的你,在接到产品经理提的一个需求后,是习惯马上动手开始撸代码呢?还是会先暂停一下,认真思考一会如下一些问题,比如这个需求产生的背景是什么
Python客栈
0