Dcat Admin 自定义 Form 表单—将配置内容缓存到 Redis 并统一调用

上一篇主要讲系统配置 Form 表单如何自定义,以及配置的 Form 表单扩展的问题。虽然功能已经满足使用,但也有其弊端:

  1. 系统配置是存在数据库中,且配置内容改动次数较少,每次获取仍需要查库,在大量用到配置的场景下影响性能。
  2. 没有统一的获取配置数据的接口,后期维护麻烦。

针对以问题我们的对策是

  1. 将配置缓存起来,使用 Redis 缓存。(当然用文件缓存也是 ok 的,但 Redis 应用的场景更多!)
  2. 统一系统配置调用的接口。

首先看一下配置表的迁移文件和数据

  • 很简单,除了主键外,只剩下 name 和 value 两个有效字段。

    <?php
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    class CreateSystemConfigsTable extends Migration
    {
      public function up()
      {
          Schema::create('system_configs', function (Blueprint $table) {
              $table->id();
              $table->string('name');
              $table->text('value');
              $table->timestamps();
          });
      }
      public function down()
      {
          Schema::dropIfExists('system_configs');
      }
    }
  • 数据库表存入的记录(现在只有两行记录,不过可以通过扩展 Tab 栏增加系统配置,就能增加表记录行数)
    Dcat Admin 自定义 Form 表单—将配置内容缓存到 Redis 并统一调用

  • 看第一行 name = config_one 数据的 value 字段内容以及格式(json 格式)。
    Dcat Admin 自定义 Form 表单—将配置内容缓存到 Redis 并统一调用

然后是 Redis 的配置

  • .env 文件的配置
    REDIS_CLIENT=phpredis
    REDIS_HOST=127.0.0.1
    REDIS_PASSWORD=null
    REDIS_PORT=6379
  • databse.php 的配置
    'cache' => [
          'url' => env('REDIS_URL'),
          'host' => env('REDIS_HOST', '127.0.0.1'),
          'password' => env('REDIS_PASSWORD', null),
          'port' => env('REDIS_PORT', '6379'),
          'database' => env('REDIS_CACHE_DB', '1'),
    ],
  • redis 的调用方法
    # get 方法:
    Redis::connection('cache')->get($cacheKey);
    # set 方法:
    Redis::connection('cache')->set($cacheKey, json_encode($data));
    # del 方法:
    Redis::connection('cache')->del($cacheKey);

最后是系统配置的统一接口以及调用方法

  • 系统配置的统一接口

    <?php
    namespace App\Models;
    use Eloquent;
    use Illuminate\Database\Eloquent\Builder;
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Support\Carbon;
    use Exception;
    use Illuminate\Support\Arr;
    use Illuminate\Support\Facades\Redis;
    class SystemConfig extends Model
    {
      use HasFactory;
      const CACHE_KEY_PREFIX = 'System-Config';
      protected $table = 'system_configs';
      protected $fillable = ['name', 'value'];
    
      // 获取系统配置
      public static function get($name, $key = null, $default = null)
      {
          if (empty($name)) {
              throw new Exception('配置名为空,请联系管理员');
          }
    
          $cacheKey = self::CACHE_KEY_PREFIX;
          $jsonData = Redis::connection('cache')->get($cacheKey);
          $data = json_decode($jsonData, true);
    
          // 如果缓存没有数据
          if (empty($data) || !is_array($data) || !Arr::exists($data, $name)) {
              $data = [];
              $config = self::query()->get()->toArray();
              foreach ($config as $item) {
                  $data[$item['name']] = json_decode($item['value'], true);
              }
              Redis::connection('cache')->set($cacheKey, json_encode($data));
          }
    
          // 如果 name 不存在,直接返回 null
          if (!Arr::exists($data, $name)) {
              return null;
          }
    
          // 获取 name 对应的配置
          $value = Arr::get($data, $name, $default);
    
          // 如果 key 值不存在,直接返回 name 对应的配置
          if (!$key) {
              return $value;
          }
    
          // 如果 key 值存在,返回 name 对应配置中的 key 键对应的值
          return Arr::get(Arr::get($data, $name, $default), $key, $default);
      }
    }
  • 系统配置的调用示例:

    // 获取整条配置信息
    SystemConfig::get('config_one')// 获取整条配置信息中的一个配置项
    SystemConfig::get('config_one', 'email')// 获取整条配置信息中的一个配置项,如果没有返回默认值
    SystemConfig::get('config_one', 'email', 'mail.qq.com')

但是配置仍会改动,所以在必要时清除缓存

  • 一般系统配置没有删除操作,只有创建和更新,现在只针对更新删除缓存。我没有用模型监听事件,我采用的是模型事件的闭包,请参见 模型闭包的使用
      /**
       * 使用模型的闭包删除缓存
       */
      protected static function booted()
      {
          // 数据更新后 - 删除缓存
          static::updated(function ($config) {
              $cacheKey = self::CACHE_KEY_PREFIX;
              Redis::connection('cache')->del($cacheKey);
          });
      }
  • 这样一来,在模型数据更新的时候,缓存是被清理掉的。

结语

  • 好了,本节内容已经讲完,也不是很复杂,只用到了 Redis 的 String 数据结构,也没有什么高深的方法,简单的 getsetdel 方法就满足了使用。
  • 如果有更好的办法,欢迎在评论区讨论。
本作品采用《CC 协议》,转载必须注明作者和本文链接
Xiao Peng
laravel_peng
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 2

赞,我们也是这么搞的。提两个建议:

  1. dcat-admin 后台可以集成下 JSON Editor( github.com/josdejong/jsoneditor ),方便编辑 json 内容。 file
  2. 需要交给运营同学管理的配置用 json 编辑器就不太合适了,可以用 dcat-admin 的 JSON 表单( JSON表单《Dcat Admin 中文文档》 ),就能用表单的形式管理 json 数据了,更方便。
1年前 评论
laravel_peng (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
技术员 @ 修炼的漱石
文章
10
粉丝
15
喜欢
93
收藏
171
排名:683
访问:1.1 万
私信
所有博文
社区赞助商