用户文件多的话,例如头像,存储到CDN的时候也要考虑目录平均散列
比较常用是按日期,例如 /2020/02/
但是缺点也非常明显,分布不均
或者直接按userId取模,例如 userId % 1000 分1000个目录来存放,只要userId是连续的,文件就必然是平均分布到这1000个目录
可是,数量很大的时候,一级目录下每个目录的文件数量或者一级目录就会非常多。
那么可以按二级目录来存放

function buildPath($id, $l1num, $l2num)
{
    //(id %(二级目录数量*二级目录数量) / 二级目录数量 => 取整 一级目录
    //(id %(二级目录数量*二级目录数量)% 二级目录数量 => 二级目录
    $tmp = $id % ($l1num * $l2num);
    $l1 = floor($tmp / $l2num);
    $l2 = $tmp % $l2num;
    return ['l1' => $l1, 'l2' => $l2];
}

为了方便演示我把一级目录和二级目录数量设置得比较小的值
就算是

$l1num = 10;
$l2num = 100;
$fileNum = 1000000;

每个目录就1000个文件,这样足够了:)
测试

$l1num = 2; //一级目录数量
$l2num = 5; //二级目录数量
$fileNum = 1000000; //文件数量
$dir = [];
for($i = 0; $i < $l1num; $i++) {
    for ($j = 0; $j < $l2num; $j++) {
        $dir[$i][$j] = 0;
    }
}
for ($i = 1; $i <= $fileNum; $i++) {
    $rs = $this->buildPath($i, $l1num, $l2num);
    $dir[$rs['l1']][$rs['l2']]++;
}
print_r($dir);
Array
(
    [0] => Array
        (
            [0] => 100000
            [1] => 100000
            [2] => 100000
            [3] => 100000
            [4] => 100000
        )

    [1] => Array
        (
            [0] => 100000
            [1] => 100000
            [2] => 100000
            [3] => 100000
            [4] => 100000
        )

)

如果没有唯一id的话也可以使用文件md5后的hash截取部份字串来作来目录来存放,不过缺点就是目录数量就非常多,而且hash费cpu

最近用UNI-APP做项目
因为无论在小程序还是原生APP中,富文本对HTML的标签和样式支持是有限的,而且手机上也不需要像PC WEB端呈现的东西那么丰富,所以就有想法找一个简洁一点的编辑器。

Squire
http://neilj.github.io/Squire/
这本身并没有UI,虽然例子中看到最上面有功能按钮。一切都需要手动添加,当然也可以用例子中的squire ui 去改。
虽然灵活,不过费时
Squire.png

simditor
国产的,但没找到中文文档,呵呵
https://simditor.tower.im/
simditor.png

Trumbowyg
https://alex-d.github.io/Trumbowyg/
Trumbowyg.png

JQUERY NOTEBOOK
http://raphaelcruzeiro.github.io/jquery-notebook/
JQUERY NOTEBOOK.png

Quill
https://quilljs.com/
Quill.png

HandyEditor
http://he.catfish-cms.com/
HandyEditor.png

summernote
https://summernote.org/
summernote.png

Medium Editor
http://yabwe.github.io/medium-editor/
MediumEditor.png

Draft.js
Draft.js
Draft.js.png

Froala Editor
收费的
https://www.froala.com/
Forala Editor.png

基于 Laravel + Dingo api + JWT + laravel-admin 的基础项目
基于 rest api 完成了注册登录等接口,修改后直接使用

代码下载

启动新项目直接使用节省时间
前后台和接口独立域名

版本:

  • Laravel 5.7.13
  • Dingo api 2.0.0-alpha2
  • JWT rc.3
  • laravel-admin 1.6.7

以下所有例子都是使用 lvbegin.com 域名

接口地址: http://api.lvbegin.com
管理端:http://admin.lvbegin.com
门户:http://www.lvbegin.com

开发环境部署
$ composer install
$ cp .env.example .env

根据实际情况修改设置,特别是数据库和REDIS,还有下面两个

ADMIN_DOMAIN=[admin.lvbegin.com](http://admin.lvbegin.com)
API_DOMAIN=[api.lvbegin.com](http://api.lvbegin.com)

继续执行下面命令

$ php artisan key:generate
$ php artisan admin:install
$ php artisan vendor:publish --provider="Encore\Admin\AdminServiceProvider"
$ php artisan jwt:secret
$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
$ php artisan vendor:publish --provider="Dingo\Api\Provider\LaravelServiceProvider"

以上执行完毕,并且修改了虚拟主机配置后可以通过浏览器打开

http://admin.lvbegin.com 测试管理端,账号和密码: admin

http://api.lvbegin.com 接口需要通过 postman 测试

接口列表:
php artisan api:routes

用户验证接口

测试的时候记得先调用注册接口注册一个用户先

虚拟主机参考
server {
    listen 80;
    server_name api.lvbegin.com admin.lvbegin.com www.lvbegin.com;
    index index.php index.html index.htm;
    root /data/www/laravel-beginning/public; # default Laravel's entry point for all requests
    set_real_ip_from 10.104.17.235;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
    location / {
        # try to serve file directly, fallback to index.php
        try_files $uri /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_index index.php;
        fastcgi_pass 127.0.0.1:9000; # address of a fastCGI server
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        include fastcgi_params;
    }
}
截图

管理端

管理端

POSTMAN 调试

参考

找到的例子是一个Blog ,由于作者是法国人,而且文档是介绍在DOCKER下跑的,我在MAC上尝试掉进了不少坑
项目地址:
https://github.com/guillaumebriday/laravel-blog

安装好:composer & node & MySQL & PHP扩展 pcntl

$ git clone https://github.com/guillaumebriday/laravel-blog.git
$ cd laravel-blog
$ cp .env.example .env
$ composer install
$ php artisan key:generate
$ php artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider"
$ php artisan storage:link
$ php artisan migrate --seed
$ npm install
$ npm run dev
$ php artisan serve

我本地没有 Redis 要做以下修改

"message": "php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known [tcp://redis:6379]",

.env 中的

QUEUE_CONNECTION = redis

应该是写错了是下面这个才对,同时改为用 databases

QUEUE_DRIVER = databases
BROADCAST_DRIVER = pusher 

pusher 依赖 Redis 改成 log

BROADCAST_DRIVER = log

以上一路没出错的话就恭喜,可以访问 http://localhost:8000
账号密码:darthvader@deathstar.ds / 4nak1n

laravel-blog-a.png
laravel-blog-b.png
laravel-blog-c.png

注意:修改配置后必须清缓存

php artisan config:clear

并且重启http服务

php artisan serve