前端:vite+vue3+ts+elementplus+less
后端:springboot2.7.13+mybatisplus
最终效果大致如下:

后端:
引入pom依赖
- <dependencies>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
-
- <dependency>
- <groupId>mysqlgroupId>
- <artifactId>mysql-connector-javaartifactId>
- <version>8.0.33version>
- dependency>
-
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <version>1.18.28version>
- dependency>
-
- <dependency>
- <groupId>com.baomidougroupId>
- <artifactId>mybatis-plus-boot-starterartifactId>
- <version>3.5.3.1version>
- dependency>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- 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;//内容
- @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
{ - }
GiveALikeMapper:
- @Mapper
- public interface GiveALikeMapper extends BaseMapper
{ - }
UserMapper:
- @Mapper
- public interface UserMapper extends BaseMapper
{ - }
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
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
getList() { - List
articles = articleMapper.selectList(null); - List
list = new ArrayList<>(); - for (Article item : articles) {
- QueryWrapper
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
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
上述代码如有问题,欢迎提出来,博主看到了会第一时间解决