springboot+vue3+ts实现一个点赞功能

news2025/4/16 7:59:32

前端:vite+vue3+ts+elementplus+less

后端:springboot2.7.5+mybatisplus

后端:

引入pom依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.2</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

运行sql

/*
 Navicat Premium Data Transfer

 Source Server         : MyDemo
 Source Server Type    : MySQL
 Source Server Version : 80027
 Source Host           : 192.168.157.134:3306
 Source Schema         : giveALike

 Target Server Type    : MySQL
 Target Server Version : 80027
 File Encoding         : 65001

 Date: 21/11/2022 23:50:34
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for article
-- ----------------------------
DROP TABLE IF EXISTS `article`;
CREATE TABLE `article`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '编号',
  `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '内容',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of article
-- ----------------------------
INSERT INTO `article` VALUES (1, '11');
INSERT INTO `article` VALUES (2, '666');
INSERT INTO `article` VALUES (3, '777');
INSERT INTO `article` VALUES (4, '999');

-- ----------------------------
-- Table structure for giveALike
-- ----------------------------
DROP TABLE IF EXISTS `giveALike`;
CREATE TABLE `giveALike`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '编号',
  `user_id` int NULL DEFAULT NULL COMMENT '用户编号',
  `article_id` int NULL DEFAULT NULL COMMENT '文章编号',
  `is_like` int NULL DEFAULT NULL COMMENT '是否点赞(0表示未点赞,1表示点赞)',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 935456769 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of giveALike
-- ----------------------------

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '编号',
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户名',
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密码',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '11', '11');

SET FOREIGN_KEY_CHECKS = 1;
 

项目结构

 

yml配置

server:
  port: 5000

spring:
  application:
    name: service-user

  datasource:
    url: jdbc:mysql://192.168.157.134:3306/giveALike?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root

entity下的三个实体类

Article:

@Data
public class Article {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;//编号
    private String content;//内容
}

 GiveALike:

@Data
@TableName("giveALike")
public class GiveALike {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    private Integer articleId;//文章编号
    private Integer userId;//用户编号
    private int isLike;//是否点赞(0表示未点赞,1表示点赞)
}

User:

@Data
public class User {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;//用户id
    private String username;//用户名
    private String password;//密码
}

mapper

ArticleMapper:

@Mapper
public interface ArticleMapper extends BaseMapper<Article> {
}

GiveALikeMapper:

@Mapper
public interface GiveALikeMapper extends BaseMapper<GiveALike> {
}

UserMapper:

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

controller

@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/giveALike")
public class GiveALikeController {

    @Resource
    private UserMapper userMapper;

    @Resource
    private ArticleMapper articleMapper;

    @Resource
    private GiveALikeMapper giveALikeMapper;

    //登录
    @PostMapping("/login")
    public User login(@RequestBody User user) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("username", user.getUsername());
        User vo = userMapper.selectOne(userQueryWrapper);
        if (vo != null && Objects.equals(vo.getPassword(), user.getPassword())) {
            return vo;
        } else {
            return null;
        }
    }

    //获取所有文章数据
    @GetMapping("/getList")
    public List<Article> getList() {
        return articleMapper.selectList(null);
    }

    //获取当前用户点赞表的数据
    @GetMapping("/getUserLike/{id}")
    public List<GiveALike> getUserLike(@PathVariable int id) {
        QueryWrapper<GiveALike> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", id);
        return giveALikeMapper.selectList(wrapper);
    }

    //点赞
    @PostMapping("/saveUserLike")
    public GiveALike saveUserLike(@RequestBody GiveALike giveALike) {
        QueryWrapper<GiveALike> wrapper = new QueryWrapper<>();
        wrapper.eq("article_id", giveALike.getArticleId()).eq("user_id", giveALike.getUserId());
        GiveALike vo = giveALikeMapper.selectOne(wrapper);
        if (vo != null) {
            if (vo.getIsLike() == 0) {
                vo.setIsLike(1);
            } else {
                vo.setIsLike(0);
            }
            giveALikeMapper.updateById(vo);
            return vo;
        } else {
            giveALike.setIsLike(1);
            giveALikeMapper.insert(giveALike);
            return giveALike;
        }
    }
}

 

前端:

相关依赖

目录结构

 

main.ts页面

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from "./router";

createApp(App).use(router).use(ElementPlus).mount('#app')

App.vue页面

<template>
  <div id="app">
    <router-view/>
  </div>
</template>
<style>

</style>

 

 路由router

import { createRouter,createWebHistory } from "vue-router";

const routes = [
    {
        path:"/home",
        name:'首页',
        component:()=>import('../page/home.vue')
    },
    {
        path:"/",
        name:'登录',
        component:()=>import('../page/login.vue')
    },
]

const router = createRouter({
    history:createWebHistory(),
    routes:routes,
})

export default router

 登录页面login

<template>
  <div class="main">
    <div class="main_username">
      <input v-model="user.username" class="username" type="text" placeholder="请输入用户名">
    </div>
    <div class="main_password">
      <input v-model="user.password" class="password" type="password" placeholder="请输入密码">
    </div>
    <el-button @click="login" type="primary" class="main_login">登录</el-button>
  </div>
</template>

<script setup lang="ts">
import {ElMessage} from 'element-plus'
import {reactive} from "vue";
import axios from "axios";
import router from "../router";

interface User {
  username: string,
  password: string
}

//登录所需的信息
const user = reactive<User>({
  username: '11',
  password: '11'
})

//登录
const login = () => {
  axios.post("http://localhost:5000/giveALike/login", user).then((res) => {
    if (res.data != '') {
      ElMessage({
        message: '登录成功',
        type: 'success',
      })
      //跳转页面
      router.push("/home")
      //将用户信息存到session
      window.sessionStorage.setItem("user", JSON.stringify(res.data))
    } else {
      console.log(66)
      ElMessage.error('登录失败')
    }
  })
}
</script>

<style lang="less" scoped>
.main {
  .main_username {
    margin-bottom: 10px;

    input {
      font-size: 30px;
    }
  }

  .main_password {
    input {
      font-size: 30px;
    }
  }

  .main_login {
    font-size: 30px;
    margin-top: 10px;
  }
}
</style>

 home页面

<template>
  <div v-loading="loading">
    <div v-for="item in data.articleList" :key="item.id">
      <div class="item">
        <div class="item_id">编号:{{ item.id }}</div>
        <div class="item_content">内容:{{ item.content }}</div>
        <div>{{ item }}</div>
        <img v-if="item.isLike===0" @click="handleLike(item.id)" src="../assets/未点赞.png" class="item_img" alt="图片">
        <img v-else @click="handleLike(item.id)" src="../assets/点赞.png" class="item_img" alt="图片">
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import axios from "axios";
import {reactive, ref} from "vue";
import {ElMessage} from "element-plus";

//加载特效
const loading = ref<boolean>(true)

const data = reactive({
  articleList: [] as Article[],//所有内容列表
  userLikeList: [] as any[]//当前用户点赞表的数据
})

interface giveALike {
  articleId: number,
  userId: number
}

interface Article {
  id: number,
  content: string,
  isLike?: number
}

//点赞所需的参数
const giveALikeParam = reactive<giveALike>({
  articleId: 0,//文章编号
  userId: 0//用户编号
})

//获取所有内容
const getList = () => {
  axios.get("http://localhost:5000/giveALike/getList").then((res) => {
    data.articleList = res.data
  })
}

//点赞
const handleLike = (row: number) => {
  //从session中获取用户信息
  const user = JSON.parse(window.sessionStorage.getItem("user") || '')
  //设置用户编号
  giveALikeParam.userId = user.id
  //设置文章编号
  giveALikeParam.articleId = row
  axios.post("http://localhost:5000/giveALike/saveUserLike", giveALikeParam).then((res) => {
    data.articleList[row - 1].isLike = data.articleList[row - 1].isLike === 1 ? 0 : 1;
    if (res.data.isLike == 1) {
      ElMessage({
        message: '点赞成功',
        type: 'success',
      })
    } else {
      ElMessage({
        message: '取消点赞',
        type: 'warning',
      })
    }
  })
}

//获取当前用户点赞表的数据
const getLikeList = () => {
  //从session中获取用户信息
  const user = JSON.parse(window.sessionStorage.getItem("user") || '')
  axios.get("http://localhost:5000/giveALike/getUserLike/" + user.id).then((res) => {
    data.userLikeList = res.data
    //懒加载
    setTimeout(()=>{
      userIsLike()
      loading.value = false
    },1000)
  })
}

//查询用户是否点赞
const userIsLike = () => {
  if(data.userLikeList.length!=0){
    for (let i = 0; i < data.articleList.length; i++) {
      for (let j = 0; j < data.userLikeList.length; j++) {
        if (data.articleList[i].id === data.userLikeList[j].articleId) {
          data.articleList[i].isLike = data.userLikeList[j].isLike
          break;
        } else {
          data.articleList[i].isLike = 0
        }
      }
    }
  }else{
    for (let i = 0; i < data.articleList.length; i++) {
      data.articleList[i].isLike = 0
    }
  }
}

getList()
getLikeList()
</script>

<style lang="less" scoped>
.item {
  display: flex;

  .item_id {
    margin-right: 10px;
  }

  .item_content {
    width: 100px;
  }

  .item_img {
    width: 100px;
    height: 100px;
    cursor: pointer;
  }
}
</style>

 上述代码如有问题,欢迎提出来,博主看到了会第一时间解决

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/24945.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通俗理解模拟退火算法,小白也看得懂!

模拟退火的实例 齐白石原是木匠&#xff0c;快30岁才正式学画。直到57岁以后画风开始转变&#xff0c;才真正有所成就。 鲁迅原本留日学医&#xff0c;25岁弃医从文&#xff0c;但37岁时才写出第一篇白话文小说《狂人日记》。 项羽在24岁巨鹿之战成名&#xff0c;26岁封王却走…

Advances in Graph Neural Networks笔记2:Fundamental Graph Neural Networks

诸神缄默不语-个人CSDN博文目录 本书网址&#xff1a;https://link.springer.com/book/10.1007/978-3-031-16174-2 本文是本书第二章的学习笔记。 我们学校没买这书&#xff0c;但是谷歌学术给我推文献时给出了一个能免登录直接上的地址&#xff0c;下次就不一定好使了&#…

Web of science,scopus,Google scholar的介绍和区别

Overview 最近为了和实验室同学分享这几个常见的数据库的区别&#xff0c;因此做了一个简单的 从这张图上面可以看到&#xff0c;Web of science (Wos)是在1997年&#xff0c;由Institute for Scientific Information (ISI)合并多种索引建立的&#xff0c;而ISI在1992年加入了…

11.21二叉树oj

目录 一.队列.栈顺序表总结 二.猫狗问题 三.股票价格跨度 四.二叉树的初始化 1.获取树中节点的个数 1.遍历思路 2.子问题思路 2.叶子节点个数 3.获取第K层节点的个数 4.获取二叉树的高度 6.判断一棵树是不是完全二叉树 一.队列.栈顺序表总结 1.顺序表和栈的底层都是…

C++ 单向链表手动实现(课后作业版)

单向链表&#xff0c;并实现增删查改等功能 首先定义节点类&#xff0c;类成员包含当前节点的值和下一个节点的地址 /node definition template <typename T> class Node { public:T value;Node<T>* next;Node() {}Node(const T& value) {this->value va…

ES6 入门教程 19 Generator 函数的语法 19.7 yield星号表达式

ES6 入门教程 ECMAScript 6 入门 作者&#xff1a;阮一峰 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录ES6 入门教程19 Generator 函数的语法19.7 yield* 表达式19 Generator 函数的语法 19.7 yield* 表达式 如果在 Generator 函数内部&…

windows域控批量创建账号方法

目录 一、收集信息 二、编写脚本 &#xff08;一&#xff09;新建aduser.ps1的powershell脚本 &#xff08;二&#xff09;New-Aduser命令详解 三、生产环境报错 &#xff08;一&#xff09;ConvertTo-SecureString &#xff08;二&#xff09;指定的账号已存在 &#xff…

debian11 安装后必备配置

debian11 安装后必备配置 运行环境&#xff1a;PVE v7.2-11 CT容器 系统版本&#xff1a;Debian-11-standard_11.3-1_amd64.tar.zst 启动信息 Debian GNU/Linux 11 debian tty1debian login: root Password: Linux debian 5.15.64-1-pve #1 SMP PVE 5.15.64-1 (Thu, 13 Oct …

【数据结构】堆的实现堆排序Top-K

文章目录一、堆的概念及结构二、堆实现&#xff08;1&#xff09;创建结构体&#xff08;2&#xff09;具体函数实现及解析1.0 交换函数1.1 堆的打印1.2 堆的初始化1.3 堆的销毁1.4 堆的插入1.5堆的向上调整算法1.6 堆的删除1.7堆的向下调整算法1.8 取堆顶的数据1.9 堆的数据个…

【力扣练习】找一个字符串中不含有重复字符的最长字串的长度

class Solution: def lengthOfLongestSubstring(self, s: str) -> int: # 哈希集合&#xff0c;记录每个字符是否出现过 occ set() n len(s) # 右指针&#xff0c;初始值为 -1&#xff0c;相当于我们在字符串的左边界的左侧&#xff…

【项目实战】Spring Boot项目抵御XSS攻击

本专栏将为大家总结项目实战相关的知识&#xff01; 点击即可关注本专栏&#xff0c;获取更多知识&#xff01; 文章目录前言一、什么是XSS攻击二、如何抵御XSS攻击三、实现抵御XSS攻击结语前言 作为Web网站来说&#xff0c;抵御XSS攻击是必须要做的事情&#xff0c;这是非常常…

C++基础知识

目录 C的基本使用 C数据的输入与输出 C使用命令行 具体案例 C生成随机数 关键字 标识符命名规则 数据类型 整形 实型&#xff08;浮点型&#xff09; 浮点型变量分为2种 表示小数的两种方式 案例演示 字符型 案例演示 字符串类型 两种风格 两种风格字符串之间…

【MyBatis】MyBtis入门程序

1. 目录结构 2. 数据库表的设计 /*Navicat Premium Data TransferSource Server : MysqlSource Server Type : MySQLSource Server Version : 50726Source Host : localhost:3306Source Schema : mybatisTarget Server Type : MySQLTarget Se…

python_循环

一、while循环的基础语法程序中的循环&#xff1a;while 条件&#xff1a;条件满足时&#xff0c;做的事情1条件满足时&#xff0c;做的事情2......即只要条件满足&#xff0c;会无限循环执行代码示例&#xff1a;# 简单示例&#xff1a;向Vivian表白100次i 0 while i < 10…

RabbitMQ系列【13】优先级队列

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 文章目录前言1. 设置优先级队列2. 消息设置优先级前言 RabbitMQ将消息写入队列中都是按顺序写的&#xff0c;消费时也是按顺序进行消费&#xff0c;队列中的消息是先进先出(FIFO).。 首先测试一下没有优…

多数银行人都会忽略5个影响系统性能的因素总结

性能测试往往在投产上线前开展&#xff0c;无法对整个系统变更进行全面的覆盖测试&#xff0c;因此性能测试需求提出十分关键。 性能测试需求交付过程中&#xff0c;需要对开发团队提出的测试需求进行审查&#xff0c;重点分析交付的测试需求是否充分覆盖了影响系统性能的因素…

【OpenCV-Python】教程:3-7 Canny边缘检测

OpenCV Python Canny 边缘检测 【目标】 Canny 边缘检测的概念cv2.Canny 【原理】 1. 去噪 由于边缘检测非常容易收到图像的噪声影响&#xff0c;第一步使用 5x5 高斯滤波去除图像中的噪声。 2. 寻找图像的亮度梯度 在平滑后&#xff08;去噪后&#xff09;的图像利用 S…

1.5 阻塞与非阻塞I/O

文章目录1、阻塞I/O2、非阻塞I/O3、异步I/O4、同步I/O5、epoll原理函数5.1、int epoll_create(int size)5.2、int epoll_ctl(int epfd,int op,int fd,struct epoll_event* event)5.3、int epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout)5.4、内核…

【Linux 线程介绍】

Linux 线程线程一定越多越好吗&#xff1f;线程的实现方式&#xff1a;API:pthread_exit函数演示获取线程的返回值多线程的不安全性查看进程中的线程数进程&#xff1a;一个正在运行的程序 &#xff0c;资源分配的基本单位 线程&#xff1a;进程内部的一条执行序列&#xff08;…

接口自动化测试

接口自动化测试1.基础知识1.接口测试原理2.接口测试点及用例设计方法3.接口测试返回值的处理4.接口测试要点5.常见HTTP状态码6.HTTP基础知识7.接口自动化测试工具2.抓包工具1.chrom抓包2.Fiddle抓包&#xff08;PC端&#xff0c;手机端&#xff09;1.原理2.下载安装3. 认识界面…