为适应2022年新解决方案场景开发,考虑到团队实际情况,将使用Laravel后端开发框架。

框架使用核心扩展:

  • 主框架:Laravel 8.*
  • 主接口扩展:dingo/api 3.*
  • 授权校验:tymon/jwt-auth JWT
  • id加密码处理:vinkla/hashids
  • Mqtt客户端:workman/mqtt 、Mosquitto-php(C扩展)

服务:Nginx、Redis、Mqtt服务(EMQX,客户端18083)、Supervisor

Laravel 开发规范

Laravel的路由将全由 Dingo/api 接管,所以环境部署后最好是生成api的路由缓存,开发环境中不用作何缓存(路由、配置等),同时建议开发人员统一开发环境使用 Homestead,使用Deployer构建自动化部署。

核心模块开发

项目结构

引入单一动作类开发方式,即
新框架开发规范 - 图1
控制器,只接收请求和响应请求,所有逻辑处理都在单一类里。
比如一个用户信息接口请求案例如下:

  1. 路由:xx/auth/user_info
  2. 控制器:app/Http/Controllers/Api/AuthController.php ```go <?php namespace App\Http\Controllers\Api; //用户信息单一类 use App\Actions\Auth\UserInfo; …

//方法 public function info(Request $request, UserInfo $action) { … $response = $action->handle($xxx);

  1. return $this->response->array(formats('成功', $response));

}

  1. 3. 单一类:app/Actions/Auth/UserInfo.php
  2. ```go
  3. <?php
  4. namespace App\Actions\Auth;
  5. /**
  6. * 单一类只有一个方法handle,主要处理逻辑
  7. */
  8. ...
  9. class SMSCode
  10. {
  11. public function handle($)
  12. {
  13. //表单校验
  14. //数据模型
  15. //服务类
  16. ....

路由

统一在 routes/api.php 文件下,必须按照模块分组路由,如:

  1. <?php
  2. //定义基于 Dingo 路由器的 API 路由
  3. $api = app(\Dingo\Api\Routing\Router::class);
  4. //定义 API 的版本分组,从而支持为多版本API接口,创建同样的路由以便后续回滚
  5. $api->version('v1', ['namespace' => 'App\Http\Controllers\Api', 'domain' => Config('app.api_domain')], function ($api) {
  6. //公用路由
  7. $api->group(['prefix' => 'pub'], function ($api) {
  8. //$api->post('/upload', 'CommonalityController@upload'); //文件上传
  9. });
  10. //企业设置
  11. $api->group(['prefix' => 'setting','middleware' => 'jwtauth.check:user'], function ($api) {
  12. $api->post('/info', 'Setting\EnterpriseController@info'); //用户信息
  13. });
  14. });

企业设置就属于一个基础模块,相关路由写进这个模块。
暴露出来的地址必须全部小写,组合词必须下划线分开,对应的控制器方法遵循驼峰式写法。如:user_info对应方法为userInfo。

独立模块化开发

一个模块为一个解决方案场景,统一在modules结构里,是一个完整的应用且依赖于基础模块。
如一个排队叫号解决方案:
image.png
按laravel扩展包方式开发,自动加载模式,需要在根项目composer.json里,通过PSR-4方式,执行composer du

  1. ...
  2. "autoload": {
  3. "psr-4": {
  4. ...
  5. "Modules\\": "modules/"
  6. },
  7. },
  8. ...

deployer构建自动化部署[项目发布]

1.本地开发机无密登录服务器

在开发机生成 deployer 专用密钥,然后拷贝公钥到服务器

  1. ssh-keygen -t rsa -b 4096 -f ~/.ssh/deployerkey
  2. //拷贝公钥到服务器
  3. ssh-copy-id -i ~/.ssh/deployerkey.pub root@10.10.20.200
  4. //在开发机上以 root 用户免密码登录到服务器
  5. ssh root@10.10.20.200 -i ~/.ssh/deployerkey

服务器 /root/.ssh/authorized_keys 文件就会有开发机deployerkey文件里公钥内容,这样就实现免密登录。

2.本地开发机配置deployer

  1. //全局安装deployer
  2. composer global require deployer/deployer -vvv
  3. //查看版本
  4. dep --version
  5. //如果提示 dep 命令不存在,将 composer 的 bin 目录
  6. //即 ~/.composer/vendor/bin/,加到你的 PATH 环境变量里面
  7. //家目录下 .bash_profile(或.profile)文件
  8. vim ~/.bash_profile
  9. //添加到文件中
  10. export PATH=/usr/local/bin:/Users/maclechan/.composer/vendor/bin:$PATH
  11. //让其生效
  12. source .bash_profile
  13. //查看环境变量
  14. echo $PATH
  15. //有出现下面即添加成功
  16. //Users/maclechan/.composer/vendor/bin
  17. //重新打开终端窗口
  18. dep --version

3.deployer的使用

在开发机的项目目录中

  1. //Deployer初始化,注意在deploy.php加到.gitignore里
  2. dep init
  3. <?php
  4. namespace Deployer;
  5. /**
  6. * 部署到测试
  7. * dep deploy dev -vvv
  8. *
  9. * 部署到正式
  10. * dep deploy prod -vvv
  11. */
  12. require 'recipe/laravel.php';
  13. // Project name
  14. set('application', '芮廷出品');
  15. // Project repository
  16. set('repository', 'http://101.69.231.68:8889/ITC_FRAME/API/CORE.git');
  17. // [Optional] Allocate tty for git clone. Default value is false.
  18. set('git_tty', true);
  19. // 保存最近五次部署,这样的话回滚最多也只能回滚到前 3 个版本
  20. set('keep_releases', 3);
  21. //出现权限相关的问题,也可将此项设置为 true 后尝试
  22. set('writable_use_sudo', true);
  23. //set('cleanup_use_sudo', true);
  24. // Shared files/dirs between deploys
  25. add('shared_files', []);
  26. add('shared_dirs', ['public/uploads','config','bootstrap/cache','storage','vendor']);
  27. // Writable dirs by web server
  28. add('writable_dirs', []);
  29. // 生产用的主机
  30. host('10.10.20.200')
  31. ->stage('prod')
  32. ->user('root')
  33. ->port(22)
  34. ->set('branch', 'master') // 最新的主分支部署到生产机
  35. ->set('deploy_path', '/var/www/core') //服务器上项目地址
  36. ->identityFile('~/.ssh/deployerkey') //公钥的位置
  37. ->forwardAgent(true)
  38. ->multiplexing(true);
  39. //->set('http_user', 'www') // 这个与 nginx 里的配置一致
  40. //->addSshOption('UserKnownHostsFile', '/dev/null')
  41. //->addSshOption('StrictHostKeyChecking', 'no');
  42. // 自定义任务:重置 opcache 缓存
  43. task('opcache_reset', function () {
  44. run('{{bin/php}} -r \'opcache_reset();\'');
  45. });
  46. // 自定义任务:重启 php-fpm 服务
  47. task('php-fpm:reload', function () {
  48. run('sudo service php7.4-fpm reload');
  49. });
  50. // 自定义任务:supervisor reload
  51. /*
  52. task('supervisor:reload', function () {
  53. run('sudo supervisorctl reload');
  54. });
  55. */
  56. // 自定义任务:使用dingo路由
  57. task('route:clear', function () {
  58. run('php /var/www/core/current/artisan route:clear');
  59. });
  60. //执行自定义任务,注意时间点是 current 已经成功链向新部署的目录之后
  61. after('deploy:symlink', 'route:clear');
  62. after('deploy:symlink', 'php-fpm:reload'); // 执行自定义任务,注意时间点是 current 已经成功链向新部署的目录之后
  63. after('deploy:symlink', 'opcache_reset'); // 部署成功后重置 opcache 缓存
  64. //after('deploy:symlink', 'supervisor:reload');

代码提交到仓库后,执行 dep deploy prod -vvv,代码就发布到服务器了。