免费资源下载
作者:技术架构师 | 发布日期:2023年10月
一、项目架构设计与技术选型
在微服务架构盛行的今天,高性能API服务成为系统间通信的核心。本教程将基于ThinkPHP 6.0,构建一个支持多租户的内容管理系统API服务,重点解决以下技术难点:
- 多态关联模型在复杂业务场景下的应用
- JWT无状态认证与权限控制
- API版本控制策略实现
- 高性能查询优化与缓存策略
二、环境配置与项目初始化
# 创建项目
composer create-project topthink/think tp6-api-project
# 安装扩展包
composer require firebase/php-jwt
composer require topthink/think-multi-app
# 配置多应用模式
# config/app.php中设置'auto_multi_app' => true
三、多态关联模型实战:评论系统设计
传统评论系统通常只能关联单一模型,而多态关联允许评论同时关联文章、视频、商品等多种模型。
3.1 数据库设计
CREATE TABLE `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` text NOT NULL COMMENT '评论内容',
`commentable_id` int(11) NOT NULL COMMENT '关联目标ID',
`commentable_type` varchar(100) NOT NULL COMMENT '关联模型类名',
`user_id` int(11) NOT NULL,
`created_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_commentable` (`commentable_type`,`commentable_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 模型定义
// appcommonmodelComment.php
namespace appcommonmodel;
use thinkModel;
class Comment extends Model
{
// 定义多态关联
public function commentable()
{
return $this->morphTo();
}
// 关联用户
public function user()
{
return $this->belongsTo(User::class);
}
}
// appcommonmodelArticle.php
class Article extends Model
{
// 定义反向多态关联
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
// appcommonmodelVideo.php
class Video extends Model
{
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
3.3 控制器中的使用
// appapicontrollerCommentController.php
class CommentController
{
// 添加评论(支持多种模型)
public function add(Request $request)
{
$data = $request->only(['content', 'target_id', 'target_type']);
// 验证目标类型合法性
$allowTypes = ['article', 'video', 'product'];
if (!in_array($data['target_type'], $allowTypes)) {
return json(['code' => 400, 'msg' => '不支持的评论目标类型']);
}
// 动态获取模型类名
$modelClass = 'app\common\model\' . ucfirst($data['target_type']);
// 检查目标是否存在
$target = $modelClass::find($data['target_id']);
if (!$target) {
return json(['code' => 404, 'msg' => '评论目标不存在']);
}
// 创建评论
$comment = new Comment([
'content' => $data['content'],
'user_id' => $request->userId // JWT解析出的用户ID
]);
// 建立多态关联
$target->comments()->save($comment);
return json([
'code' => 200,
'msg' => '评论成功',
'data' => $comment->hidden(['user_id'])
]);
}
// 获取目标的评论列表(支持预加载用户信息)
public function list(Request $request)
{
$targetType = $request->param('target_type');
$targetId = $request->param('target_id');
$comments = Comment::with(['user' => function($query) {
$query->field('id,username,avatar');
}])
->where('commentable_type', $targetType)
->where('commentable_id', $targetId)
->order('created_at', 'desc')
->paginate(10);
return json([
'code' => 200,
'data' => $comments
]);
}
}
四、JWT认证中间件实现
// appapimiddlewareJwtAuth.php
namespace appapimiddleware;
use thinkfacadeConfig;
use FirebaseJWTJWT;
use FirebaseJWTKey;
class JwtAuth
{
public function handle($request, Closure $next)
{
$token = $request->header('Authorization');
if (!$token) {
return json(['code' => 401, 'msg' => 'Token不存在']);
}
try {
// 移除Bearer前缀
if (strpos($token, 'Bearer ') === 0) {
$token = substr($token, 7);
}
$config = Config::get('jwt');
$decoded = JWT::decode($token, new Key($config['key'], $config['alg']));
// 将用户信息存入请求对象
$request->userId = $decoded->uid;
$request->userInfo = (array)$decoded;
} catch (Exception $e) {
return json(['code' => 401, 'msg' => 'Token验证失败: ' . $e->getMessage()]);
}
return $next($request);
}
}
// config/jwt.php
return [
'key' => 'your-256-bit-secret-key-here', // 建议使用环境变量
'alg' => 'HS256',
'expire' => 7200, // 2小时过期
];
五、API版本控制策略
通过路由分组实现API版本控制,支持平滑升级:
// route/api.php
use thinkfacadeRoute;
// V1版本API
Route::group('v1', function() {
// 评论相关
Route::post('comment/add', 'v1.CommentController/add');
Route::get('comment/list', 'v1.CommentController/list');
// 文章相关
Route::resource('article', 'v1.ArticleController');
})->prefix('api/v1/')->middleware(['JwtAuth']);
// V2版本API(新增功能)
Route::group('v2', function() {
// 新增评论回复功能
Route::post('comment/reply', 'v2.CommentController/reply');
Route::get('comment/thread/:id', 'v2.CommentController/thread');
})->prefix('api/v2/')->middleware(['JwtAuth', 'ApiLogger']);
六、性能优化实践
6.1 查询优化
// 使用with预加载避免N+1查询问题
$articles = Article::with(['comments' => function($query) {
$query->with('user')->limit(5);
}, 'tags'])
->where('status', 1)
->cache('home_articles', 300) // 缓存5分钟
->select();
// 使用field限制查询字段
$users = User::field('id,username,avatar')
->whereIn('id', $userIds)
->select()
->column(null, 'id'); // 转为ID为键的数组
6.2 缓存策略
// appcommonserviceCacheService.php
class CacheService
{
// 获取带自动缓存的评论数
public static function getCommentCount($targetType, $targetId)
{
$cacheKey = "comment_count:{$targetType}:{$targetId}";
return cache()->remember($cacheKey, 600, function() use ($targetType, $targetId) {
return Comment::where('commentable_type', $targetType)
->where('commentable_id', $targetId)
->count();
});
}
// 批量获取评论数(减少缓存读取次数)
public static function getBatchCommentCounts($targetType, array $targetIds)
{
$result = [];
$uncachedIds = [];
foreach ($targetIds as $id) {
$cacheKey = "comment_count:{$targetType}:{$id}";
$cached = cache($cacheKey);
if ($cached !== null) {
$result[$id] = $cached;
} else {
$uncachedIds[] = $id;
$result[$id] = null;
}
}
if (!empty($uncachedIds)) {
$counts = Comment::where('commentable_type', $targetType)
->whereIn('commentable_id', $uncachedIds)
->group('commentable_id')
->column('COUNT(*) as count', 'commentable_id');
foreach ($uncachedIds as $id) {
$count = $counts[$id] ?? 0;
$result[$id] = $count;
cache("comment_count:{$targetType}:{$id}", $count, 600);
}
}
return $result;
}
}
七、完整案例:内容审核回调系统
结合多态关联和事件系统,实现内容审核回调:
// 定义审核状态变更事件
// appcommoneventContentReviewed.php
namespace appcommonevent;
class ContentReviewed
{
public $model;
public $modelId;
public $oldStatus;
public $newStatus;
public function __construct($model, $modelId, $oldStatus, $newStatus)
{
$this->model = $model;
$this->modelId = $modelId;
$this->oldStatus = $oldStatus;
$this->newStatus = $newStatus;
}
}
// 事件监听器
// appcommonlistenerReviewNotifier.php
class ReviewNotifier
{
public function handle(ContentReviewed $event)
{
// 根据模型类型执行不同的通知逻辑
switch ($event->model) {
case 'article':
$this->notifyArticleAuthor($event);
break;
case 'comment':
$this->notifyCommentAuthor($event);
break;
case 'video':
$this->notifyVideoUploader($event);
break;
}
// 记录审核日志
ReviewLog::create([
'target_type' => $event->model,
'target_id' => $event->modelId,
'old_status' => $event->oldStatus,
'new_status' => $event->newStatus,
'reviewer_id' => request()->userId,
'reviewed_at' => date('Y-m-d H:i:s')
]);
}
private function notifyArticleAuthor($event)
{
$article = Article::find($event->modelId);
if ($article && $article->user) {
// 发送站内信或邮件通知
Message::create([
'user_id' => $article->user_id,
'title' => '文章审核通知',
'content' => "您的文章《{$article->title}》审核状态已变更为:{$this->getStatusText($event->newStatus)}"
]);
}
}
}
// 在控制器中触发事件
public function review(Request $request)
{
$data = $request->only(['target_type', 'target_id', 'status']);
// 获取目标模型
$modelClass = 'app\common\model\' . ucfirst($data['target_type']);
$target = $modelClass::find($data['target_id']);
if (!$target) {
return json(['code' => 404, 'msg' => '目标不存在']);
}
$oldStatus = $target->status;
$target->status = $data['status'];
$target->save();
// 触发审核事件
event(new ContentReviewed(
$data['target_type'],
$data['target_id'],
$oldStatus,
$data['status']
));
return json(['code' => 200, 'msg' => '审核完成']);
}
八、部署与监控建议
- 环境配置:使用Docker容器化部署,配置OPcache和Redis扩展
- 性能监控:集成ThinkPHP的Trace调试,结合Prometheus监控API响应时间
- 日志管理:使用JSON格式结构化日志,便于ELK收集分析
- API文档:使用OpenAPI 3.0规范自动生成接口文档
- 压力测试:使用ab或wrk进行并发测试,优化数据库连接池配置

