杰瑞科技汇

ThinkPHP实战教程如何快速上手?

ThinkPHP 6.0 实战教程:从零开始构建一个博客系统

第一部分:准备工作与项目初始化

什么是 ThinkPHP?

ThinkPHP 是一个开源的、快速、简单的面向对象的轻量级 PHP 开发框架,它遵循 Apache2 开源协议发布,是为了简化企业级应用开发和 Web 应用开发而诞生的,ThinkPHP 使用简单的 MVC 架构,让开发更加清晰、高效。

ThinkPHP实战教程如何快速上手?-图1
(图片来源网络,侵删)

环境要求

在开始之前,请确保你的开发环境满足以下要求:

  • PHP 版本: PHP 7.2.5 或更高版本 (推荐 PHP 8.0+)。
  • Composer: PHP 的依赖管理工具,用于安装 ThinkPHP 框架和扩展。
  • Web 服务器: Apache 2.4+ 或 Nginx 1.8+。
  • 数据库: MySQL 5.7+ 或 MariaDB 10.2+。
  • PHP 扩展: pdo, pdo_mysql, mbstring, fileinfo, openssl 等。

安装 ThinkPHP

ThinkPHP 官方推荐使用 Composer 来创建项目,打开你的终端(命令行工具),执行以下命令:

# 创建一个名为 myblog 的项目,并选择最新稳定版
composer create-project topthink/think myblog

这个命令会下载 ThinkPHP 框架及其所有依赖,并创建一个名为 myblog 的项目目录。

项目结构解析

安装完成后,进入 myblog 目录,你会看到以下主要文件夹:

ThinkPHP实战教程如何快速上手?-图2
(图片来源网络,侵删)
  • app/: 应用目录,我们所有的业务逻辑代码都将写在这里。
    • controller/: 控制器目录,处理用户请求。
    • model/: 模型目录,与数据库交互。
    • view/: 视图目录,负责页面展示。
  • config/: 配置目录,存放各种配置文件(数据库、路由、缓存等)。
  • public/: Web 访问目录,这是你的 Web 服务器(如 Apache/Nginx)指向的根目录,所有外部请求都会先进入这个目录。
  • route/: 路由目录,定义 URL 和控制器方法的映射关系。
  • vendor/: Composer 依赖目录,存放 ThinkPHP 框架和第三方库。

第二部分:配置与数据库设计

配置数据库连接

我们需要修改配置文件来连接到我们的数据库。

  1. 打开 config/database.php 文件。
  2. 修改 connections 数组中的 mysql 配置项,填入你的数据库信息。
// config/database.php
return [
    // 默认使用的数据库连接配置
    'default'         => env('database.driver', 'mysql'),
    // 自定义时间查询规则
    'time_query_rule' => [],
    // 自动写入时间戳字段
    'auto_timestamp'  => true,
    // 时间字段取出后的默认时间格式
    'datetime_format' => 'Y-m-d H:i:s',
    // 数据库连接配置信息
    'connections'     => [
        'mysql' => [
            // 数据库类型
            'type'              => env('database.type', 'mysql'),
            // 服务器地址
            'hostname'          => env('database.hostname', '127.0.0.1'),
            // 数据库名
            'database'          => env('database.database', 'myblog'),
            // 用户名
            'username'          => env('database.username', 'root'),
            // 密码
            'password'          => env('database.password', 'your_password'),
            // 端口
            'hostport'          => env('database.hostport', '3306'),
            // 数据库连接参数
            'params'            => [],
            // 数据库编码默认采用utf8
            'charset'           => env('database.charset', 'utf8mb4'),
            // 数据库表前缀
            'prefix'            => env('database.prefix', ''),
            // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
            'deploy'            => 0,
            // 数据库读写是否分离 主从式有效
            'rw_separate'       => false,
            // 读写分离后 主服务器数量
            'master_num'        => 1,
            // 指定从服务器序号
            'slave_no'          => '',
            // 是否严格检查字段是否存在
            'fields_strict'     => true,
            // 是否需要断线重连
            'break_reconnect'   => false,
            // 监听SQL
            'trigger_sql'       => env('app_debug'),
            // 开启字段缓存
            'fields_cache'      => false,
        ],
    ],
];

提示: ThinkPHP 支持使用 .env 文件来管理环境变量,更加安全,你可以在项目根目录创建 .env 文件,将上述配置信息写入其中。

创建数据库和表

在你的 MySQL 中,创建一个名为 myblog 的数据库,我们设计博客系统需要的两张表:article(文章表)和 category(分类表)。

-- 创建分类表
CREATE TABLE `category` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '分类ID',
  `name` varchar(50) NOT NULL COMMENT '分类名称',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章分类';
-- 创建文章表
CREATE TABLE `article` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '文章ID', varchar(255) NOT NULL COMMENT '文章标题',
  `content` text NOT NULL COMMENT '文章内容',
  `category_id` int(11) NOT NULL COMMENT '分类ID',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_category_id` (`category_id`),
  CONSTRAINT `fk_article_category` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章';

第三部分:构建 MVC

创建控制器

控制器是用户请求的入口,我们将创建一个 Index 控制器来处理首页和文章列表,一个 Article 控制器来处理文章详情。

ThinkPHP实战教程如何快速上手?-图3
(图片来源网络,侵删)

app/controller/ 目录下创建 Index.phpArticle.php

app/controller/Index.php (首页控制器)

<?php
declare (strict_types = 1);
namespace app\controller;
use app\BaseController;
use app\model\Article as ArticleModel;
use think\facade\View;
class Index extends BaseController
{
    // 首页,显示文章列表
    public function index()
    {
        // 获取最新的10篇文章,并关联分类信息
        $articles = ArticleModel::with(['category'])
                                ->order('create_time', 'desc')
                                ->limit(10)
                                ->select();
        // 将数据传递给视图
        View::assign('articles', $articles);
        return View::fetch();
    }
}

app/controller/Article.php (文章控制器)

<?php
declare (strict_types = 1);
namespace app\controller;
use app\BaseController;
use app\model\Article as ArticleModel;
use think\facade\View;
use think\exception\ValidateException;
class Article extends BaseController
{
    // 显示文章详情
    public function detail($id)
    {
        // 根据ID查找文章,如果找不到则抛出404异常
        $article = ArticleModel::with(['category'])->find($id);
        if (!$article) {
            abort(404, '文章不存在');
        }
        View::assign('article', $article);
        return View::fetch();
    }
}

创建模型

模型负责与数据库交互,我们需要为 articlecategory 表创建对应的模型。

app/model/ 目录下创建 Article.phpCategory.php

app/model/Article.php (文章模型)

<?php
declare (strict_types = 1);
namespace app\model;
use think\Model;
class Article extends Model
{
    // 设置数据表名
    protected $name = 'article';
    // 设置字段信息
    protected $schema = [
        'id'          => 'int',
        'title'       => 'string',
        'content'     => 'string',
        'category_id' => 'int',
        'create_time' => 'datetime',
        'update_time' => 'datetime',
    ];
    // 自动时间戳
    protected $autoWriteTimestamp = true;
    // 定义与 Category 模型的关联关系 (一个文章属于一个分类)
    public function category()
    {
        return $this->belongsTo(Category::class);
    }
}

app/model/Category.php (分类模型)

<?php
declare (strict_types = 1);
namespace app\model;
use think\Model;
class Category extends Model
{
    protected $name = 'category';
    protected $schema = [
        'id'          => 'int',
        'name'        => 'string',
        'create_time' => 'datetime',
        'update_time' => 'datetime',
    ];
    protected $autoWriteTimestamp = true;
    // 定义与 Article 模型的关联关系 (一个分类有多个文章)
    public function articles()
    {
        return $this->hasMany(Article::class);
    }
}

创建视图

视图负责展示数据,我们需要创建对应的 HTML 模板文件。

view/ 目录下创建 index/index.htmlarticle/detail.html

view/index/index.html (首页模板)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">我的博客 - 首页</title>
    <style>
        body { font-family: sans-serif; line-height: 1.6; margin: 0; padding: 20px; }
        .container { max-width: 800px; margin: auto; }
        h1 { color: #333; }
        .article-list { list-style: none; padding: 0; }
        .article-item { border-bottom: 1px solid #eee; padding: 15px 0; }
        .article-item:last-child { border-bottom: none; }
        .article-title { font-size: 1.5em; margin-bottom: 5px; }
        .article-title a { text-decoration: none; color: #007bff; }
        .article-meta { color: #666; font-size: 0.9em; }
    </style>
</head>
<body>
    <div class="container">
        <h1>文章列表</h1>
        <ul class="article-list">
            {volist name="articles" id="article"}
            <li class="article-item">
                <h2 class="article-title">
                    <a href="{:url('article/detail', ['id' => $article.id])}">{$article.title}</a>
                </h2>
                <p class="article-meta">
                    分类: {$article.category.name} | 发布时间: {$article.create_time}
                </p>
                <p>
                    {mb_substr(strip_tags($article.content), 0, 100, 'UTF-8')}...
                </p>
            </li>
            {/volist}
        </ul>
    </div>
</body>
</html>

view/article/detail.html (文章详情模板)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">{$article.title} - 我的博客</title>
    <style>
        body { font-family: sans-serif; line-height: 1.6; margin: 0; padding: 20px; }
        .container { max-width: 800px; margin: auto; }
        h1 { color: #333; }
        .article-meta { color: #666; font-size: 0.9em; margin-bottom: 20px; }
        .article-content { white-space: pre-wrap; }
    </style>
</head>
<body>
    <div class="container">
        <h1>{$article.title}</h1>
        <p class="article-meta">
            分类: {$article.category.name} | 发布时间: {$article.create_time}
        </p>
        <div class="article-content">
            {$article.content}
        </div>
        <a href="{:url('index/index')}">返回首页</a>
    </div>
</body>
</html>

第四部分:配置路由与访问

配置路由

为了让 URL 更美观,我们需要配置路由,打开 route/app.php 文件,添加以下路由规则:

// route/app.php
// 首页路由,指向 Index 控制器的 index 方法
Route::get('/', 'Index/index');
// 文章详情路由,使用变量规则 {id}
// 访问格式如 /article/1
Route::get('article/:id', 'Article/detail')
     ->pattern(['id' => '\d+']); // 限制 id 必须为数字

配置 Web 服务器

Apache 配置

确保你的 public 目录是 Web 服务器的根目录,在 Apache 的配置文件中(通常是 httpd.conf 或虚拟主机配置文件),设置:

<VirtualHost *:80>
    DocumentRoot "/path/to/your/myblog/public"
    ServerName myblog.local
    <Directory "/path/to/your/myblog/public">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Nginx 配置

同样,将 public 目录作为根目录,在 Nginx 配置中添加:

server {
    listen 80;
    server_name myblog.local;
    root /path/to/your/myblog/public;
    index index.php index.html;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000; # 或者使用 unix sock
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

配置完成后,重启你的 Web 服务器。

访问网站

在浏览器中访问你配置的域名(http://myblog.local)。

  • 首页: 你应该能看到文章列表。
  • 文章详情: 点击文章标题,你应该能跳转到文章详情页面。

第五部分:进阶功能(后台管理)

一个完整的博客系统需要一个后台来管理文章和分类。

创建后台控制器

app/controller/ 目录下创建一个 admin 目录,并在其中创建控制器。

app/controller/admin/Article.php (后台文章管理)

<?php
declare (strict_types = 1);
namespace app\controller\admin;
use app\BaseController;
use app\model\Article as ArticleModel;
use think\facade\View;
use think\facade\Db;
class Article extends BaseController
{
    // 文章列表
    public function index()
    {
        $list = ArticleModel::with(['category'])->paginate(10);
        View::assign('list', $list);
        return View::fetch();
    }
    // 添加文章页面
    public function add()
    {
        // 获取所有分类
        View::assign('categories', \app\model\Category::select());
        return View::fetch();
    }
    // 保存新文章
    public function save()
    {
        $data = $this->request->post();
        try {
            ArticleModel::create($data);
            return json(['code' => 1, 'msg' => '添加成功']);
        } catch (\Exception $e) {
            return json(['code' => 0, 'msg' => '添加失败:' . $e->getMessage()]);
        }
    }
    // 编辑文章页面
    public function edit($id)
    {
        $article = ArticleModel::find($id);
        if (!$article) {
            abort(404);
        }
        View::assign('article', $article);
        View::assign('categories', \app\model\Category::select());
        return View::fetch();
    }
    // 更新文章
    public function update($id)
    {
        $data = $this->request->put();
        try {
            ArticleModel::update($data, ['id' => $id]);
            return json(['code' => 1, 'msg' => '更新成功']);
        } catch (\Exception $e) {
            return json(['code' => 0, 'msg' => '更新失败:' . $e->getMessage()]);
        }
    }
    // 删除文章
    public function delete($id)
    {
        try {
            ArticleModel::destroy($id);
            return json(['code' => 1, 'msg' => '删除成功']);
        } catch (\Exception $e) {
            return json(['code' => 0, 'msg' => '删除失败:' . $e->getMessage()]);
        }
    }
}

app/controller/admin/Category.php (后台分类管理)

<?php
declare (strict_types = 1);
namespace app\controller\admin;
use app\BaseController;
use app\model\Category as CategoryModel;
use think\facade\View;
class Category extends BaseController
{
    public function index()
    {
        $list = CategoryModel::select();
        View::assign('list', $list);
        return View::fetch();
    }
    public function add()
    {
        if ($this->request->isPost()) {
            $data = $this->request->post();
            try {
                CategoryModel::create($data);
                return json(['code' => 1, 'msg' => '添加成功']);
            } catch (\Exception $e) {
                return json(['code' => 0, 'msg' => '添加失败:' . $e->getMessage()]);
            }
        }
        return View::fetch();
    }
    public function edit($id)
    {
        $category = CategoryModel::find($id);
        if (!$category) {
            abort(404);
        }
        View::assign('category', $category);
        return View::fetch();
    }
    public function update($id)
    {
        $data = $this->request->put();
        try {
            CategoryModel::update($data, ['id' => $id]);
            return json(['code' => 1, 'msg' => '更新成功']);
        } catch (\Exception $e) {
            return json(['code' => 0, 'msg' => '更新失败:' . $e->getMessage()]);
        }
    }
    public function delete($id)
    {
        try {
            CategoryModel::destroy($id);
            return json(['code' => 1, 'msg' => '删除成功']);
        } catch (\Exception $e) {
            return json(['code' => 0, 'msg' => '删除失败:' . $e->getMessage()]);
        }
    }
}

创建后台视图

view/ 目录下创建 admin 目录,并添加对应的模板文件,这里只展示 article/index.html 作为示例。

view/admin/article/index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">后台 - 文章管理</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        table { width: 100%; border-collapse: collapse; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        a { text-decoration: none; color: #007bff; margin-right: 10px; }
    </style>
</head>
<body>
    <h1>文章管理</h1>
    <a href="{:url('admin/article/add')}">添加文章</a>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>标题</th>
                <th>分类</th>
                <th>创建时间</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {volist name="list" id="article"}
            <tr>
                <td>{$article.id}</td>
                <td>{$article.title}</td>
                <td>{$article.category.name}</td>
                <td>{$article.create_time}</td>
                <td>
                    <a href="{:url('admin/article/edit', ['id' => $article.id])}">编辑</a>
                    <a href="javascript:void(0)" onclick="del({$article.id})">删除</a>
                </td>
            </tr>
            {/volist}
        </tbody>
    </table>
    {$list|raw}
    <script>
    function del(id) {
        if (confirm('确定要删除吗?')) {
            fetch('{:url("admin/article/delete")}?id=' + id, {
                method: 'GET',
                headers: {
                    'X-Requested-With': 'XMLHttpRequest'
                }
            })
            .then(response => response.json())
            .then(data => {
                if (data.code === 1) {
                    alert('删除成功');
                    window.location.reload();
                } else {
                    alert(data.msg);
                }
            });
        }
    }
    </script>
</body>
</html>

配置后台路由

route/app.php 中添加后台路由,通常会给后台路由加上一个前缀,如 /admin

// route/app.php
// ... 前台路由 ...
// 后台路由组,添加 /admin 前缀
Route::group('admin', function () {
    Route::get('article', 'admin.Article/index');
    Route::get('article/add', 'admin.Article/add');
    Route::post('article/save', 'admin.Article/save');
    Route::get('article/edit/:id', 'admin.Article/edit');
    Route::put('article/update/:id', 'admin.Article/update');
    Route::delete('article/delete', 'admin.Article/delete'); // 或者用 GET
    Route::get('category', 'admin.Category/index');
    // ... 其他分类路由 ...
})->middleware(\app\http\middleware\AuthMiddleware::class); // 假设我们有一个认证中间件

第六部分:总结与进阶

至此,你已经使用 ThinkPHP 6.0 搭建了一个功能完整的前台展示和后台管理的博客系统。

回顾我们学到的东西:

  1. 项目初始化: 使用 Composer 快速创建项目。
  2. 配置: 配置数据库连接等核心设置。
  3. MVC 架构:
    • M (Model): 创建模型,定义数据表结构和关联关系。
    • V (View): 编写模板,使用 ThinkPHP 的模板引擎渲染数据。
    • C (Controller): 创建控制器,接收请求,调用模型,返回视图。
  4. 路由: 配置清晰的 URL 路由,实现请求的优雅分发。
  5. 数据库操作: 使用模型进行增、删、改、查,并学习关联查询。
  6. 后台开发: 扩展了后台管理功能,涉及更复杂的表单处理和 AJAX 交互。

后续可以学习和深入的方向:

  • 中间件: 实现用户登录认证、权限控制等,为后台路由添加一个登录检查中间件。
  • 验证器: 创建专门的验证器类,对表单数据进行更严谨的验证。
  • 数据库迁移: 使用数据库迁移工具来管理数据库结构的变更。
  • 缓存: 使用 ThinkPHP 的缓存功能来提升网站性能。
  • 命令行工具: 学习使用 think 命令行工具来自动化生成代码、执行任务等。
  • 部署: 学习如何将你的 ThinkPHP 项目部署到生产服务器(如使用 Docker)。

ThinkPHP 文档是学习的最佳资源,当你遇到问题时,一定要查阅 ThinkPHP 6.0 完全开发手册

希望这份实战教程对你有帮助!祝你编码愉快!

分享:
扫描分享到社交APP
上一篇
下一篇