SpringBoot+Vue+Mybatis(注解形式)实现商品评论

如果不理解组件传值的话,可以去看我的另一个文章:
Vue组件传值(父组件与子组件)-CSDN博客

先展示实现的效果:

实现步骤如下:

  1. 建数据表

DROP TABLE IF EXISTS `comment`;
CREATE TABLE `comment` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '评论ID',
  `content` text NOT NULL COMMENT '评论内容',
  `user_id` bigint(20) NOT NULL COMMENT '评论作者ID',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `is_delete` tinyint(4) DEFAULT NULL COMMENT '是否删除(0:未删除;1:已删除)',
  `product_id` bigint(20) DEFAULT NULL COMMENT '商品ID',
  `parent_id` bigint(20) DEFAULT NULL COMMENT '父评论ID',
  `root_parent_id` bigint(20) DEFAULT NULL COMMENT '根评论ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8 COMMENT='评论信息表';

-- ----------------------------
-- Records of comment
-- ----------------------------
INSERT INTO `comment` VALUES ('1', '评论1', '1', '2022-10-05 14:14:32', '0', '1', null, null);
INSERT INTO `comment` VALUES ('3', '回复1-2', '2', '2022-10-07 14:16:25', '0', '1', '1', '1');
INSERT INTO `comment` VALUES ('6', '回复1-2-1', '3', '2022-10-13 14:18:51', '0', '1', '3', '1');
INSERT INTO `comment` VALUES ('7', '评论2', '2', '2022-10-05 14:19:40', '0', '1', null, null);
INSERT INTO `comment` VALUES ('8', '回复2-1', '1', '2022-10-14 14:20:07', '0', '1', '7', '7');
INSERT INTO `comment` VALUES ('9', '评论3', '3', '2022-10-05 14:20:54', '0', '1', null, null);
INSERT INTO `comment` VALUES ('24', '评论回复测试n3', '1', '2022-10-27 11:23:54', '0', '1', '9', '9');
INSERT INTO `comment` VALUES ('34', '我是根评论', '1', '2024-03-19 12:14:34', '0', '1', null, null);
INSERT INTO `comment` VALUES ('35', '我现在回复的是【顾无言002】,你好', '1', '2024-03-19 12:15:17', '0', '1', '3', '1');
INSERT INTO `comment` VALUES ('38', '我现在回复的是【张三】的评论【评论3】', '1', '2024-03-19 13:40:43', '0', '1', '9', null);
INSERT INTO `comment` VALUES ('39', '我很喜欢这个Xiaomi Book Pro 16 2022,价格实惠,耐用,性价比嘎嘎高', '1', '2024-03-19 13:41:45', '0', '49', null, null);

2.在你的实体类中创建Comment.java(我的在:com.example.springboot.entity.Comment.java)

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * 评论信息
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Comment implements Serializable {

    private Long id;               // 评论ID
    private String content;        // 评论内容
    private Long userId;           // 评论作者ID
    //    private String userName;       // 评论作者姓名
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;         // 创建时间
    private Integer isDelete;        // 是否删除(0:未删除;1:已删除)

    private Long productId;         // 商品ID
    private Long parentId;          // 父评论ID(被回复的评论)
    private Long rootParentId;      // 根评论ID(最顶级的评论)

    private User user;
    private List<Comment> child;    // 本评论下的子评论
}

  1. controller层
package com.example.springboot.controller;

import com.example.springboot.common.Result;
import com.example.springboot.entity.Comment;
import com.example.springboot.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/comment")
public class CommentController {


    @Autowired
    private CommentService commentService;

    /**
     * 获取评论列表
     *
     * @return
     */
    @GetMapping("/list")
    public Result getCommentList(@RequestParam("productId") Long productId) {
        List<Comment> list = commentService.getCommentList(productId);
        Long total = commentService.getCommentListTotal(productId);
        Map<String, Object> map = new HashMap<>();
        map.put("commentList", list);
        map.put("total", total);
        return Result.success(map);
    }

    /**
     * 添加评论
     *
     * @param comment
     * @return
     */
    @PostMapping("/add")
    public Result addComment(@RequestBody Comment comment) {
        if (commentService.save(comment))
            return Result.success("评论成功");
        return Result.error("评论失败");
    }

    /**
     * 删除评论
     *
     * @param comm
     * @return
     */
    @PostMapping("/delete")
    public Result deleteComment(@RequestBody Comment comm) {
        if (commentService.removeComment(comm))
            return Result.success("删除评论成功");
        return Result.error("删除评论失败");
    }
}
  1. service层
package com.example.springboot.service;


import com.example.springboot.entity.Comment;

import java.util.List;

public interface CommentService {

    /**
     * 获取评论列表
     *
     * @param productId
     * @return
     */
    List<Comment> getCommentList(Long productId);

    /**
     * 获取评论列表总数
     *
     * @param productId
     * @return
     */
    Long getCommentListTotal(Long productId);

    /**
     * 添加评论
     *
     * @param comment
     * @return
     */
    boolean save(Comment comment);

    /**
     * 删除评论
     *
     * @param comment
     * @return
     */
    boolean removeComment(Comment comment);
}
  1. serviceImpl层
package com.example.springboot.service.impl;

import com.example.springboot.entity.Comment;
import com.example.springboot.entity.User;
import com.example.springboot.mapper.CommentMapper;
import com.example.springboot.mapper.UserMapper;
import com.example.springboot.service.CommentService;
import com.example.springboot.utils.CommentUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;


@Service
public class CommentServiceImpl implements CommentService {

    @Autowired(required = false)
    private CommentMapper commentMapper;
    @Autowired(required = false)
    private UserMapper userMapper;

    /**
     * 获取评论列表
     *
     * @param productId
     * @return
     */
    @Override
    public List<Comment> getCommentList(Long productId) {
        List<Comment> list = commentMapper.getCommentList(productId);
        return CommentUtils.processComments(list);
    }

    /**
     * 获取评论列表总数
     *
     * @param productId
     * @return
     */
    @Override
    public Long getCommentListTotal(Long productId) {
        return commentMapper.getCommentListTotal(productId);
    }

    /**
     * 添加评论
     *
     * @param comment
     * @return
     */
    @Override
    public boolean save(Comment comment) {
        User user = userMapper.selectById(comment.getUserId().intValue());
//        comment.setUserName(user.getUsername());
        comment.setCreateTime(new Date());
        comment.setIsDelete(0);
        return commentMapper.save(comment) > 0;
    }

    /**
     * 删除评论
     *
     * @param comment
     * @return
     */
    @Override
    public boolean removeComment(Comment comment) {
        Queue<Comment> queue = new LinkedList<>();
        queue.offer(comment);
        while (!queue.isEmpty()) {
            Comment cur = queue.poll();
            int resultNum = commentMapper.removeById(cur.getId());
            if (resultNum <= 0) return false;
            if (cur.getChild() != null) {
                List<Comment> child = cur.getChild();
                for (Comment tmp : child)
                    queue.offer(tmp);
            }
        }
        return true;
    }
}
  1. mapper层
package com.example.springboot.mapper;

import com.example.springboot.entity.Comment;
import com.example.springboot.entity.User;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.type.JdbcType;

import java.util.List;

@Mapper
public interface CommentMapper {
    /**
     * 根据商品ID获取评论列表
     *
     * @param productId
     * @return
     */
    @Results(
            id = "CommentMapSimple",
            value = {
                    @Result(column = "id", property = "id", jdbcType = JdbcType.INTEGER, id = true),
                    @Result(column = "content", property = "content", jdbcType = JdbcType.VARCHAR),
                    @Result(column = "user_id", property = "userId", jdbcType = JdbcType.INTEGER),
                    @Result(column = "create_time", property = "createTime", jdbcType = JdbcType.TIMESTAMP),
                    @Result(column = "is_delete", property = "isDelete", jdbcType = JdbcType.TINYINT),
                    @Result(column = "product_id", property = "productId", jdbcType = JdbcType.INTEGER),
                    @Result(column = "parent_id", property = "parentId", jdbcType = JdbcType.INTEGER),
                    @Result(column = "root_parent_id", property = "rootParentId", jdbcType = JdbcType.INTEGER),
                    @Result(property = "user", column = "user_id",
                            javaType = User.class,
                            one = @One(select = "com.example.springboot.mapper.UserMapper.selectSimpleById")),
            }
    )
    @Select("SELECT * FROM comment WHERE product_id = #{productId and is_delete = 0} ORDER BY create_time DESC")
    List<Comment> getCommentList(Long productId);

    /**
     * 获取评论列表总数
     *
     * @param productId
     * @return
     */
    @Select("SELECT COUNT(*) FROM comment WHERE product_id = #{productId}")
    Long getCommentListTotal(Long productId);

    /**
     * 添加评论
     *
     * @param comment
     * @return
     */
    @Insert("INSERT INTO comment (content, user_id, create_time, is_delete, product_id, parent_id, root_parent_id) " +
            "VALUES (#{content},#{userId}, #{createTime}, #{isDelete}, #{productId}, #{parentId}, #{rootParentId})")
    int save(Comment comment);

    /**
     * 根据评论ID删除评论
     *
     * @param id
     * @return
     */
    @Delete("DELETE FROM comment WHERE id = #{id}")
    int removeById(Long id);
}

7.创建一个CommentUtils.java(用来格式化评论列表的)

声明:来源:Vue+SpringBoot实现评论功能_springboot vue 评论区-CSDN博客

package com.example.springboot.utils;

import com.example.springboot.entity.Comment;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CommentUtils {

    /**
     * 构建评论树
     *
     * @param list
     * @return
     */
    public static List<Comment> processComments(List<Comment> list) {
        Map<Long, Comment> map = new HashMap<>();   // (id, Comment)
        List<Comment> result = new ArrayList<>();
        // 将所有根评论加入 map
        for (Comment comment : list) {
            if (comment.getParentId() == null)
                result.add(comment);
            map.put(comment.getId(), comment);
        }
        // 子评论加入到父评论的 child 中
        for (Comment comment : list) {
            Long id = comment.getParentId();
            if (id != null) {   // 当前评论为子评论
                Comment p = map.get(id);
                if (p.getChild() == null)    // child 为空,则创建
                    p.setChild(new ArrayList<>());
                p.getChild().add(comment);
            }
        }
        return result;
    }
}

上面的都复制粘贴,自己把包的位置弄好就行。

下面的一定要读懂,并且适配到自己的项目中

下面的是前端的展示:

1.展示案例:

可以去百度一个json试图查看

[
    {
        "id": 34,
        "content": "我是根评论",
        "userId": 1,
        "createTime": "2024-03-19 04:14:34",
        "isDelete": 0,
        "productId": 1,
        "parentId": null,
        "rootParentId": null,
        "user": {
            "id": 1,
            "username": "gwy001",
            "password": "c8837b23ff8aaa8a2dde915473ce0991",
            "name": "昂对阿松大",
            "sex": "男",
            "phone": "15555555555",
            "email": "1022222@qq.com",
            "address": "山西省太原市尖草坪区88号",
            "avatar": "http://localhost:9090/file/download/img.png",
            "createTime": "2024-01-17 02:57:56",
            "loginTime": "2024-01-23 02:57:26",
            "createTimeStr": null,
            "loginTimeStr": null,
            "role": "用户",
            "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwiZXhwIjoxNzEwNjY5ODQ4fQ.FlLosYXsB_zfFzP_NIGLOBI7O0W_A6LSBQcFVEHFTBU",
            "status": 1,
            "cart": null,
            "orders": null,
            "reviews": null
        },
        "child": null
    },
    {
        "id": 9,
        "content": "评论3",
        "userId": 3,
        "createTime": "2022-10-05 06:20:54",
        "isDelete": 0,
        "productId": 1,
        "parentId": null,
        "rootParentId": null,
        "user": {
            "id": 3,
            "username": "user1",
            "password": "4297f44b13955235245b2497399d7a93",
            "name": "张三",
            "sex": "男",
            "phone": "13800138001",
            "email": "user1@example.com",
            "address": "北京市朝阳区",
            "avatar": "http://localhost:9090/file/download/微信图片_202401141653313.jpg",
            "createTime": "2024-01-02 02:58:16",
            "loginTime": null,
            "createTimeStr": null,
            "loginTimeStr": null,
            "role": "用户",
            "token": "",
            "status": 1,
            "cart": null,
            "orders": null,
            "reviews": null
        },
        "child": [
            {
                "id": 38,
                "content": "我现在回复的是【张三】的评论【评论3】",
                "userId": 1,
                "createTime": "2024-03-19 05:40:43",
                "isDelete": 0,
                "productId": 1,
                "parentId": 9,
                "rootParentId": null,
                "user": {
                    "id": 1,
                    "username": "gwy001",
                    "password": "c8837b23ff8aaa8a2dde915473ce0991",
                    "name": "的撒旦",
                    "sex": "男",
                    "phone": "44877778855",
                    "email": "445555@qq.com",
                    "address": "啊实打实大苏打啊阿斯顿",
                    "avatar": "http://localhost:9090/file/download/img.png",
                    "createTime": "2024-01-17 02:57:56",
                    "loginTime": "2024-01-23 02:57:26",
                    "createTimeStr": null,
                    "loginTimeStr": null,
                    "role": "用户",
                    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwiZXhwIjoxNzEwNjY5ODQ4fQ.FlLosYXsB_zfFzP_NIGLOBI7O0W_A6LSBQcFVEHFTBU",
                    "status": 1,
                    "cart": null,
                    "orders": null,
                    "reviews": null
                },
                "child": null
            },
            {
                "id": 24,
                "content": "评论回复测试n3",
                "userId": 1,
                "createTime": "2022-10-27 03:23:54",
                "isDelete": 0,
                "productId": 1,
                "parentId": 9,
                "rootParentId": 9,
                "user": {
                    "id": 1,
                    "username": "gwy001",
                    "password": "c8837b23ff8aaa8a2dde915473ce0991",
                    "name": "阿松大",
                    "sex": "男",
                    "phone": "15555555555",
                    "email": "1231231231@qq.com",
                    "address": "啊实打实大苏打飒飒的",
                    "avatar": "http://localhost:9090/file/download/img.png",
                    "createTime": "2024-01-17 02:57:56",
                    "loginTime": "2024-01-23 02:57:26",
                    "createTimeStr": null,
                    "loginTimeStr": null,
                    "role": "用户",
                    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwiZXhwIjoxNzEwNjY5ODQ4fQ.FlLosYXsB_zfFzP_NIGLOBI7O0W_A6LSBQcFVEHFTBU",
                    "status": 1,
                    "cart": null,
                    "orders": null,
                    "reviews": null
                },
                "child": null
            }
        ]
    },
    {
        "id": 7,
        "content": "评论2",
        "userId": 2,
        "createTime": "2022-10-05 06:19:40",
        "isDelete": 0,
        "productId": 1,
        "parentId": null,
        "rootParentId": null,
        "user": {
            "id": 2,
            "username": "gwy002",
            "password": "4297f44b13955235245b2497399d7a93",
            "name": "顾无言002",
            "sex": "男",
            "phone": "17544685987",
            "email": "gwy002@163.com",
            "address": "阿松大阿松大阿萨的",
            "avatar": "http://localhost:9090/file/download/微信图片_20240114165331.jpg",
            "createTime": "2024-01-10 02:58:09",
            "loginTime": null,
            "createTimeStr": null,
            "loginTimeStr": null,
            "role": "用户",
            "token": "",
            "status": 1,
            "cart": null,
            "orders": null,
            "reviews": null
        },
        "child": [
            {
                "id": 8,
                "content": "回复2-1",
                "userId": 1,
                "createTime": "2022-10-14 06:20:07",
                "isDelete": 0,
                "productId": 1,
                "parentId": 7,
                "rootParentId": 7,
                "user": {
                    "id": 1,
                    "username": "gwy001",
                    "password": "c8837b23ff8aaa8a2dde915473ce0991",
                    "name": "阿松大",
                    "sex": "男",
                    "phone": "13131231",
                    "email": "231313@qq.com",
                    "address": "大锅饭大概豆腐干的风格的给",
                    "avatar": "http://localhost:9090/file/download/img.png",
                    "createTime": "2024-01-17 02:57:56",
                    "loginTime": "2024-01-23 02:57:26",
                    "createTimeStr": null,
                    "loginTimeStr": null,
                    "role": "用户",
                    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwiZXhwIjoxNzEwNjY5ODQ4fQ.FlLosYXsB_zfFzP_NIGLOBI7O0W_A6LSBQcFVEHFTBU",
                    "status": 1,
                    "cart": null,
                    "orders": null,
                    "reviews": null
                },
                "child": null
            }
        ]
    },
    {
        "id": 1,
        "content": "评论1",
        "userId": 1,
        "createTime": "2022-10-05 06:14:32",
        "isDelete": 0,
        "productId": 1,
        "parentId": null,
        "rootParentId": null,
        "user": {
            "id": 1,
            "username": "gwy001",
            "password": "c8837b23ff8aaa8a2dde915473ce0991",
            "name": "的风格",
            "sex": "男",
            "phone": "132323333",
            "email": "12313123@qq.com",
            "address": "上大师傅大师傅士大夫士大夫是",
            "avatar": "http://localhost:9090/file/download/img.png",
            "createTime": "2024-01-17 02:57:56",
            "loginTime": "2024-01-23 02:57:26",
            "createTimeStr": null,
            "loginTimeStr": null,
            "role": "用户",
            "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwiZXhwIjoxNzEwNjY5ODQ4fQ.FlLosYXsB_zfFzP_NIGLOBI7O0W_A6LSBQcFVEHFTBU",
            "status": 1,
            "cart": null,
            "orders": null,
            "reviews": null
        },
        "child": [
            {
                "id": 3,
                "content": "回复1-2",
                "userId": 2,
                "createTime": "2022-10-07 06:16:25",
                "isDelete": 0,
                "productId": 1,
                "parentId": 1,
                "rootParentId": 1,
                "user": {
                    "id": 2,
                    "username": "gwy002",
                    "password": "4297f44b13955235245b2497399d7a93",
                    "name": "顾无言002",
                    "sex": "男",
                    "phone": "17544685987",
                    "email": "gwy002@163.com",
                    "address": "河北省唐山市路北区唐山学院",
                    "avatar": "http://localhost:9090/file/download/微信图片_20240114165331.jpg",
                    "createTime": "2024-01-10 02:58:09",
                    "loginTime": null,
                    "createTimeStr": null,
                    "loginTimeStr": null,
                    "role": "用户",
                    "token": "",
                    "status": 1,
                    "cart": null,
                    "orders": null,
                    "reviews": null
                },
                "child": [
                    {
                        "id": 35,
                        "content": "我现在回复的是【顾无言002】,你好",
                        "userId": 1,
                        "createTime": "2024-03-19 04:15:17",
                        "isDelete": 0,
                        "productId": 1,
                        "parentId": 3,
                        "rootParentId": 1,
                        "user": {
                            "id": 1,
                            "username": "gwy001",
                            "password": "c8837b23ff8aaa8a2dde915473ce0991",
                            "name": "阿松大",
                            "sex": "男",
                            "phone": "15525555585",
                            "email": "1030414374@qq.com",
                            "address": "山西省太原市546456456",
                            "avatar": "http://localhost:9090/file/download/img.png",
                            "createTime": "2024-01-17 02:57:56",
                            "loginTime": "2024-01-23 02:57:26",
                            "createTimeStr": null,
                            "loginTimeStr": null,
                            "role": "用户",
                            "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwiZXhwIjoxNzEwNjY5ODQ4fQ.FlLosYXsB_zfFzP_NIGLOBI7O0W_A6LSBQcFVEHFTBU",
                            "status": 1,
                            "cart": null,
                            "orders": null,
                            "reviews": null
                        },
                        "child": null
                    },
                    {
                        "id": 6,
                        "content": "回复1-2-1",
                        "userId": 3,
                        "createTime": "2022-10-13 06:18:51",
                        "isDelete": 0,
                        "productId": 1,
                        "parentId": 3,
                        "rootParentId": 1,
                        "user": {
                            "id": 3,
                            "username": "user1",
                            "password": "4297f44b13955235245b2497399d7a93",
                            "name": "张三",
                            "sex": "男",
                            "phone": "13800138001",
                            "email": "user1@example.com",
                            "address": "北京市朝阳区",
                            "avatar": "http://localhost:9090/file/download/微信图片_202401141653313.jpg",
                            "createTime": "2024-01-02 02:58:16",
                            "loginTime": null,
                            "createTimeStr": null,
                            "loginTimeStr": null,
                            "role": "用户",
                            "token": "",
                            "status": 1,
                            "cart": null,
                            "orders": null,
                            "reviews": null
                        },
                        "child": null
                    }
                ]
            }
        ]
    }
]
  1. 前端vue展示

这里的话需要用到组件传值,我们在商品的评论展示的时候需要用到子组件来展示,当前评论下的所有相关回复评论的信息。

在这里,我们的父组件是我们的用来展示评论的页面,子组件是用来展示所有相关回复评论的信息的。

父组件:

下面的是核心代码

这个是用来展示评论的页面,把下面的代码块适配到你自己的代码内

<template>
    <div>


        <el-row :gutter="10">
            <el-col :span="6">10</el-col>
        </el-row>

        <div>
            <el-button style="width: 500px;margin: 50px" size="medium" type="primary" @click="loadCommentList">测试
            </el-button>
        </div>

        <!--        评论区     -->
        <el-card style="height: 440px; overflow-y: auto;">

            <div v-if="commentList.length <= 0">
                <el-empty :image-size="200"></el-empty>
            </div>
            <div class="box-card" v-for="(comment,index) in commentList" :key="index">

                <!--     根评论       -->

                <el-row>
                    <el-col :span="1">
                        <!--  用户头像  -->
                        <el-col :span="1">
                            <div class="block">
                                <el-avatar :size="50" :src="comment.user.avatar"></el-avatar>
                            </div>
                        </el-col>
                    </el-col>
                    <el-col :span="23">
                        <el-row>
                            <!--  用户昵称  -->
                            <el-col :span="2">
                                <span>{{ comment.user.name }}</span>
                            </el-col>
                            <!--  评论时间  -->
                            <el-col :span="21">
                                <span style="color: #99a9bf">{{ comment.createTime }}</span>
                            </el-col>
                            <!--  操作  -->
                            <el-col :span="1">
                                <el-link v-if="comment?.userId === parseInt(userId)"
                                         @click="deleteComment(comment)">
                                    删除
                                </el-link>
                                <el-link v-if="comment?.userId !== parseInt(userId)"
                                         @click="replyComment(comment)">回复
                                </el-link>
                            </el-col>
                        </el-row>

                        <el-row>
                            <!--  评论内容  -->
                            <span style="font-size: 15px">{{ comment.content }}</span>
                        </el-row>
                    </el-col>
                </el-row>


                <!--     子评论       -->
                <div style="margin-left: 80px">
                    <!--     递归实现子评论的展示      -->
                    <childComment :list="comment.child" :parentName="comment.user.name" :currentUserId="userId"
                                  @data="handleMessageFromChild"/>
                </div>


            </div>

        </el-card>
        <el-card>
            <el-row>
                <el-col :span="22">
                    <el-input
                            type="textarea"
                            placeholder="请输入内容"
                            v-model="textarea"
                            maxlength="50"
                            show-word-limit
                    >
                    </el-input>
                </el-col>
                <el-col :span="2">
                    <el-button v-if="parentId !== ''" type="primary" size="medium" @click="sendComment">回复</el-button>
                    <el-link v-if="parentId !== ''" type="info" size="medium" @click="cancelComment">取消回复
                    </el-link>
                    <el-button v-if="parentId === ''" type="success" size="medium" @click="sendComment">发送</el-button>
                </el-col>
            </el-row>
        </el-card>
    </div>
</template>

<style>
<script>
import childComment from "./childComment.vue";

export default {
    components: {
        childComment
    },
    data() {
        return {
            textarea: '',
            userId: '1',
            productId: '1',
            parentId: '',  //  parent_id
            rootParentId: '',  //  root_parent_id
            commentList: [],
            circleUrl: "https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png",
    },
    methods: {

        // 发送评论
        sendComment() {
            // 评论内容         从输入框获取
            // 用户id          从本地获取
            // 发布时间         后端生成
            // is_delete        0
            // productId       从return获取商品id
            // 父评论id        父评论就是从点击回复里面获取的      如果存在,那么就在return中
            // 根评论id        从 父评论 中获取 根评论id         如果存在,那么就在return中

            if (this.userId === null || this.userId === '' || this.userId === undefined) {
                this.$message.info('请先登录')
                return
            }
            if (this.productId === null || this.productId === '' || this.productId === undefined) {
                this.$message.info('商品不存在')
                this.$router.go(-1)
            }

            let comment = {}
            comment.content = this.textarea
            comment.userId = this.userId
            comment.isDelete = 0
            comment.productId = this.productId
            comment.parentId = this.parentId
            comment.rootParentId = this.rootParentId
            console.log(comment);
            this.$request.post('/comment/add', comment).then(res => {
                if (res.code === '200') {
                    this.$message.success('评论成功')
                    this.loadCommentList()
                    this.textarea = ''
                    this.cancelComment()
                } else {
                    this.$message.error(res.msg)
                }
            })
        },
        // 子组件返回值
        handleMessageFromChild(data) {
            console.log('父组件接收到数据:' + data)
            console.log(data);
            this.parentId = data.parentId
            this.rootParentId = data.rootParentId
        },
        // 回复设置
        replyComment(comment) {
            this.parentId = comment.id
            this.rootParentId = comment.rootParentId
            console.log(this.parentId)
            console.log(this.rootParentId)
        },
        // 取消回复
        cancelComment() {
            this.parentId = ''
            this.rootParentId = ''
            console.log(this.parentId)
            console.log(this.rootParentId)
        },
        // 删除评论
        deleteComment(comment) {
            // 直接删除这个评论就行,实体类
            console.log(comment)
            this.$request.post('/comment/delete', comment).then(res => {
                if (res.code === '200') {
                    this.$message.success('删除成功')
                    this.loadCommentList()
                } else {
                    this.$message.error(res.msg)
                }
            })
        },
        // 获取评论集合
        loadCommentList() {
            this.$request.get('/comment/list' + '?productId=1').then(res => {
                if (res.code == '200') {
                    this.commentList = res.data.commentList
                    console.log(this.commentList)
                } else {
                    this.$message.error(res.msg)
                }
            })
        },
    }
}

</script>

子组件:childComment.vue

<script>
import {defineComponent} from 'vue'

export default defineComponent({
    name: "childComment",
    props: {
        list: {
            type: Array,
            default: () => []
        },
        parentName: {
            type: String,
            default: ''
        },
        currentUserId: {
            type: String,
            default: ''
        }
    },
    methods: {
        replyComment(comment) {
            let data = {
                parentId: comment.id,
                rootParentId: comment.rootParentId,
                commentProductId: comment.productId
            }
            this.$emit('data', data);
            console.log('子组件向父组件传值', data)
        },
        deleteComment(comment) {
            // 直接删除这个评论就行,实体类
        },

        handleMessageFromChild(data) {
            console.log('父组件接收到数据:' + data)
            console.log(data);
            /*    this.parentId = data.parentId
                this.rootParentId = data.rootParentId
                let data = {
                    parentId: comment.id,
                    rootParentId: comment.rootParentId
                }*/
            this.$emit('data', data);
            console.log('子组件向父组件传值', data)
        },
    }
})
</script>

<template>

    <div>
        <div v-for="(comment, index) in list" :key="index">
            <el-row>
                <el-col :span="2">
                    <!--  用户头像  -->
                    <div class="block" style="margin-left: 10px">
                        <el-avatar :size="40" :src="comment.user.avatar"></el-avatar>
                    </div>
                </el-col>
                <el-col :span="22">
                    <el-row>
                        <!--  子评论用户昵称  -->
                        <el-col :span="2">
                            <span style="color: #a19e93"> {{ comment.user.name }}</span>
                        </el-col>

                        <!--  回复  -->
                        <el-col :span="2">
                            <span style="color: #a19e93">回复</span>
                        </el-col>

                        <!--  根评论用户昵称  -->
                        <el-col :span="2">
                            <span style="color: #a19e93">{{ parentName }}</span>
                        </el-col>
                        <!--  评论时间  -->
                        <el-col :span="16">
                            <span style="color: #99a9bf">{{ comment.createTime }}</span>
                        </el-col>
                        <!--  操作  -->
                        <el-col :span="1">
                            <el-link v-if="parseInt(currentUserId) === comment.userId"
                                     @click="deleteComment(comment)">删除
                            </el-link>
                            <el-link v-if="parseInt(currentUserId) !== comment.userId"
                                     @click="replyComment(comment)">回复
                            </el-link>
                        </el-col>

                    </el-row>

                    <el-row style="margin: 5px 0">
                        <!--  回复内容  -->
                        <span style="font-size: 15px">{{ comment.content }}</span>
                    </el-row>
                </el-col>
            </el-row>
            <!--   递归的核心     -->
            <childComment v-if="comment.child?.length" :list="comment.child" :parentName="comment.user.name"
                          :currentUserId="currentUserId" @data="handleMessageFromChild"/>

        </div>
    </div>


</template>

<style scoped>

</style>
  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
作为AI领域的热门技术之一,人脸识别已经在很多领域得到了广泛的应用。本文将介绍如何利用SpringBootVueMybatis等技术实现人脸识别功能。 1. 准备工作 在开始实现功能之前,我们需要准备一些必要的工具和素材: - 一台安装了Windows或Linux操作系统的电脑 - Java JDK 8以上版本 - IntelliJ IDEA或Eclipse等IDE - Vue CLI和Node.js - OpenCV库 - 一些人脸照片和人脸数据库 2. 搭建环境 首先,我们需要创建一个SpringBoot项目,并在pom.xml文件中添加Mybatis、MySQL和SpringBoot Web等依赖: ``` <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 接着,我们需要使用Vue CLI创建一个Vue项目,并安装Vuetify UI库和Axios HTTP库: ``` $ vue create face-recognition-system $ cd face-recognition-system $ npm install vuetify axios --save ``` 3. 图片处理 在人脸识别功能中,我们需要对照片进行处理,从照片中提取出人脸信息。这一步可以使用OpenCV库实现。 首先,我们需要下载安装OpenCV库,并在Java项目中添加相关的依赖: ``` <dependency> <groupId>org.openpnp</groupId> <artifactId>opencv</artifactId> <version>4.5.2-0</version> </dependency> ``` 接着,我们可以使用OpenCV库中的一些函数来处理照片。例如,我们可以使用CascadeClassifier类来加载人脸检测模型,并使用imread函数来读取照片: ``` CascadeClassifier faceDetector = new CascadeClassifier("haarcascade_frontalface_default.xml"); Mat image = Imgcodecs.imread("path/to/image.jpg"); MatOfRect faceDetections = new MatOfRect(); faceDetector.detectMultiScale(image, faceDetections); ``` 4. 数据库操作 在人脸识别功能中,我们需要将从照片中提取出的人脸信息存储到数据库中,以便后续的识别和比对。 使用Mybatis操作数据库非常方便。我们只需要在Java项目中创建一个Mapper接口,定义相关的SQL语句,并使用@Mapper注解将接口注册为Mybatis的Mapper。例如,我们可以定义一个UserMapper接口用于操作用户信息的表: ``` @Mapper public interface UserMapper { @Select("select * from user where username=#{username}") User findByUsername(String username); @Select("select * from user where face_id=#{faceId}") User findByFaceId(String faceId); @Insert("insert into user(username, password, face_id) values(#{username}, #{password}, #{faceId})") int insert(User user); @Update("update user set username=#{username}, password=#{password}, face_id=#{faceId} where id=#{id}") int update(User user); @Delete("delete from user where id=#{id}") int deleteById(int id); } ``` 在使用Mapper接口中的方法之前,我们需要在application.properties中配置数据库信息: ``` spring.datasource.url=jdbc:mysql://localhost:3306/face_recognition_db spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver ``` 5. 实现识别和比对 最后,我们需要将人脸识别的功能整合起来,完成整个系统的实现。 首先,在前端页面中,我们可以使用Vuetify UI库中的<v-file-input>组件来上传照片,并使用Axios库将照片发送到后端的接口: ``` <v-file-input v-model="file" label="Choose a file"></v-file-input> methods: { uploadFile() { let formData = new FormData(); formData.append('file', this.file); axios.post('/api/recognition', formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(response => { this.result = response.data.result; }).catch(error => { console.error(error); }) } } ``` 接着,在后端的Controller中,我们可以使用OpenCV库和Mybatis库来进行照片识别和比对。例如,我们可以定义一个/recognition接口用于照片识别和比对: ``` @PostMapping("/recognition") public Result recognition(@RequestParam("file") MultipartFile file) throws IOException { CascadeClassifier faceDetector = new CascadeClassifier("haarcascade_frontalface_default.xml"); Mat image = Imgcodecs.imdecode(new MatOfByte(file.getBytes()), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED); MatOfRect faceDetections = new MatOfRect(); faceDetector.detectMultiScale(image, faceDetections); // 识别出的人脸数量不为1,则返回错误信息 if (faceDetections.toArray().length != 1) { return Result.error("No or multiple faces detected"); } Mat face = image.submat(faceDetections.toArray()[0]); byte[] faceBytes = new byte[(int) (face.total() * face.elemSize())]; face.get(0, 0, faceBytes); String faceId = FaceRecognitionUtils.getFaceId(faceBytes); // 根据faceId在数据库中查找对应的用户 User user = userMapper.findByFaceId(faceId); if (user == null) { return Result.error("Unknown user"); } return Result.success(user.getUsername()); } ``` 在上述代码中,我们首先使用OpenCV库识别照片中的人脸,然后使用FaceRecognitionUtils类中的getFaceId函数将人脸信息转化为一个唯一的faceId,最后查询数据库中是否存在对应的用户。 至此,整个人脸识别系统的实现已经完成了。当然,由于涉及到的技术非常多,上述代码也只是一个简单的示例。如果您想深入了解人脸识别相关的技术和应用,建议再深入学习一下相关的知识和技术。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值