Springboot+vue实现多级评论

目录

​编辑

数据库设计:

实体类:entity

mapper:

 service:

serviceImpl:

 controller:

application.yml:

Vue代码:


数据库设计:

CREATE TABLE `comment` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
  `content` varchar(255) DEFAULT NULL COMMENT '评论内容',
  `username` varchar(255) DEFAULT NULL COMMENT '用户名称',
  `user_id` int DEFAULT NULL COMMENT '用户id',
  `rate` decimal(10,1) DEFAULT NULL COMMENT '评分',
  `foreign_id` int DEFAULT NULL COMMENT '业务模块的id',
  `pid` int DEFAULT NULL COMMENT '父级评论id',
  `target` varchar(255) DEFAULT NULL COMMENT '回复对象',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

实体类:entity

package com.chen.comments.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import javax.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;


/**
 * @author Y·C
 * @version 1.0.0
 * @ClassName Comment.java
 * @Description TODO
 * @createTime 2023年04月21日 21:52:00
 */
@Data
@Table(name = "comment")
public class Comment {


    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    private String content;
    private String username;
    private Integer userId;
    private BigDecimal rate;
    private Integer foreignId;
    private Integer pid;
    private String target;
    @JsonFormat(pattern = "yyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    @TableField(exist = false)
    private List<Comment> children;
}

mapper:

package com.chen.comments.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chen.comments.entity.Comment;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author Y·C
 * @version 1.0.0
 * @ClassName CommentDao.java
 * @Description TODO
 * @createTime 2023年04月21日 22:06:00
 */
@Mapper
public interface CommentMapper extends BaseMapper<Comment> {

}

 service:

package com.chen.comments.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.chen.comments.entity.Comment;

import java.util.List;

/**
 * @author Y·C
 * @version 1.0.0
 * @ClassName CommentService.java
 * @Description TODO
 * @createTime 2023年04月22日 10:20:00
 */
public interface CommentService extends IService<Comment> {

    List<Comment> findAllByForeignId(Integer foreignId);
}

serviceImpl:

package com.chen.comments.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chen.comments.entity.Comment;
import com.chen.comments.mapper.CommentMapper;
import com.chen.comments.service.CommentService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author Y·C
 * @version 1.0.0
 * @ClassName CommentServiceImpl.java
 * @Description TODO
 * @createTime 2023年04月22日 10:21:00
 */
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Resource
    private CommentMapper commentMapper;

    @Override
    public List<Comment> findAllByForeignId(Integer foreignId) {

        QueryWrapper<Comment> wrapper = new QueryWrapper<>();
        wrapper.eq("foreign_id",foreignId);
        List<Comment> comments = commentMapper.selectList(wrapper);

        return comments;
    }
}

 controller:

package com.chen.comments.controller;

import com.chen.comments.entity.Comment;
import com.chen.comments.service.CommentService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Y·C
 * @version 1.0.0
 * @ClassName CommentController.java
 * @Description TODO
 * @createTime 2023年04月21日 22:09:00
 */
@CrossOrigin
@RestController
@RequestMapping("/comment")
public class CommentController {

    @Resource
    private CommentService commentService;


    @PostMapping
    public void save(@RequestBody Comment comment){
        commentService.save(comment);
    }

    @GetMapping
    public Map<String,Object> list(@RequestParam Integer foreignId){

        Map<String,Object> map = new HashMap<>();
        map.put("rate",BigDecimal.ZERO);

        List<Comment> comments = commentService.findAllByForeignId(foreignId);


        //获得所有不为空的评分
        List<Comment> commentList = comments.stream().filter(comment -> comment.getRate() != null).collect(Collectors.toList());
        //将查询出来的评分进行累加
         commentList.stream().map(Comment::getRate).reduce(BigDecimal::add).ifPresent(res -> {
             //算出平均分
             map.put("rate",res.divide(BigDecimal.valueOf(commentList.size()),1,RoundingMode.HALF_UP));
         });

        List<Comment> rootComments = comments.stream().filter(comment -> comment.getPid() == null).collect(Collectors.toList());
        for (Comment rootComment : rootComments) {
            rootComment.setChildren(comments.stream().filter(comment -> rootComment.getId().equals(comment.getPid())).collect(Collectors.toList()));
        }

        map.put("comments",rootComments);

        return map;
    }


}

application.yml:

server:
  port: 9000
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/rate-demo?serverTimezone=GMT%2b8
    username: root
    password: password

Vue代码:

<template>
  <div style="width: 1000px; margin: 0 auto">
    <div style="width: 500px;margin: 10px auto; border: 1px solid #ccc; padding: 20px">
      <div>商品名称:++++</div>
      <div style="margin: 10px 0">商品价格 :¥100</div>
      <div style="margin: 10px 0">商品评分:<el-rate style="display: inline-block" :colors="['#99A9BF','#F7BA2A','#FF9900']"
      v-model="value" disabled allow-half show-text></el-rate></div>
    </div>




    <div style="margin: 20px 0">
      <el-rate v-model="comment.rate" :colors="['#99A9BF','#F7BA2A','#FF9900']"
              :max="5"
              allow-half
              show-text
              :texts="['非常差','失望至极','一般般','非常满意','surprise']"></el-rate>
      <div style="margin: 10px 0">
        <el-input type="textarea" placeholder="请输入评论" v-model="comment.content"></el-input>
        <div style="text-align: right; margin: 10px 0" >
          <el-button type="primary" @click="submit" >提交</el-button>
        </div>
      </div>
    </div>

    <div style="margin: 20px 0">
      <div style="margin: 10px 0; font-size: 24px; padding: 10px 0; border-bottom: 1px solid #ccc; text-align: left">
        评论列表
      </div>
      <div style="margin: 20px 0; text-align: left">
        <div style="padding: 10px 0;border-bottom: 1px solid #ccc;"  v-for="item in comments" :key = "item.id">

          <div style=" display: flex">
            <div style="width: 80px"><el-avatar :size="50" :src="'https://edu-yc.oss-cn-beijing.aliyuncs.com/avatar/b70223e8672e10f69f0ca36e652507ca.png'"></el-avatar></div>
            <div style="flex: 1">
              <div style="color: black ">  <b>{{ item.username }}:</b><span>{{ item.content }}</span></div>

              <div style="width: 200px;margin-top: 15px">
                <i class="el-icon-time"></i><span style="margin-left: 5px">{{ item.createTime}}</span>
              </div>
              <!--多级回复-->
              <div>
                <el-button type="text" @click="reply(item.id,item.username)">回复</el-button>
              </div>

              <!--回复列表-->
              <div v-if="item.children.length" style="margin-left: 100px;background-color:aliceblue;padding: 10px;border-radius: 10px">
                <div v-for="sub in item.children" :key="sub.id">
                  <div style="padding: 5px 0">
                    <b style="cursor: pointer" @click="reply(sub.pid,sub.username)">{{ sub.username }}</b>
                    <span>
                      回复
                    <span style="color: cornflowerblue">@{{ sub.target }}</span>
                    <span style="color: #666; margin-left: 10px">{{ sub.content }}</span>
                    </span>
                    <div style="width: 200px;margin-top: 15px">
                      <i class="el-icon-time"></i><span style="margin-left: 5px">{{ item.createTime}}</span>
                    </div>
                  </div>
                </div>
              </div>

            </div>
          </div>
        </div>
      </div>
    </div>

    <el-dialog title="回复" :visible.sync="dialogFormVisible" width="40%">
      <el-form :model="replyComment">
        <el-form-item label="内容" :label-width="100">
          <el-input v-model="replyComment.content" autocomplete="off" style="width: 80%"></el-input>
        </el-form-item>
        </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveReply">确 定</el-button>
      </div>

    </el-dialog>


  </div>
</template>

<script>


export default {
  name: 'Home',
  data(){
    return{
      value:0,
      comments:[],
      pid: 0,
      comment:{
        rate:0,
        content:''
      },
      replyComment:{

      },
      dialogFormVisible:false
    }
  },
  created() {
    this.load()
  },
  methods:{

    reply(pid,target){
      this.replyComment ={pid: pid, userId:2,username:'李四',foreignId:1,target:target}
      this.dialogFormVisible =true
    },
    load(){
      fetch("http://localhost:9000/comment?foreignId=1").then(res =>{
          if(res.status ===500){
            this.$notify.success("系统错误")
            return {}
          }
           return res.json()
       }).then(res => {
        this.value = res.rate
        this.comments = res.comments
      })
    },
    saveReply(){
      fetch("http://localhost:9000/comment",{
        method:'post',
        headers:{
          'Content-Type':'application/json;charset=utf-8'
        },
        body: JSON.stringify(this.replyComment)
      }).then(res =>{
        if (res.status ===200){
          this.$notify.success("评论成功")
          this.load();
          this.replyComment ={}
          this.dialogFormVisible=false
        }
      })
    },
    submit(){
      this.comment.userId = 1
      this.comment.username = '张三'
      this.comment.foreignId = 1

      fetch("http://localhost:9000/comment",{
        method:'post',
        headers:{
          'Content-Type':'application/json;charset=utf-8'
        },
        body: JSON.stringify(this.comment)
      }).then(res =>{
        if (res.status ===200){
          this.$notify.success("评论成功")
          this.load();
          this.comment ={}
        }
      })
    }
  }
}
</script>

  • 5
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
资源名字:基于Springboot+vue+mysql的4S店车辆管理系统设计与实现(源码+设计文档+部署说明+视频演示).zip 资源内容:项目全套源码+完整文档 源码说明: 全部项目源码都是经过测试校正后百分百成功运行。 基于Spring Boot+Vue+MySQL的4S店车辆管理系统是一个用于管理和销售4S店车辆的信息管理平台,具有以下主要特点: 技术栈:该系统采用了Spring Boot作为后端框架,Vue作为前端框架,MySQL作为数据存储,具备较高的技术稳定性和可扩展性。 车辆信息管理:系统提供车辆信息的录入、存储和管理功能,包括车型、品牌、颜色、配置等信息,方便4S店进行车辆库存管理。 销售管理:系统支持销售流程管理,包括客户信息录入、车辆选择、报价、订单生成等,方便销售人员进行销售活动的跟踪和管理。 库存管理:系统实时记录车辆库存情况,包括车辆数量、型号、状态等信息,帮助4S店进行库存的监控和管理。 售后服务:系统提供售后服务管理功能,包括维修记录、保养计划、客户反馈等,帮助4S店提供优质的售后服务和维护客户关系。 客户管理:系统支持客户信息管理,包括客户基本信息、购车记录、售后服务记录等,帮助4S店建立客户档案和进行客户关系管理。 报表统计:系统提供各类报表和统计分析功能,包括销售统计、库存分析、客户分析等,帮助4S店进行业务数据分析和决策支持。 权限管理:系统实现多级权限管理,分配不同角色的权限,保证数据安全和操作权限的合理控制。 用户界面友好:系统具有简洁明了的用户界面和良好的用户体验,方便用户快速上手和操作。 总之,基于Spring Boot+Vue+MySQL的4S店车辆管理系统具有技术稳定性高、车辆信息管理、销售管理、库存管理、售后服务、客户管理等特点,帮助4S店提高销售效率、优化库存管理、提供优质的售后服务,实现车辆销售和管理的高效化和智能化。
基于SpringBoot+Vue的论坛管理系统是一个集成了前端和后端技术的论坛管理平台,用于管理用户的帖子、评论等信息。该系统的源码、部署说明和系统介绍已经打包成一个zip文件,方便用户使用。 该系统的前端部分采用了Vue框架进行开发,主要实现了用户界面和交互,包括登录、注册、发布帖子、评论、点赞等功能。而后端部分则采用了SpringBoot框架,负责处理用户请求、管理用户数据并提供相应的API接口。 该系统可以方便地处理用户的帖子、评论等信息,支持多级分类和标签,用户可以根据自己的需求进行筛选和搜索,也可以根据不同的类型进行查看和发布帖子。同时,该系统还支持评论、点赞等互动方式,让用户可以更加深入地交流和讨论。 此外,该系统还支持对用户权限的管理,可以对不同用户进行分组和授权,确保信息的安全性。 对于管理员而言,该系统可以方便地管理用户的帖子和评论信息,进行管理和审核。而对于用户而言,该系统可以方便地交流和分享经验,获取到最新的信息和知识。 总之,该基于SpringBoot+Vue的论坛管理系统是一个功能齐全、易用、实用性很高的论坛管理平台,能够方便地管理用户的帖子和评论信息,提高了管理效率和信息准确性。同时,对于开发者而言也是一个学习VueSpringBoot技术的不错案例,值得一试。
实现多级评论需要在后端和前端两个方面进行处理。 在后端,你需要定义一个评论的数据结构,可以使用递归方式来处理多级评论。每个评论对象应该包含评论的内容、评论的时间、评论者的信息以及子评论列表。子评论列表也是一个评论对象的集合,可以使用 List 或者 Set 来实现。 在前端,你需要使用递归组件来展示多级评论。可以定义一个 Comment 组件来展示一个评论对象,如果这个评论对象包含子评论,那么在 Comment 组件中递归调用 Comment 组件来展示子评论。 以下是一个简单的示例代码: 后端 Java 代码: ```java public class Comment { private String content; private LocalDateTime time; private User user; private List<Comment> children; // getters and setters } ``` 前端 Vue 代码: ```vue <template> <div class="comment"> <div class="content">{{ comment.content }}</div> <div class="time">{{ comment.time }}</div> <div class="user">{{ comment.user.name }}</div> <div class="children"> <comment v-for="child in comment.children" :comment="child" :key="child.id"></comment> </div> </div> </template> <script> export default { name: "Comment", props: { comment: { type: Object, required: true } }, components: { Comment: () => import("./Comment.vue") } }; </script> ``` 在这个示例中,我们使用了递归组件 Comment 来展示多级评论。如果当前评论对象包含子评论,那么在 Comment 组件中递归调用 Comment 组件来展示子评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Y·C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值