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


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

    后端:springboot2.7.13+mybatisplus

    最终效果大致如下:

    后端:

    引入pom依赖

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframework.bootgroupId>
    4. <artifactId>spring-boot-starter-webartifactId>
    5. dependency>
    6. <dependency>
    7. <groupId>mysqlgroupId>
    8. <artifactId>mysql-connector-javaartifactId>
    9.         <version>8.0.33version>
    10. dependency>
    11. <dependency>
    12. <groupId>org.projectlombokgroupId>
    13. <artifactId>lombokartifactId>
    14. <version>1.18.28version>
    15. dependency>
    16. <dependency>
    17. <groupId>com.baomidougroupId>
    18. <artifactId>mybatis-plus-boot-starterartifactId>
    19. <version>3.5.3.1version>
    20. dependency>
    21. <dependency>
    22. <groupId>org.springframework.bootgroupId>
    23. <artifactId>spring-boot-starter-testartifactId>
    24. <scope>testscope>
    25. dependency>
    26. dependencies>

    运行sql

    1. /*
    2.  Navicat Premium Data Transfer
    3.  Source Server         : MyDemo
    4.  Source Server Type    : MySQL
    5.  Source Server Version : 80027
    6.  Source Host           : 192.168.157.134:3306
    7.  Source Schema         : giveALike
    8.  Target Server Type    : MySQL
    9.  Target Server Version : 80027
    10.  File Encoding         : 65001
    11.  Date: 21/11/2022 23:50:34
    12. */
    13. SET NAMES utf8mb4;
    14. SET FOREIGN_KEY_CHECKS = 0;
    15. -- ----------------------------
    16. -- Table structure for article
    17. -- ----------------------------
    18. DROP TABLE IF EXISTS `article`;
    19. CREATE TABLE `article`  (
    20.   `id` int NOT NULL AUTO_INCREMENT COMMENT '编号',
    21.   `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '内容',
    22.   PRIMARY KEY (`id`) USING BTREE
    23. ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    24. -- ----------------------------
    25. -- Records of article
    26. -- ----------------------------
    27. INSERT INTO `article` VALUES (1, '11');
    28. INSERT INTO `article` VALUES (2, '666');
    29. INSERT INTO `article` VALUES (3, '777');
    30. INSERT INTO `article` VALUES (4, '999');
    31. -- ----------------------------
    32. -- Table structure for giveALike
    33. -- ----------------------------
    34. DROP TABLE IF EXISTS `giveALike`;
    35. CREATE TABLE `giveALike`  (
    36.   `id` int NOT NULL AUTO_INCREMENT COMMENT '编号',
    37.   `user_id` int NULL DEFAULT NULL COMMENT '用户编号',
    38.   `article_id` int NULL DEFAULT NULL COMMENT '文章编号',
    39.   `is_like` int NULL DEFAULT NULL COMMENT '是否点赞(0表示未点赞,1表示点赞)',
    40.   PRIMARY KEY (`id`) USING BTREE
    41. ) ENGINE = InnoDB AUTO_INCREMENT = 935456769 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    42. -- ----------------------------
    43. -- Records of giveALike
    44. -- ----------------------------
    45. -- ----------------------------
    46. -- Table structure for user
    47. -- ----------------------------
    48. DROP TABLE IF EXISTS `user`;
    49. CREATE TABLE `user`  (
    50.   `id` int NOT NULL AUTO_INCREMENT COMMENT '编号',
    51.   `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户名',
    52.   `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密码',
    53.   PRIMARY KEY (`id`) USING BTREE
    54. ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    55. -- ----------------------------
    56. -- Records of user
    57. -- ----------------------------
    58. INSERT INTO `user` VALUES (1, '11', '11');
    59. SET FOREIGN_KEY_CHECKS = 1;

    项目结构

    yml配置,数据库改成你自己的数据库

    1. server:
    2. port: 5000
    3. spring:
    4. application:
    5. name: service-user
    6. datasource:
    7. url: jdbc:mysql://192.168.157.134:3306/giveALike?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
    8. driver-class-name: com.mysql.cj.jdbc.Driver
    9. username: root
    10. password: root

    entity下的三个实体类

    Article: 

    1. @Data
    2. public class Article {
    3. @TableId(value = "id", type = IdType.AUTO)
    4. private Integer id;//编号
    5. private String content;//内容
    6. @TableField(exist = false)
    7. private int isLike;//是否点赞(0表示未点赞,1表示点赞)
    8. }

     GiveALike:

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

    User:

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

    mapper

    ArticleMapper:

    1. @Mapper
    2. public interface ArticleMapper extends BaseMapper
      {
    3. }

    GiveALikeMapper:

    1. @Mapper
    2. public interface GiveALikeMapper extends BaseMapper {
    3. }

    UserMapper:

    1. @Mapper
    2. public interface UserMapper extends BaseMapper {
    3. }

    controller

    1. @Slf4j
    2. @CrossOrigin
    3. @RestController
    4. @RequestMapping("/giveALike")
    5. public class GiveALikeController {
    6. @Resource
    7. private UserMapper userMapper;
    8. @Resource
    9. private ArticleMapper articleMapper;
    10. @Resource
    11. private GiveALikeMapper giveALikeMapper;
    12. //登录
    13. @PostMapping("/login")
    14. public User login(@RequestBody User user) {
    15. QueryWrapper userQueryWrapper = new QueryWrapper<>();
    16. userQueryWrapper.eq("username", user.getUsername());
    17. User vo = userMapper.selectOne(userQueryWrapper);
    18. if (vo != null && Objects.equals(vo.getPassword(), user.getPassword())) {
    19. return vo;
    20. } else {
    21. return null;
    22. }
    23. }
    24. //获取所有文章数据
    25. //TODO 优化建议:使用分页,减少并发
    26. @GetMapping("/getList")
    27. public List
      getList() {
    28. List
      articles = articleMapper.selectList(null);
    29. List
      list = new ArrayList<>();
    30. for (Article item : articles) {
    31. QueryWrapper wrapper = new QueryWrapper<>();
    32. wrapper.eq("article_id", item.getId());
    33. GiveALike giveALike = giveALikeMapper.selectOne(wrapper);
    34. if (giveALike == null || giveALike.getIsLike() == 0) {
    35. item.setIsLike(0);
    36. } else {
    37. item.setIsLike(1);
    38. }
    39. list.add(item);
    40. }
    41. return list;
    42. }
    43. //点赞
    44. @PostMapping("/saveUserLike")
    45. @Transactional
    46. public GiveALike saveUserLike(@RequestBody GiveALike giveALike) {
    47. QueryWrapper wrapper = new QueryWrapper<>();
    48. wrapper.eq("article_id", giveALike.getArticleId()).eq("user_id", giveALike.getUserId());
    49. GiveALike vo = giveALikeMapper.selectOne(wrapper);
    50. if (vo != null) {
    51. if (vo.getIsLike() == 0) {
    52. vo.setIsLike(1);
    53. } else {
    54. vo.setIsLike(0);
    55. }
    56. giveALikeMapper.updateById(vo);
    57. return vo;
    58. } else {
    59. giveALike.setIsLike(1);
    60. giveALikeMapper.insert(giveALike);
    61. return giveALike;
    62. }
    63. }
    64. }

    前端:

    相关依赖

    目录结构

    main.ts页面

    1. import { createApp } from 'vue'
    2. import ElementPlus from 'element-plus'
    3. import 'element-plus/dist/index.css'
    4. import App from './App.vue'
    5. import router from "./router";
    6. createApp(App).use(router).use(ElementPlus).mount('#app')

    App.vue页面

    1. <template>
    2. <div id="app">
    3. <router-view/>
    4. div>
    5. template>
    6. <style>
    7. style>

     路由router.ts

    1. import {createRouter, createWebHistory, RouteRecordRaw} from "vue-router";
    2. const routes: Array<RouteRecordRaw> = [
    3. {
    4. path: "/home",
    5. name: '首页',
    6. component: () => import('../page/home.vue')
    7. },
    8. {
    9. path: "/",
    10. name: '登录',
    11. component: () => import('../page/login.vue')
    12. },
    13. ]
    14. const router = createRouter({
    15. history: createWebHistory(),
    16. routes: routes,
    17. })
    18. export default router

     登录页面login.vue

    1. <template>
    2. <div class="main">
    3. <div class="main_username">
    4. <input v-model="user.username" class="username" type="text" placeholder="请输入用户名">
    5. div>
    6. <div class="main_password">
    7. <input v-model="user.password" class="password" type="password" placeholder="请输入密码">
    8. div>
    9. <el-button @click="login" type="primary" class="main_login">登录el-button>
    10. div>
    11. template>
    12. <script setup lang="ts">
    13. import {ElMessage} from 'element-plus'
    14. import {reactive} from "vue";
    15. import axios from "axios";
    16. import router from "../router";
    17. interface User {
    18. username: string,
    19. password: string
    20. }
    21. //登录所需的信息
    22. const user = reactive<User>({
    23. username: '11',
    24. password: '11'
    25. })
    26. //登录
    27. const login = () => {
    28. axios.post("http://localhost:5000/giveALike/login", user).then((res) => {
    29. if (res.data != '') {
    30. ElMessage({
    31. message: '登录成功',
    32. type: 'success',
    33. })
    34. //跳转页面
    35. router.push("/home")
    36. //将用户信息存到session
    37. window.sessionStorage.setItem("user", JSON.stringify(res.data))
    38. } else {
    39. ElMessage.error('登录失败')
    40. }
    41. })
    42. }
    43. script>
    44. <style lang="less" scoped>
    45. .main {
    46. .main_username {
    47. margin-bottom: 10px;
    48. input {
    49. font-size: 30px;
    50. }
    51. }
    52. .main_password {
    53. input {
    54. font-size: 30px;
    55. }
    56. }
    57. .main_login {
    58. font-size: 30px;
    59. margin-top: 10px;
    60. }
    61. }
    62. style>

     home.vue页面

    1. <template>
    2. <div>
    3. <div v-for="item in data.articleList" :key="item.id">
    4. <div class="item">
    5. <div class="item_id">编号:{{ item.id }}div>
    6. <div class="item_content">内容:{{ item.content }}div>
    7. <div>{{ item }}div>
    8. <img v-if="item.isLike===0" @click="handleLike(item.id)" src="../assets/未点赞.png" class="item_img" alt="图片">
    9. <img v-else @click="handleLike(item.id)" src="../assets/点赞.png" class="item_img" alt="图片">
    10. div>
    11. div>
    12. div>
    13. template>
    14. <script setup lang="ts">
    15. import axios from "axios";
    16. import {reactive} from "vue";
    17. import {ElMessage} from "element-plus";
    18. const data = reactive({
    19. articleList: [] as Article[],//所有内容列表
    20. userLikeList: [] as any[]//当前用户点赞表的数据
    21. })
    22. interface GiveALike {
    23. articleId: number,
    24. userId: number
    25. }
    26. interface Article {
    27. id: number,
    28. content: string,
    29. isLike?: number
    30. }
    31. //点赞所需的参数
    32. const giveALikeParam = reactive<GiveALike>({
    33. articleId: 0,//文章编号
    34. userId: 0//用户编号
    35. })
    36. //获取所有内容
    37. const getList = () => {
    38. axios.get("http://localhost:5000/giveALike/getList").then((res) => {
    39. data.articleList = res.data
    40. console.log(res.data)
    41. })
    42. }
    43. //点赞
    44. const handleLike = (row: number) => {
    45. //从session中获取用户信息
    46. const user = JSON.parse(window.sessionStorage.getItem("user") ?? '')
    47. //设置用户编号
    48. giveALikeParam.userId = user.id
    49. //设置文章编号
    50. giveALikeParam.articleId = row
    51. axios.post("http://localhost:5000/giveALike/saveUserLike", giveALikeParam).then((res) => {
    52. data.articleList[row - 1].isLike = data.articleList[row - 1].isLike === 1 ? 0 : 1;
    53. if (res.data.isLike == 1) {
    54. ElMessage({
    55. message: '点赞成功',
    56. type: 'success',
    57. })
    58. } else {
    59. ElMessage({
    60. message: '取消点赞',
    61. type: 'warning',
    62. })
    63. }
    64. })
    65. }
    66. getList()
    67. script>
    68. <style lang="less" scoped>
    69. .item {
    70. display: flex;
    71. .item_id {
    72. margin-right: 10px;
    73. }
    74. .item_content {
    75. width: 100px;
    76. }
    77. .item_img {
    78. width: 100px;
    79. height: 100px;
    80. cursor: pointer;
    81. }
    82. }
    83. style>

     Gitee仓库地址:Gitee

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

    springboot3+react18+ts版

  • 相关阅读:
    苹果macOS系统M1、M2芯片关闭sip的方法
    大数据开发之Apache Hive
    windows开启启动bat脚本
    PHP中性能优化之生成器
    【时间复杂度】定义与计算方法
    5G紧急呼叫流程分析
    【操作系统】9/35MMAP
    前端页面项目——博客系统
    面了个腾讯拿38K跳槽出来的,见识到了真正的测试天花板
    遗传算法GA求解连续函数问题
  • 原文地址:https://blog.csdn.net/crazy1013/article/details/127974796