Categories
java

hytrix

断路器 用作监控请求 是否合理 当出现异常流量 可以短路保护

具体使用方式通过切面编程 将需要监控的方法 包括controller service dao 的方法添加注解方式

然后当执行该方法时 会先进去hystrix定义的监控线程上

异步执行需监控的方法 并注册一个超时事件在 监控线程上

所以被HystrixCommand 注解的方法其实是异步执行的

思考 是否应该在网关应用上 添加hystrix 做断路器限流

的确是应该如此这样做

Categories
php

laravel 入口

php 通过 symfony/http-foundation(http请求响应封装) 框架捕获http请求

laravel kernel 类 为laravel http 入口

middleware 类似于 过滤器 可以执行请求处理 然后next 执行处理链 必定有 handle 方法 当需要处理请求前操作 在调用 $next 前修改请求信息 当需要处理请求后 或者 在响应上操作 则 在$next后 修改信息 且返回结果必定为 $response对象

public function handle($request, Closure $next)
    {
        // Check if we're dealing with CORS and if we should handle it
        if (! $this->shouldRun($request)) {
            return $next($request);
        }

        // For Preflight, return the Preflight response
        if ($this->cors->isPreflightRequest($request)) {
            $response = $this->cors->handlePreflightRequest($request);

            $this->cors->varyHeader($response, 'Access-Control-Request-Method');

            return $response;
        }

        // Add the headers on the Request Handled event as fallback in case of exceptions
        if (class_exists(RequestHandled::class) && $this->container->bound('events')) {
            $this->container->make('events')->listen(RequestHandled::class, function (RequestHandled $event) {
                $this->addHeaders($event->request, $event->response);
            });
        }

        // Handle the request
        $response = $next($request);

        if ($request->getMethod() === 'OPTIONS') {
            $this->cors->varyHeader($response, 'Access-Control-Request-Method');
        }

        return $this->addHeaders($request, $response);
    }
Categories
nodejs

nodejs Stream

nodejs 流对象操作 记录

自定义可写流

const {Writable} = require('stream')

class CounterStream extends Writable {
    


    constructor(options){
        super(options)
        this.counter = 0
    }

    _write(chunk , encoding, callback){
        console.log(chunk.toString("utf-8"))
        this.counter+=chunk.length
        callback.call()
    }

    
}


module.exports = CounterStream

关键在于继承stream.Writeable 并且重写 _write(chunk , encoding, callback)

自定义可读流

const {Readable} = require('stream')

class MyReadableStream extends Readable {
    


    constructor(options){
        super(options)
        this.isFinished = false
    
    }

    _read(size){
        //待处理数据放在this._buffer中
        if(!this.isFinished){
            this.push("abc123")
            this.isFinished = true
        }else{
            this.push(null)
        }
    }
}


module.exports = MyReadableStream

关键在于继承stream.Readable 并且重写 _read(size)

_read 方法中要把数据放到this.push的方法中 且 没有数据读取时 this.push(null) 结束读取

可以从Readable.pipe(Writable) 使用管道的方式 从可读流读取数据 pipe 到可写流中

注意 该方法为异步方法

特殊的流 socket 为双向流 可读可写

process.stdin 标准输入流

process.stdout 标准输出流

process.stderr 标准异常流

把标准输入流输出到标准输出流

const stdin = require('process').stdin
const stdout = require('process').stdout
const stderr = require('process').stderr

stdin.pipe(stdout)

执行后 主线程阻塞 读取标准输入流 读取到数据后 在 标准输出流输出

输入流事件有以下几个

输出流事件

Categories
java microservice php

Sidecar

Spring Cloud Netflix Sidecar框架提供了Sidecar模式的现成解决方案。Spring Cloud Netflix Sidecar框架框架可以提供对其他非Spring Cloud技术栈的微服务的治理。比如,你可以使用Node或者Golang php 编写一个Web项目,这个服务同样可以以Sidecar模式,纳入到Spring Cloud管理中去。

Categories
java

spring integration

类似于数据管道处理的 框架 是一个面向数据的框架

可以兼容多种现有的消息处理框架 包括kafka MQ 等 也可以处理 java 特有JMS消息 RMI Socket 等数据接入点

核心信息用Message 代表

Channel 发送信息 send 拉取信息 receive 订阅消息 subscribe

queue channel 可以缓冲消息

channel interceptor 拦截器了 说明消息处理也是过滤链模式

channel.addInterceptor(Interceptor xxx)

xml 配置说明

spring-integration 可通过xml配置消息处理链 达到代码解耦效果

Categories
php

php 静态变量与全局变量

静态变量 : 在函数内部以static 作为声明前缀

全局变量 : 在函数内部以global作为声明前缀

共同点

静态变量与全局变量当同一方法在一次访问后更新后 能一直维持该值的该值 第二次 也依然能读取上次的赋值

最大的访问域是一个请求 不同请求下的值不一样。(php 一次请求就是一个进程 进程内部变量不能共享)

不同点

静态变量 在方法内部声明 也只能在方法内部使用

全局变量 在任何地方声明 在任何地方调用

且可以通过GLOBALS[‘xxx’]调用

Categories
php

php 字符串模板

$var = "world";
$helloWorld = "hello {$var}";
echo $helloWorld;

双引号自带模板语法功能 花括号自带变量替换功能

Categories
php

php nginx 环境下载

nginx 配置

root /var/www/php;  // 新版本 root 要放在这里次啊能起作用
location   ~\.php$ {
                        root            /var/www/php;
                        index          index.php index.htmlindex.htm;
                        fastcgi_pass    unix:/run/php/php7.4-fpm.sock;
                        fastcgi_index   index.php;
                        include         fastcgi_params;
                }

服务器 安装 php-fpm

然后 nginx 通过unix:/run/php/php7.4-fpm.sock 转发请求到php-fpm上

tips : fastcgi_params 添加以下配置(若访问首页空白)

fastcgi_param SCRIPT_FILENAME     $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO           $fastcgi_script_name;
//从nginx变量 传到  cgi变量(即php变量)

fastcgi_param 参数详解 就是从nginx传过去的变量 可以通过_SERVER 获取

关键变量是

DOCUMENT_ROOT php 项目文件所在文件夹

SCRIPT_NAME php 项目文件

SCRIPT_FILENAME $document_root$fastcgi_script_name; //php 文件全路径

nginx变量 都是$开头小写下划线组合


fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

以上参数可以通过 php $_SERVER[‘SERVER_NAME’] 获取变量值

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'];
}