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

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

后端:springboot2.7.13+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>
        <version>8.0.33</version>
    </dependency>

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

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</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配置,数据库改成你自己的数据库

扫描二维码关注公众号,回复: 16587240 查看本文章
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;//内容
    @TableField(exist = false)
    private int isLike;//是否点赞(0表示未点赞,1表示点赞)
}

 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;
        }
    }

    //获取所有文章数据
    //TODO 优化建议:使用分页,减少并发
    @GetMapping("/getList")
    public List<Article> getList() {
        List<Article> articles = articleMapper.selectList(null);
        List<Article> list = new ArrayList<>();
        for (Article item : articles) {
            QueryWrapper<GiveALike> wrapper = new QueryWrapper<>();
            wrapper.eq("article_id", item.getId());
            GiveALike giveALike = giveALikeMapper.selectOne(wrapper);
            if (giveALike == null || giveALike.getIsLike() == 0) {
                item.setIsLike(0);
            } else {
                item.setIsLike(1);
            }
            list.add(item);
        }
        return list;
    }

    //点赞
    @PostMapping("/saveUserLike")
    @Transactional
    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.ts

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

const routes: Array<RouteRecordRaw> = [
    {
        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.vue

<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 {
      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.vue页面

<template>
  <div>
    <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} from "vue";
import {ElMessage} from "element-plus";

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
    console.log(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',
      })
    }
  })
}

getList()
</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>

 Gitee仓库地址:Gitee

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

springboot3+react18+ts版

猜你喜欢

转载自blog.csdn.net/crazy1013/article/details/127974796