以下是使用 Spring Boot + Vue + Mybatis - Plus 实现文章点赞功能的步骤:
后端实现(Spring Boot + Mybatis - Plus)
- 数据库设计
创建article
表和article_like
表。article
表存储文章信息,article_like
表用于记录点赞信息,结构如下:
article
表:
字段名 | 类型 | 说明 |
---|---|---|
id | bigint | 文章 ID(主键) |
title | varchar | 文章标题 |
content | text | 文章内容 |
like_count | int | 点赞数(初始值为 0) |
article_like
表:
字段名 | 类型 | 说明 |
---|---|---|
id | bigint | 点赞记录 ID(主键) |
article_id | bigint | 文章 ID(外键,关联article 表的id ) |
user_id | bigint | 用户 ID(假设你有用户系统) |
2.创建实体类
Article
类
import com.baomidou.mybatisplus.annotation.IdentityStrategy;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("article")
public class Article {
@TableId(type = IdentityStrategy.AUTO)
private Long id;
private String title;
private String content;
private Integer likeCount = 0;
}
ArticleLike
类
import com.baomidou.mybatisplus.annotation.IdentityStrategy;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("article_like")
public class ArticleLike {
@TableId(type = IdentityStrategy.AUTO)
private Long id;
private Long articleId;
private Long user_id;
}
- 创建 Mapper 接口
ArticleMapper
接口:
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
import com.example.demo.model.Article;
@Repository
public interface ArticleMapper extends BaseMapper<Article> {
}
ArticleLikeMapper
接口:
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
import com.example.demo.model.ArticleLike;
@Repository
public interface ArticleLikeMapper extends BaseMapper<ArticleLike> {
}
创建 Service 层
ArticleService
接口:
import com.example.demo.model.Article;
import com.baomidou.mybatisplus.extension.service.IService;
public interface ArticleService extends IService<Article> {
void incrementLikeCount(Long articleId);
}
ArticleServiceImpl
类:
import com.example.demo.mapper.ArticleMapper;
import com.example.demo.model.Article;
import com.example.demo.service.ArticleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
@Override
@Transactional
public void incrementLikeCount(Long articleId) {
Article article = getById(articleId);
if (article!= null) {
article.setLikeCount(article.getLikeCount() + 1);
updateById(article);
}
}
}
ArticleLikeService
接口:
import com.example.demo.model.ArticleLike;
import com.baomidou.mybatisplus.extension.service.IService;
public interface ArticleLikeService extends IService<ArticleLike> {
boolean isLikedByUser(Long articleId, Long userId);
void likeArticle(Long articleId, Long userId);
}
ArticleLikeServiceImpl
类
import com.example.demo.mapper.ArticleLikeMapper;
import com.example.demo.model.ArticleLike;
import com.example.demo.service.ArticleLikeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
@Service
public class ArticleLikeServiceImpl extends ServiceImpl<ArticleLikeMapper, ArticleLike> implements ArticleLikeService {
@Override
public boolean isLikedByUser(Long articleId, Long userId) {
return lambdaQuery()
.eq(ArticleLike::getArticleId, articleId)
.eq(ArticleLike::getUser_id, userId)
.count() > 0;
}
@Override
@Transactional
public void likeArticle(Long articleId, Long userId) {
if (!isLikedByUser(articleId, userId)) {
ArticleLike articleLike = new ArticleLike();
articleLike.setArticleId(articleId);
articleLike.setUser_id(userId);
save(articleLike);
}
}
}
- 创建 Controller 类
import com.example.demo.service.ArticleLikeService;
import com.example.demo.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/article")
public class ArticleController {
@Autowired
private ArticleService articleService;
@Autowired
private ArticleLikeService articleLikeService;
// 点赞文章接口
@PostMapping("/{articleId}/like")
public void likeArticle(@PathVariable Long articleId, @RequestHeader("user-id") Long userId) {
articleLikeService.likeArticle(articleId, userId);
articleService.incrementLikeCount(articleId);
}
// 查询文章是否被用户点赞接口
@GetMapping("/{articleId}/isLiked")
public boolean isLiked(@PathVariable Long articleId, @RequestHeader("user-id") Long userId) {
return articleLikeService.isLikedByUser(articleId, userId);
}
}
前端实现(Vue)
- 创建点赞组件(
LikeButton.vue
)
<template>
<button @click="toggleLike">{{ liked? '取消点赞' : '点赞' }}</button>
</template>
<script>
export default {
props: {
articleId: {
type: Number,
required: true
}
},
data() {
return {
liked: false
};
},
methods: {
async toggleLike() {
const userId = this.$store.getters.userId; // 假设从Vuex存储中获取用户ID
if (this.liked) {
// 取消点赞请求
await this.$axios.delete(`/article/${this.articleId}/like`, {
headers: { 'user - id': userId }
});
} else {
// 点赞请求
await this.$axios.post(`/article/${this.articleId}/like`, null, {
headers: { 'user - id': userId }
});
}
this.liked =!this.liked;
},
async checkLiked() {
const userId = this.$store.getters.userId;
const response = await this.$axios.get(`/article/${this.articleId}/isLiked`, {
headers: { 'user - id': userId }
});
this.liked = response.data;
}
},
mounted() {
this.checkLiked();
}
};
</script>
- 在文章展示页面使用点赞组件
<template>
<div>
<h2>{{ article.title }}</h2>
<p>{{ article.content }}</p>
<LikeButton :articleId="article.id" />
</div>
</template>
<script>
import LikeButton from '@/components/LikeButton.vue';
export default {
components: {
LikeButton
},
data() {
return {
article: {}
};
},
// 假设通过接口获取文章数据并赋值给article
mounted() {
// 获取文章数据的逻辑
}
};
</script>
上述代码中的@RequestHeader("user - id")
假设你在请求头中传递用户 ID,实际应用中可能需要根据你的认证和授权机制进行调整。
在实际应用中,你可能需要考虑更多的功能,如取消点赞时减少点赞数、性能优化等。