美文网首页PHP经验分享LaravelLaravel开发实践
Lumen业务篇:接口开发之代码分层(模块化结构),实例演示!

Lumen业务篇:接口开发之代码分层(模块化结构),实例演示!

作者: 我爱余倩 | 来源:发表于2019-04-29 21:45 被阅读23次

    一、前言

    1. 最近赶在5月1的上线大关,一直没有来得及更新。
    2. 前段时间,有读者建议我出一个 Lumen 项目示例,目前只实现了部分功能,后面有时间慢慢补全逻辑和完善注释。
    3. 同样也要借此机会,介绍一下 Module(模块化) 的项目结构,针对本文,具体的目录层次如下:
    /app
    ....../Base            # 定义基础类
    ....../Common          # 定义常量、全局函数
    ....../Middlewares
    ....../Modules
    ....../....../Job      # Job模块
    ....../....../Task     # Task模块
    ....../Providers
    ............others............
    /bootstrap
    /config                # 配置文件目录
    /database
    /routes
    ......others.......
    

    二、说明

    1. 还没有书写注释和完整的业务逻辑,所以新手可能理解难度较高。
    2. 本文的项目背景是 定时任务系统,基于 Lumen 开箱即用的 队列 实现。
    3. 项目开发环境使用最新的 Lumen 5.8.x 以及 PHP 7.2.16 版本。
    4. 快速上手,可以使用本人至今 'Windows' 下正常开发使用的 整合压缩包

    三、开始

    1. 确定本地已经安装了 Composer 环境。

    2. 代码仓库 拉下最新的代码,覆盖上述创建的项目文件。

    3. 注意,git clone 完成后要执行 composer install 安装依赖。

    4. 熟悉 Laravel 的读者应该会习惯使用 php artisan serve 指令快速启动服务,鉴于 Lumen 开箱地精简掉了许多 Artisan 指令,因此本人特意从 Laravel 中提取了 'ServeCommand.php' 作为 Lumen 项目的扩展,感兴趣的读者可以查看这个 packagist,当然,本文的项目已经默认包含了本扩展。

    5. 目前已经实现的功能如下:

    添加定时任务 查询定时任务 定时任务列表
    {{base_url}}/api/task/add {{base_url}}/api/task/seek/{task_uuid} {{base_url}}/api/task/all

    5.1. 添加定时任务接口

    HTTP/1.1 200 OK. POST {{base_url}}/api/task/add
    
    @请求模板: 
    {
       "callback_url": "http://127.0.0.1:8001",
       "callback_header": {
           "Content-Type": "application/json"
       },
       "callback_time": "2019-4-22 16:21:51",
       "task_title": "test task",
       "callback_body": {
           "course_id": 1,
           "lesson_id": 25
       }
    }
    @成功响应: 
    {
       "status_code": 200,
       "data": {
           "task_uuid": "54ddf0cceecac4b3349c3f3bffab1f8e",
           "status": "待执行",
           "task_title": "test task",
           "created_at": "2019-04-30 11:18:20",
           "first_execute": "",
           "success_execute": "",
           "failure_execute": ""
       }
    }
    

    5.2. 查询定时任务接口

    HTTP/1.1 200 OK. POST {{base_url}}/api/task/seed/{task_uuid}
    task_uuid = 54ddf0cceecac4b3349c3f3bffab1f8e
    
    @成功响应: 
    {
       "status_code": 200,
       "data": {
           "task_uuid": "54ddf0cceecac4b3349c3f3bffab1f8e",
           "status": "待执行",
           "task_title": "test task",
           "created_at": "2019-04-30 11:18:20",
           "first_execute": "",
           "success_execute": "",
           "failure_execute": ""
       }
    }
    

    5.1. 定时任务列表接口

    HTTP/1.1 200 OK. POST {{base_url}}/api/task/all
    
    @成功响应: 
    {
       "status_code": 200,
       "data": {
           "pagination": {
               "total": 1,
               "count": 1,
               "per_page": 10,
               "current_page": 1,
               "last_page": 1
           },
           "data": [
               {
                   "task_uuid": "de70b9b9bf5fb13ff6e96776839ceb15",
                   "status": "待执行",
                   "task_title": "test task",
                   "created_at": "2019-04-30 10:54:27",
                   "first_execute": "",
                   "success_execute": "",
                   "failure_execute": ""
               }
           ]
       }
    }
    
    1. 贴出核心 'TaskJob.php' 下的代码,前往 代码仓库,可以查看完整代码文件。
    <?php
    
    namespace App\Modules\Task;
    
    use App\Jobs\BaseJob;
    use App\Modules\Job\JobModel;
    use Illuminate\Support\Arr;
    use Illuminate\Support\Facades\Log;
    
    class TaskJob extends BaseJob
    {
        const MAX_ATTEMPTS = 5;
    
        /**
         * @var array
         */
        private $taskData;
    
        /**
         * @var TaskModel
         */
        private $taskInstance;
    
        /**
         * @var JobModel
         */
        private $jobInstance;
    
        /**
         * @var mixed
         */
        private $response;
    
        public function __construct(array $taskData)
        {
            $this->taskData = $taskData;
            $this->setTaskInstance();
            $this->setJobInstance();
        }
    
        public function handle()
        {
            $this->posting() ? $this->successEnding() : $this->errorEnding();
            $this->delete();
            return false;
        }
    
        private function setTaskInstance()
        {
            $taskContent = json_encode(Arr::except($this->taskData, ['task_title']));
            $filled = ['task_uuid' => md5($taskContent . time()), 'task_content' => $taskContent, 'task_title' => $this->taskData['task_title']];
            $this->taskInstance = (new TaskModel)->createOne($filled);
        }
    
        private function setJobInstance()
        {
            $this->jobInstance = (new JobModel)->createOne();
        }
    
        public function getJobInstance()
        {
            return $this->jobInstance;
        }
    
        public function getTaskInstance()
        {
            return $this->taskInstance;
        }
    
        private function makeHeaders()
        {
            $temp = Arr::pull($this->taskData, 'callback_header');
            $return = [];
            foreach ($temp as $key => $value) {
                $return[] = $key . ':' . $value;
            }
            return $return;
        }
    
        private function posting()
        {
            $url = Arr::pull($this->taskData, 'callback_url');
            $body = Arr::pull($this->taskData, 'callback_body');
            $headers = $this->makeHeaders();
    
            $this->getTaskInstance()->activeOne();
            $this->getJobInstance()->attempts($this->attempts());
    
            // begin:
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_HEADER, 0);
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
            $this->response = curl_exec($curl);
            $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
            curl_close($curl);
            // end:
    
            return ($httpCode == 200);
        }
    
        /**
         * @author AdamTyn
         * @description 处理成功结果
         *
         * @return void
         */
        private function successEnding()
        {
            Log::alert(PHP_EOL . PHP_EOL . PHP_EOL . '<Success in 定时系统回调> at ' . date('Y-m-d H:i:s') . PHP_EOL . '<具体响应内容:> ' . 'detail=> ' . PHP_EOL . $this->response . PHP_EOL . PHP_EOL . PHP_EOL);
    
            $this->getTaskInstance()->successOne($this->response);
        }
    
        /**
         * @author AdamTyn
         * @description 处理失败结果
         *
         * @return void
         */
        private function errorEnding()
        {
            $log = PHP_EOL . PHP_EOL . PHP_EOL . '<Error in 定时系统回调> at ' . date('Y-m-d H:i:s') . PHP_EOL . '<具体错误内容:> ' . 'detail=> ' . PHP_EOL . $this->response . PHP_EOL . PHP_EOL . PHP_EOL;
            Log::error($log);
    
            if ($this->attempts() == self::MAX_ATTEMPTS) {
                $this->getTaskInstance()->failureOne($this->response);
            } else {
                $this->release(mt_rand(5, 20));// 失败的定时任务,会推迟随机秒数后再执行
            }
        }
    }
    
    

    四、结语

    1. 本教程面向新手,更多教程会在日后给出。
    2. 随着系统升级,软件更新,以后的配置可能有所变化,在下会第一时间测试并且更新教程;
    3. 欢迎联系在下,讨论建议都可以,之后会发布其它的教程。
    4. 后面紧锣密鼓地将会推出 Laravel业务篇 系列的教程,敬请期待。

    相关文章

      网友评论

        本文标题:Lumen业务篇:接口开发之代码分层(模块化结构),实例演示!

        本文链接:https://www.haomeiwen.com/subject/hhtpnqtx.html