本文目录导读:

我来为你详细介绍PHP项目中实现收藏/点赞功能的完整方案。
数据库设计
基础表结构
-- 用户表 (已有)
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
表 (已有,如文章、视频等)
CREATE TABLE `articles` (
`id` int(11) NOT NULL AUTO_INCREMENT, varchar(200) NOT NULL,
`content` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
-- 点赞记录表
CREATE TABLE `likes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '用户ID',
`target_id` int(11) NOT NULL COMMENT '目标内容ID',
`target_type` varchar(20) NOT NULL COMMENT '目标类型: article, video, comment',
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_target` (`user_id`, `target_id`, `target_type`),
KEY `idx_target` (`target_id`, `target_type`)
) ENGINE=InnoDB;
-- 收藏记录表
CREATE TABLE `favorites` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '用户ID',
`target_id` int(11) NOT NULL COMMENT '目标内容ID',
`target_type` varchar(20) NOT NULL COMMENT '目标类型',
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_target` (`user_id`, `target_id`, `target_type`),
KEY `idx_target` (`target_id`, `target_type`)
) ENGINE=InnoDB;
点赞功能实现
Service层 - LIKE操作
<?php
class LikeService {
private $db;
public function __construct($db) {
$this->db = $db;
}
/**
* 切换点赞状态
* @param int $userId 用户ID
* @param int $targetId 目标ID
* @param string $targetType 目标类型
* @return array
*/
public function toggleLike($userId, $targetId, $targetType) {
try {
// 检查是否已点赞
$hasLiked = $this->checkLike($userId, $targetId, $targetType);
if ($hasLiked) {
// 取消点赞
$this->removeLike($userId, $targetId, $targetType);
$liked = false;
} else {
// 添加点赞
$this->addLike($userId, $targetId, $targetType);
$liked = true;
}
// 获取最新的点赞数
$count = $this->getLikeCount($targetId, $targetType);
return [
'success' => true,
'liked' => $liked,
'count' => $count
];
} catch (Exception $e) {
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* 添加点赞
*/
private function addLike($userId, $targetId, $targetType) {
$sql = "INSERT INTO likes (user_id, target_id, target_type)
VALUES (:user_id, :target_id, :target_type)";
$stmt = $this->db->prepare($sql);
$stmt->execute([
':user_id' => $userId,
':target_id' => $targetId,
':target_type' => $targetType
]);
// 更新内容表的点赞数(如果存在)
$this->updateCount($targetId, $targetType, 'like', 1);
}
/**
* 取消点赞
*/
private function removeLike($userId, $targetId, $targetType) {
$sql = "DELETE FROM likes
WHERE user_id = :user_id
AND target_id = :target_id
AND target_type = :target_type";
$stmt = $this->db->prepare($sql);
$stmt->execute([
':user_id' => $userId,
':target_id' => $targetId,
':target_type' => $targetType
]);
// 更新内容表的点赞数
$this->updateCount($targetId, $targetType, 'like', -1);
}
/**
* 检查是否已点赞
*/
public function checkLike($userId, $targetId, $targetType) {
$sql = "SELECT id FROM likes
WHERE user_id = :user_id
AND target_id = :target_id
AND target_type = :target_type";
$stmt = $this->db->prepare($sql);
$stmt->execute([
':user_id' => $userId,
':target_id' => $targetId,
':target_type' => $targetType
]);
return $stmt->fetch() ? true : false;
}
/**
* 获取点赞数
*/
public function getLikeCount($targetId, $targetType) {
$sql = "SELECT COUNT(*) as count FROM likes
WHERE target_id = :target_id
AND target_type = :target_type";
$stmt = $this->db->prepare($sql);
$stmt->execute([
':target_id' => $targetId,
':target_type' => $targetType
]);
$result = $stmt->fetch();
return $result['count'];
}
/**
* 更新内容表的计数(可选)
*/
private function updateCount($targetId, $targetType, $type, $value) {
// 根据目标类型更新不同表
switch ($targetType) {
case 'article':
$column = $type === 'like' ? 'like_count' : 'favorite_count';
$sql = "UPDATE articles SET {$column} = {$column} + :value WHERE id = :id";
break;
// 可以添加其他类型
}
if (isset($sql)) {
$stmt = $this->db->prepare($sql);
$stmt->execute([
':value' => $value,
':id' => $targetId
]);
}
}
}
收藏功能实现
<?php
class FavoriteService {
private $db;
public function __construct($db) {
$this->db = $db;
}
/**
* 切换收藏状态
*/
public function toggleFavorite($userId, $targetId, $targetType) {
try {
$hasFavorited = $this->checkFavorite($userId, $targetId, $targetType);
if ($hasFavorited) {
$this->removeFavorite($userId, $targetId, $targetType);
$favorited = false;
} else {
$this->addFavorite($userId, $targetId, $targetType);
$favorited = true;
}
$count = $this->getFavoriteCount($targetId, $targetType);
return [
'success' => true,
'favorited' => $favorited,
'count' => $count
];
} catch (Exception $e) {
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
// 添加收藏
private function addFavorite($userId, $targetId, $targetType) {
$sql = "INSERT INTO favorites (user_id, target_id, target_type)
VALUES (:user_id, :target_id, :target_type)";
$stmt = $this->db->prepare($sql);
return $stmt->execute([
':user_id' => $userId,
':target_id' => $targetId,
':target_type' => $targetType
]);
}
// 取消收藏
private function removeFavorite($userId, $targetId, $targetType) {
$sql = "DELETE FROM favorites
WHERE user_id = :user_id
AND target_id = :target_id
AND target_type = :target_type";
$stmt = $this->db->prepare($sql);
return $stmt->execute([
':user_id' => $userId,
':target_id' => $targetId,
':target_type' => $targetType
]);
}
// 检查是否已收藏
public function checkFavorite($userId, $targetId, $targetType) {
$sql = "SELECT id FROM favorites
WHERE user_id = :user_id
AND target_id = :target_id
AND target_type = :target_type";
$stmt = $this->db->prepare($sql);
$stmt->execute([
':user_id' => $userId,
':target_id' => $targetId,
':target_type' => $targetType
]);
return $stmt->fetch() ? true : false;
}
// 获取收藏数
public function getFavoriteCount($targetId, $targetType) {
$sql = "SELECT COUNT(*) as count FROM favorites
WHERE target_id = :target_id
AND target_type = :target_type";
$stmt = $this->db->prepare($sql);
$stmt->execute([
':target_id' => $targetId,
':target_type' => $targetType
]);
$result = $stmt->fetch();
return $result['count'];
}
// 获取用户收藏列表
public function getUserFavorites($userId, $targetType, $page = 1, $limit = 10) {
$offset = ($page - 1) * $limit;
$sql = "SELECT f.*, a.title, a.created_at
FROM favorites f
JOIN articles a ON f.target_id = a.id
WHERE f.user_id = :user_id
AND f.target_type = :target_type
ORDER BY f.created_at DESC
LIMIT :limit OFFSET :offset";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':user_id', $userId, PDO::PARAM_INT);
$stmt->bindParam(':target_type', $targetType, PDO::PARAM_STR);
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll();
}
}
控制器层实现
<?php
class ActionController {
private $likeService;
private $favoriteService;
private $auth; // 用户认证服务
public function __construct() {
$db = new PDO("mysql:host=localhost;dbname=test", "root", "");
$this->likeService = new LikeService($db);
$this->favoriteService = new FavoriteService($db);
$this->auth = new AuthService();
}
/**
* AJAX处理点赞请求
*/
public function handleLike() {
// 检查用户登录
$user = $this->auth->getCurrentUser();
if (!$user) {
return json_encode(['success' => false, 'message' => '请先登录']);
}
// 验证输入
$targetId = intval($_POST['target_id']);
$targetType = in_array($_POST['target_type'], ['article', 'video'])
? $_POST['target_type'] : 'article';
if (!$targetId) {
return json_encode(['success' => false, 'message' => '参数错误']);
}
// 执行点赞操作
$result = $this->likeService->toggleLike($user['id'], $targetId, $targetType);
return json_encode($result);
}
/**
* AJAX处理收藏请求
*/
public function handleFavorite() {
$user = $this->auth->getCurrentUser();
if (!$user) {
return json_encode(['success' => false, 'message' => '请先登录']);
}
$targetId = intval($_POST['target_id']);
$targetType = in_array($_POST['target_type'], ['article', 'video'])
? $_POST['target_type'] : 'article';
if (!$targetId) {
return json_encode(['success' => false, 'message' => '参数错误']);
}
$result = $this->favoriteService->toggleFavorite($user['id'], $targetId, $targetType);
return json_encode($result);
}
}
前端实现
HTML结构
<!-- 点赞按钮 -->
<div class="action-bar">
<button class="btn-like" data-id="123" data-type="article">
<i class="icon-like"></i>
<span class="count">99</span>
</button>
<!-- 收藏按钮 -->
<button class="btn-favorite" data-id="123" data-type="article">
<i class="icon-star"></i>
<span class="count">56</span>
</button>
</div>
JavaScript交互
// 封装AJAX请求
class ActionHandler {
constructor() {
this.initEvents();
}
initEvents() {
// 点赞事件
document.querySelectorAll('.btn-like').forEach(btn => {
btn.addEventListener('click', (e) => this.handleLike(e));
});
// 收藏事件
document.querySelectorAll('.btn-favorite').forEach(btn => {
btn.addEventListener('click', (e) => this.handleFavorite(e));
});
}
async handleLike(event) {
const btn = event.currentTarget;
const targetId = btn.dataset.id;
const targetType = btn.dataset.type;
// 防重复点击
if (btn.classList.contains('loading')) return;
btn.classList.add('loading');
try {
const formData = new FormData();
formData.append('target_id', targetId);
formData.append('target_type', targetType);
const response = await fetch('/api/like', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.success) {
// 更新UI
btn.classList.toggle('active');
btn.querySelector('.count').textContent = result.count;
// 动画效果
btn.querySelector('i').classList.add('animated');
setTimeout(() => {
btn.querySelector('i').classList.remove('animated');
}, 500);
} else {
alert(result.message || '操作失败');
}
} catch (error) {
console.error('Error:', error);
alert('网络错误,请稍后重试');
} finally {
btn.classList.remove('loading');
}
}
async handleFavorite(event) {
// 类似点赞逻辑
// ...
}
}
// 初始化
new ActionHandler();
性能优化建议
使用Redis缓存
class LikeServiceWithCache extends LikeService {
private $redis;
public function __construct($db, $redis) {
parent::__construct($db);
$this->redis = $redis;
}
public function getLikeCountWithCache($targetId, $targetType) {
$cacheKey = "likes:{$targetType}:{$targetId}";
// 尝试从缓存获取
$count = $this->redis->get($cacheKey);
if ($count === false) {
// 缓存未命中,从数据库获取
$count = parent::getLikeCount($targetId, $targetType);
$this->redis->setex($cacheKey, 3600, $count); // 缓存1小时
}
return $count;
}
}
批量查询优化
// 批量获取多个内容的点赞状态
public function getBatchLikeStatus($userId, $targetIds, $targetType) {
if (empty($targetIds)) return [];
$placeholders = implode(',', array_fill(0, count($targetIds), '?'));
$sql = "SELECT target_id FROM likes
WHERE user_id = ?
AND target_id IN ($placeholders)
AND target_type = ?";
$params = array_merge([$userId], $targetIds, [$targetType]);
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
$likedIds = $stmt->fetchAll(PDO::FETCH_COLUMN);
return array_fill_keys($likedIds, true);
}
安全注意事项
// 1. 防止SQL注入(使用预处理语句)
// 2. 验证用户权限
// 3. 防止重复操作(数据库唯一索引)
// 4. 限制操作频率
class RateLimiter {
private $redis;
private $maxRequests = 10; // 每分钟最多10次
private $timeWindow = 60; // 60秒
public function isAllowed($userId, $action) {
$key = "rate_limit:{$action}:{$userId}";
$current = $this->redis->get($key) ?: 0;
if ($current >= $this->maxRequests) {
return false;
}
$this->redis->multi();
$this->redis->incr($key);
$this->redis->expire($key, $this->timeWindow);
$this->redis->exec();
return true;
}
}
这个方案完整实现了收藏和点赞功能,包含了数据库设计、后端逻辑、前端交互以及性能优化等核心要素,你可以根据实际需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播