Categories
php

php trait

php 实现多继承的组件

<?php
trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
}

class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
}

class ezcReflectionFunction extends ReflectionFunction {
    use ezcReflectionReturnInfo;
    /* ... */
}
?>

trait 定义组件

内部function定义方法接口 可以有实现的代码

在具体某个类 内部 通过关键字 use 引入trait 组件

当有相同名称方法trait 还优先调用 可通过parent:: 调用本来继承下来的方法

Categories
php

laravel-admin 添加文件导入

安装excel 包

composer require maatwebsite/excel

新增一个action操作

php artisan admin:action WeinpinhuiUser/ImportAction --name="导入"
<?php

namespace App\Admin\Actions\WeinpinhuiUser;

use App\Imports\WeipinhuiUser\ImportWeipinhuiUser;
use Encore\Admin\Actions\Action;
use Encore\Admin\Facades\Admin;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;


class ImportAction extends Action
{
    protected $selector = '.import-action';

    public function handle(Request $request)
    {
        // $request ...
        try{
            // $request ...
            $file = $request-> file('file');
            Excel::import(new ImportWeipinhuiUser(),$file);

            return $this->response()->success('数据导入成功')->refresh();
        }catch (\Exception $e){
            return $this->response()->error($e -> getMessage());
        }

    }

    public function html()
    {
        return <<<HTML
        <a class="btn btn-sm btn-default import-action">导入</a>
HTML;
    }

    public function form()
    {
        $this
            ->file('file', '请选择文件')
            ->options(['showPreview' => false,
                'allowedFileExtensions'=>['xlsx','xls'],
                'showUpload'=>false
            ]);
    }

    public function handleActionPromise()
    {
        $resolve = <<<SCRIPT
var actionResolverss = function (data) {
            $('.modal-footer').show()
            $('.tips').remove()
            var response = data[0];
            var target   = data[1];

            if (typeof response !== 'object') {
                return $.admin.swal({type: 'error', title: 'Oops!'});
            }

            var then = function (then) {
                if (then.action == 'refresh') {
                    $.admin.reload();
                }

                if (then.action == 'download') {
                    window.open(then.value, '_blank');
                }

                if (then.action == 'redirect') {
                    $.admin.redirect(then.value);
                }
            };

            if (typeof response.html === 'string') {
                target.html(response.html);
            }

            if (typeof response.swal === 'object') {
                $.admin.swal(response.swal);
            }

            if (typeof response.toastr === 'object') {
                $.admin.toastr[response.toastr.type](response.toastr.content, '', response.toastr.options);
            }

            if (response.then) {
              then(response.then);
            }
        };

        var actionCatcherss = function (request) {
            $('.modal-footer').show()
            $('.tips').remove()

            if (request && typeof request.responseJSON === 'object') {
                $.admin.toastr.error(request.responseJSON.message, '', {positionClass:"toast-bottom-center", timeOut: 10000}).css("width","500px")
            }
        };
SCRIPT;

        Admin::script($resolve);

        return <<<SCRIPT
         $('.modal-footer').hide()
         let html = `<div class='tips' style='color: blue;font-size: 15px;'>正在处理中<img src="data:image/gif;base64,R0lGODlhEAAQAPQAAP///1VVVfr6+np6eqysrFhYWG5ubuPj48TExGNjY6Ojo5iYmOzs7Lq6utjY2ISEhI6OjgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAFUCAgjmRpnqUwFGwhKoRgqq2YFMaRGjWA8AbZiIBbjQQ8AmmFUJEQhQGJhaKOrCksgEla+KIkYvC6SJKQOISoNSYdeIk1ayA8ExTyeR3F749CACH5BAkKAAAALAAAAAAQABAAAAVoICCKR9KMaCoaxeCoqEAkRX3AwMHWxQIIjJSAZWgUEgzBwCBAEQpMwIDwY1FHgwJCtOW2UDWYIDyqNVVkUbYr6CK+o2eUMKgWrqKhj0FrEM8jQQALPFA3MAc8CQSAMA5ZBjgqDQmHIyEAIfkECQoAAAAsAAAAABAAEAAABWAgII4j85Ao2hRIKgrEUBQJLaSHMe8zgQo6Q8sxS7RIhILhBkgumCTZsXkACBC+0cwF2GoLLoFXREDcDlkAojBICRaFLDCOQtQKjmsQSubtDFU/NXcDBHwkaw1cKQ8MiyEAIfkECQoAAAAsAAAAABAAEAAABVIgII5kaZ6AIJQCMRTFQKiDQx4GrBfGa4uCnAEhQuRgPwCBtwK+kCNFgjh6QlFYgGO7baJ2CxIioSDpwqNggWCGDVVGphly3BkOpXDrKfNm/4AhACH5BAkKAAAALAAAAAAQABAAAAVgICCOZGmeqEAMRTEQwskYbV0Yx7kYSIzQhtgoBxCKBDQCIOcoLBimRiFhSABYU5gIgW01pLUBYkRItAYAqrlhYiwKjiWAcDMWY8QjsCf4DewiBzQ2N1AmKlgvgCiMjSQhACH5BAkKAAAALAAAAAAQABAAAAVfICCOZGmeqEgUxUAIpkA0AMKyxkEiSZEIsJqhYAg+boUFSTAkiBiNHks3sg1ILAfBiS10gyqCg0UaFBCkwy3RYKiIYMAC+RAxiQgYsJdAjw5DN2gILzEEZgVcKYuMJiEAOwAAAAAAAAAAAA=="><\/div>`
         $('.modal-header').append(html)
process.then(actionResolverss).catch(actionCatcherss);
SCRIPT;
    }
}

在列表工具按钮添加导入action

 $grid->tools(function (Grid\Tools $tools) {
            $tools->append(new ImportAction());
        });

界面渲染已完成

现在处理数据保存

添加数据保存对象

php artisan make:import WeipinHuiUser/ImportWeipinhuiUser --model=App\Models\WeipinhuiUser
<?php

namespace App\Imports\Member;

use App\Models\MemberModel;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithStartRow;

class ImportWeinpinhuiUser implements ToModel,WithStartRow
{
    /**
    * @param array $row
    *
    * @return \Illuminate\Database\Eloquent\Model|null
    */
    public function model(array $row)
    {
        // 0代表的是第一列 以此类推
        // $row 是每一行的数据
        return new WeipinhuiUser([
             'employee_no' => $row[0],
            'name' => $row[1]
        ]);
    }


    /**
     * 从第几行开始处理数据 就是不处理标题
     * @return int
     */
    public function startRow(): int
    {
        return 2;
    }
}

注意:对应的model添加对应属性为可批量处理

class WeipinhuiUser extends Model
{
    use HasFactory;

    protected $fillable = ['employee_no', 'name'];
}
Categories
php

php 7.4

安装php7.4

add-apt-repository ppa:ondrej/php
apt-get update

Categories
nodejs

pm2 loadbalance

pm2 负载均衡

pm2 start app.js -i 4

以1个主进程监听端口 4个副进程 处理nodejs请求进程

pm2 start app.js -i max

以cpu核心的数量处理nodejs请求进程

pm2 其实是利用nodejs cluster模块运行

查看http://nodejs.cn/api/cluster.html

单个 Node.js 实例运行在单个线程中。 为了充分利用多核系统,有时需要启用一组 Node.js 进程去处理负载任务。

cluster 模块可以创建共享服务器端口的子进程。

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`主进程 ${process.pid} 正在运行`);

  // 衍生工作进程。
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 已退出`);
  });
} else {
  // 工作进程可以共享任何 TCP 连接。
  // 在本例子中,共享的是 HTTP 服务器。
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('你好世界\n');
  }).listen(8000);

  console.log(`工作进程 ${process.pid} 已启动`);
}
$ node server.js
主进程 3596 正在运行
工作进程 4324 已启动
工作进程 4520 已启动
工作进程 6056 已启动
工作进程 5644 已启动
Categories
java

maven runnable jar

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>robin.tcpip.gateway.Main</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

mainClass 指定 可执行主类

执行 mvn package 可打包

打包成runnable jar 后可直接运行 且保内包含所有依赖的jar包

Categories
java

zuul 1.x

zuul 网关应用分 1.X 版本 和 2.X 版本 两者相差很大

以下详细说明zuul 1.X 版本

在原始在zuul-core 包中 所有请求是通过 com.netflix.zuul.http.ZuulServlet 在 /zuul/* 下建立servlet 入口

然后在 zuulServlet的service方法中 执行 zuulRunner 去处理请求

然后不同请求路径下会使用 zuulRunner里面的不同的 filterProcessor 去处理

譬如 :

静态路由的地址 由配置文件配置的路由器处理

微服务路由地址 由ribbon的提供路由策略 RibbonRoutingFilter

所有的这些处理请求filter 其实是把请求重发到对应的地址

再把响应结果返回给网关(转发)

具体实现http请求的框架可以配置 okhttp httpClient 等

和 spring-boot 整合后

springmvc 用 org.springframework.cloud.netflix.zuul.web.ZuulController

包装了zuulServlet (servletWrapper)

还是通过springMVC去处理网关!!!

Categories
go

beego

go语言实现的 类似ruby on rails 的http 服务框架

需要通过 bee命令 生成controller view model 等

灵活度上会弱于普通的http框架 但架构上会优于其他框架

Categories
docker

docker remote api

docker 服务 提供给其他服务通讯的api

默认通讯socket 在本机的

unix://var/run/docker.sock

而且 必须有root权限才能访问该socket

当设置环境变量

DOCKER_OPTS="-H=unix:///var/run/docker.sock -H=0.0.0.0:4232"  

默认在本机4232 端口开启 docker 远程访问服务

该remote api socket 支持http协议

当执行 curl localhost:4232/version 返回服务器docker 版本信息

具体的docker remote api :

获取容器清单

GET /containers/json 

创建新容器

POST /containers/create

监控容器

GET /containers/(id)/json

获取容器内进程信息

GET /containers/(id)/top

获取容器日志信息

GET /containers/(id)/logs

导出容器内容

GET /containers/(id)/export

启动容器

POST /containers/(id)/start

停止容器

POST /containers/(id)/stop

重启容器

POST /containers/(id)/restart

终止容器

POST /containers/(id)/kill

创建镜像

POST /images/create

利用容器创建镜像

POST /commit

获取镜像清单

GET /images/json

导入指定的路径文件

POST /images/(name)/insert

删除镜像

DELETE /images/(name)

推送镜像到Registry

POST /images/(name)/push

Tag镜像

POST /images/(name)/tag

搜索镜像

GET /images/search

查看镜像历史

GET /images/(name)/history

构建镜像

POST /build
Categories
go

go 基本入门

标准输入流输出流

import "fmt"

func main() {
   fmt.Println("Hello, World!")
}

等同于

import "fmt"
import "os"

func main() {
   fmt.Fprinf(os.Stdout, "HelloWorld") 
}

fmt 为格式化包 用作格式化输出

fmt.Println 标准输出流打印 (默认在标准输出流输出)

os.Stdout 才是标准输出流

os.Stdin 为标准输入流

os.Stderr 为标准异常流

基本流操作


fmt.Fprinf(os.Stdout, "HelloWorld") 

往某个输出流输出数据

fmt.Fprinf(xxxout, "HelloWorld") 

基本文件控制

socket控制

Categories
go

go 基本命令

运行某个go文件

go run xxx.go

编译go文件

go build hello.go 

查看go 文档 默认在本机6060 显示web文档 (只可本机访问)

godoc 

查看某个方法

go doc fmt.Println