美文网首页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业务篇:接口开发之代码分层(模块化结构),实例演示!

    一、前言 最近赶在5月1的上线大关,一直没有来得及更新。 前段时间,有读者建议我出一个 Lumen 项目示例,目前...

  • Lumen业务篇:接口开发之标准化输出

    一、前言 应读者建议,将结合此前的 Lumen业务篇:接口开发之自定义表单验证 一文,完整地介绍一下本人所理解的 ...

  • Lumen实例讲解:第二部分

    一、前言 在前面的文章 Lumen实例讲解:第一部分 中,简单的介绍了 Lumen定时任务系统 的项目结构以及接口...

  • Android架构篇-1 项目组织架构

    模块化分层 1.结构清晰,各模块代码分离,符合高内聚低耦合,快速定位查找代码2.团队协作开发灵活,互不影响,各模块...

  • 封装库的接口强制实现

    我们实现分层代码的时候习惯使用一个小写的结构体去实现当前层次对外的接口,外层调用本层方法只能去调用实例化方法获得一...

  • 代码评判标准

    坏代码常见问题 命名不规范 类设计不合理 分层不明确 没有模块化概念 代码结构混乱 高度耦合 好代码的标准 可维护...

  • 前端模块化开发

    1 ES5的方式实现模块化开发 在工作区中创建两个js文件用于演示模块化开发的代码构建。 npm初始化 在01.j...

  • 实例演示vuex模块化和命名空间

    一个简单的实例演示vuex模块化和命名空间因为Vuex Store是全局注册的,不利于较大的项目,引入模块分离业务...

  • RDIFramework.NET框架基于Quartz.Net实现

    在上一篇Quartz.Net实现作业定时调度详解,我们通过实例代码详细讲解与演示了基于Quartz.NET开发的详...

  • vuex入门实例2

    vuex入门实例2 这章节我准备以requirejs模块化,讲解下如何快速上手vuex 源码地址 工程代码结构如下...

网友评论

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

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