主頁 > 後端開發 > PHP laravel+thrift+swoole打造微服務框架

PHP laravel+thrift+swoole打造微服務框架

2020-09-24 19:56:40 後端開發

Laravel作為最受歡迎的php web框架一直廣受廣大互聯網公司的喜愛,

筆者也參與過一些由laravel開發的專案,雖然laravel的性能廣受詬病但是業界也有一些比較好的解決方案,比如堆機器,比如使用swoole進行加速,

一個專案立項到開發上線,隨著時間和需求的不斷激增,會越來越復雜,變成一個大專案,如果前期專案架構沒設計的不好,代碼會越來越臃腫,難以維護,后期的每次產品迭代上線都會牽一發而動全身,專案微服務化,松耦合模塊間的關系,是一個很好的選擇,隨然增加了維護成本,但是還是很值得的,

那么有什么辦法使一個laravel專案改造成微服務呢?

 

最近研究thrift的時候發現thrift對php之城非常好,那么可不可以使用使用thrift作為rpc框架,使用swoole來實作異步TCP服務,打造一個微服務框架呢,

 

心動不如行動我們開始嘗試一下吧,首先我們創建一個laravel的專案,筆者使用的laravel官方提供的homestead的環境,

laravel new laravel-thrift-app 

安裝laravel-s https://github.com/hhxsv5/laravel-s/blob/master/README-CN.md

composer require "hhxsv5/laravel-s:~3.5.0" -vvv 

laravel-s是一個由swoole寫的laravel擴展,賦予laravel更好的性能,具體使用方法參看官方檔案,

在專案的根目錄下新建一個thrift的目錄,然后在該子目錄下創建 Thrift IDL 檔案 user.thrift,用于定義和用戶相關的服務介面,

1 namespace php App.Thrift.User  
2 // 定義用戶介面 
3 service User {     
4 string getInfo(1:i32 id)
5  }

 

這里我們定義了一個介面,接著在專案根目錄下運行如下命令,根據上述 IDL 檔案生成相關的服務代碼:

thrift -r --gen php:server -out ./ thrift/user.thrift 

 

查看檔案這時候我們會發現在App\Thrift\User`目錄下生成對應的服務代碼,

 

通過 Composer 安裝 Thrift PHP 依賴包:

composer require apache/thrift 

 

撰寫服務代碼,在 app目錄下新建一個 Services/Server 子目錄,然后在該目錄下創建服務介面類 UserService,該類實作自 `App\Thrift\User\UserIf` 介面:

 1 <?php
 2 namespace App\Services\Server;
 3 
 4 
 5 use App\Thrift\User\UserIf;
 6 
 7 class UserService implements UserIf
 8 {
 9     public function getInfo($id)
10     {
11         return "chenSi".$id;
12     }
13 }

 

在 app 目錄下新建一個 Sockets目錄用于存放 Swoole 相關代碼,首先我們創建一個 ServerTransport.php用來存放服務端代理類,并撰寫代碼如下:

 1 <?php
 2 namespace App\Sockets;
 3 
 4 
 5 use Thrift\Server\TServerTransport;
 6 
 7 class ServerTransport extends TServerTransport
 8 {
 9     /**
10      * @var array 服務器選項
11      */
12     public $options = [
13         'dispatch_mode'         => 1, //1: 輪循, 3: 爭搶
14         'open_length_check'     => true, //打開包長檢測
15         'package_max_length'    => 8192000, //最大的請求包長度,8M
16         'package_length_type'   => 'N', //長度的型別,參見PHP的pack函式
17         'package_length_offset' => 0,   //第N個位元組是包長度的值
18         'package_body_offset'   => 4,   //從第幾個位元組計算長度
19     ];
20 
21     /**
22      * @var SwooleServer
23      */
24     public $server;
25     protected $host;
26     protected $port;
27     protected $sockType;
28 
29 
30     public function __construct($swoole, $host, $port = 9999, $sockType = SWOOLE_SOCK_TCP, $options = [])
31     {
32         $this->server = $swoole;
33         $this->host   = $host;
34         $this->port   = $port;
35         $this->sockType = $sockType;
36         $this->options = array_merge($this->options,$options);
37 
38     }
39 
40 
41     public function listen()
42     {
43         $this->server =$this->server->addlistener($this->host,$this->port,$this->sockType);
44         $this->server->set($this->options);
45         return null;
46     }
47 
48 
49     public function close()
50     {
51         //$this->server->shutdown();
52         return null;
53     }
54 
55 
56     protected function acceptImpl()
57     {
58         return null;
59     }
60 }

 

我們在代理類的建構式中初始化 Swoole TCP 服務器引數,由于我們使用的是laravel-s然后在該類中定義 listen 方法啟動這個swoole增加監聽的埠并監聽客戶端請求,

我們在 app/Sockets目錄下創建 Transport.php檔案用于存放基于 Swoole 的傳輸層實作代碼:

  1 <?php
  2 /**
  3  * Created by PhpStorm.
  4  * User: 74100
  5  * Date: 2019/10/21
  6  * Time: 2:22
  7  */
  8 namespace App\Sockets;
  9 
 10 use Swoole\Server as SwooleServer;
 11 use Thrift\Exception\TTransportException;
 12 use Thrift\Transport\TTransport;
 13 
 14 class Transport extends TTransport
 15 {
 16     /**
 17      * @var swoole服務器實體
 18      */
 19     protected $server;
 20     /**
 21      * @var int 客戶端連接描述符
 22      */
 23     protected $fd = -1;
 24     /**
 25      * @var string 資料
 26      */
 27     protected $data = '';
 28     /**
 29      * @var int 資料讀取指標
 30      */
 31     protected $offset = 0;
 32 
 33     /**
 34      * SwooleTransport constructor.
 35      * @param SwooleServer $server
 36      * @param int $fd
 37      * @param string $data
 38      */
 39     public function __construct(SwooleServer $server, $fd, $data)
 40     {
 41         $this->server = $server;
 42         $this->fd = $fd;
 43         $this->data = https://www.cnblogs.com/a609251438/p/$data;
 44     }
 45 
 46     /**
 47      * Whether this transport is open.
 48      *
 49      * @return boolean true if open
 50      */
 51     public function isOpen()
 52     {
 53         return $this->fd > -1;
 54     }
 55 
 56     /**
 57      * Open the transport for reading/writing
 58      *
 59      * @throws TTransportException if cannot open
 60      */
 61     public function open()
 62     {
 63         if ($this->isOpen()) {
 64             throw new TTransportException('Swoole Transport already connected.', TTransportException::ALREADY_OPEN);
 65         }
 66     }
 67 
 68     /**
 69      * Close the transport.
 70      * @throws TTransportException
 71      */
 72     public function close()
 73     {
 74         if (!$this->isOpen()) {
 75             throw new TTransportException('Swoole Transport not open.', TTransportException::NOT_OPEN);
 76         }
 77         $this->server->close($this->fd, true);
 78         $this->fd = -1;
 79     }
 80 
 81     /**
 82      * Read some data into the array.
 83      *
 84      * @param int $len How much to read
 85      * @return string The data that has been read
 86      * @throws TTransportException if cannot read any more data
 87      */
 88     public function read($len)
 89     {
 90         if (strlen($this->data) - $this->offset < $len) {
 91             throw new TTransportException('Swoole Transport[' . strlen($this->data) . '] read ' . $len . ' bytes failed.');
 92         }
 93         $data = substr($this->data, $this->offset, $len);
 94         $this->offset += $len;
 95         return $data;
 96     }
 97 
 98     /**
 99      * Writes the given data out.
100      *
101      * @param string $buf The data to write
102      * @throws TTransportException if writing fails
103      */
104     public function write($buf)
105     {
106         if (!$this->isOpen()) {
107             throw new TTransportException('Swoole Transport not open.', TTransportException::NOT_OPEN);
108         }
109         $this->server->send($this->fd, $buf);
110     }
111 }

 

Transport類主要用于從傳輸層寫入或讀取資料,最后我們創建 Server.php 檔案,用于存放基于 Swoole 的 RPC 服務器類:

 1 <?php
 2 /**
 3  * Created by PhpStorm.
 4  * User: 74100
 5  * Date: 2019/10/21
 6  * Time: 2:24
 7  */
 8 namespace App\Sockets;
 9 
10 use Swoole\Server as SwooleServer;
11 use Thrift\Server\TServer;
12 
13 class Server extends TServer
14 {
15     public function serve()
16     {
17 
18         $this->transport_->server->on('receive', [$this, 'handleReceive']);
19         $this->transport_->listen();
20 
21     }
22 
23     public function stop()
24     {
25         $this->transport_->close();
26     }
27 
28     /**
29      * 處理RPC請求
30      * @param Server $server
31      * @param int $fd
32      * @param int $fromId
33      * @param string $data
34      */
35     public function handleReceive(SwooleServer $server, $fd, $fromId, $data)
36     {
37         $transport = new Transport($server, $fd, $data);
38         $inputTransport = $this->inputTransportFactory_->getTransport($transport);
39         $outputTransport = $this->outputTransportFactory_->getTransport($transport);
40         $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
41         $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
42         $this->processor_->process($inputProtocol, $outputProtocol);
43     }
44 }

 

 

該類繼承自 Thrift\Server\TServer,在子類中需要實作 serve` 和 `stop`方法,分別定義服務器啟動和關閉邏輯,這里我們在 serve方法中定義了 Swoole TCP 服務器收到請求時的回呼處理函式,其中 $this->transport 指向 App\Swoole\ServerTransport 實體,回呼函式 handleReceive中我們會將請求資料傳入傳輸層處理類 Transport進行初始化,然后再通過一系列轉化通過處理器對請求進行處理,該方法中 `$this` 指標指向的屬性都是在外部啟動 RPC 服務器時傳入的,后面我們會看到,定義好請求回呼后,即可通過 `$this->transport_->listen()` 啟動服務器并監聽請求,

 

最后我們使用laravel-s的事件回呼,

在laravel-s的組態檔新增Master行程啟動時的事件,

'event_handlers'           => [     'ServerStart' => \App\Events\ServerStartEvent::class, ], 

 

撰寫ServerStartEvent類,

 1 <?php
 2 namespace App\Events;
 3 use App\Sockets\ServerTransport;
 4 use Hhxsv5\LaravelS\Swoole\Events\ServerStartInterface;
 5 use App\Services\Server\UserService;
 6 use App\Sockets\TFramedTransportFactory;
 7 use App\Thrift\User\UserProcessor;
 8 use Thrift\Factory\TBinaryProtocolFactory;
 9 use Swoole\Http\Server;
10 use App\Sockets\Server as TServer;
11 
12 
13 class ServerStartEvent implements ServerStartInterface
14 {
15     public function __construct()
16     {
17     }
18     public function handle(Server $server)
19     {
20         // 初始化thrift
21         $processor = new UserProcessor(new UserService());
22         $tFactory = new TFramedTransportFactory();
23         $pFactory = new TBinaryProtocolFactory();
24         // 監聽本地 9999 埠,等待客戶端連接請求
25         $transport = new ServerTransport($server,'127.0.0.1', 9999);
26         $server = new TServer($processor, $transport, $tFactory, $tFactory, $pFactory, $pFactory);
27         $server->serve();
28     }
29 }

 

這時候我們服務端的代碼已經寫完,開始寫客戶端的代碼,

接下來,我們來修改客戶端請求服務端遠程介面的代碼,在此之前在 app/Sockets目錄下新建一個 ClientTransport.php 來存放客戶端與服務端通信的傳輸層實作代碼:

  1 <?php
  2 namespace App\Sockets;
  3     use Swoole\Client;
  4     use Thrift\Exception\TTransportException;
  5     use Thrift\Transport\TTransport;
  6 
  7     class ClientTransport extends TTransport
  8     {
  9         /**
 10          * @var string 連接地址
 11          */
 12         protected $host;
 13         /**
 14          * @var int 連接埠
 15          */
 16         protected $port;
 17         /**
 18          * @var Client
 19          */
 20         protected $client;
 21 
 22         /**
 23          * ClientTransport constructor.
 24          * @param string $host
 25          * @param int $port
 26          */
 27         public function __construct($host, $port)
 28         {
 29             $this->host = $host;
 30             $this->port = $port;
 31             $this->client = new Client(SWOOLE_SOCK_TCP);
 32         }
 33 
 34         /**
 35          * Whether this transport is open.
 36          *
 37          * @return boolean true if open
 38          */
 39         public function isOpen()
 40         {
 41             return $this->client->sock > 0;
 42         }
 43 
 44         /**
 45          * Open the transport for reading/writing
 46          *
 47          * @throws TTransportException if cannot open
 48          */
 49         public function open()
 50         {
 51             if ($this->isOpen()) {
 52                 throw new TTransportException('ClientTransport already open.', TTransportException::ALREADY_OPEN);
 53             }
 54             if (!$this->client->connect($this->host, $this->port)) {
 55                 throw new TTransportException(
 56                     'ClientTransport could not open:' . $this->client->errCode,
 57                     TTransportException::UNKNOWN
 58                 );
 59             }
 60         }
 61 
 62         /**
 63          * Close the transport.
 64          * @throws TTransportException
 65          */
 66         public function close()
 67         {
 68             if (!$this->isOpen()) {
 69                 throw new TTransportException('ClientTransport not open.', TTransportException::NOT_OPEN);
 70             }
 71             $this->client->close();
 72         }
 73 
 74         /**
 75          * Read some data into the array.
 76          *
 77          * @param int $len How much to read
 78          * @return string The data that has been read
 79          * @throws TTransportException if cannot read any more data
 80          */
 81         public function read($len)
 82         {
 83             if (!$this->isOpen()) {
 84                 throw new TTransportException('ClientTransport not open.', TTransportException::NOT_OPEN);
 85             }
 86             return $this->client->recv($len, true);
 87         }
 88 
 89         /**
 90          * Writes the given data out.
 91          *
 92          * @param string $buf The data to write
 93          * @throws TTransportException if writing fails
 94          */
 95         public function write($buf)
 96         {
 97             if (!$this->isOpen()) {
 98                 throw new TTransportException('ClientTransport not open.', TTransportException::NOT_OPEN);
 99             }
100             $this->client->send($buf);
101         }
102     }

 

我們在 app/Services/Client 目錄下創建 UserService.php,用于存放 RPC 客戶端連接與請求服務介面方法:

 1 <?php
 2     namespace App\Services\Client;
 3 
 4     use App\Sockets\ClientTransport;
 5     use App\Thrift\User\UserClient;
 6     use Thrift\Exception\TException;
 7     use Thrift\Protocol\TBinaryProtocol;
 8     use Thrift\Protocol\TMultiplexedProtocol;
 9     use Thrift\Transport\TBufferedTransport;
10     use Thrift\Transport\TFramedTransport;
11     use Thrift\Transport\TSocket;
12 
13     class UserService
14     {
15         public function getUserInfoViaSwoole(int $id)
16         {
17             try {
18                 // 建立與 SwooleServer 的連接
19                 $socket = new ClientTransport("127.0.0.1", 9999);
20 
21                 $transport = new TFramedTransport($socket);
22                 $protocol = new TBinaryProtocol($transport);
23                 $client = new UserClient($protocol);
24                 $transport->open();
25 
26                 $result = $client->getInfo($id);
27 
28                 $transport->close();
29                 return $result;
30             } catch (TException $TException) {
31                 dd($TException);
32             }
33         }
34     }

 

測驗,新增一個路由,

1 Route::get('/user/{id}', function($id) {
2     $userService = new UserService();
3     $user = $userService->getUserInfoViaSwoole($id);
4     return $user;
5 });

 

啟動laravel-s,

php bin/laravels start 

 

在瀏覽器中輸入 http://192.168.10.100:5200/user/2 (192.168.10.100為我homestead設定的地址,5200為laravel-s設定的埠號)

這時候我們就會發現瀏覽器上面出現chensi2幾個大字,一個由larave+thrift+swoole搭建的微服務框架就這樣完成了,埠號固定9999也可以使用consul做服務發現,

 

當然了有興趣的可以寫一個package自己去實作而不用laravels這個擴展,

  • 多PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那里入手去提升,對此我整理了一些資料,包括但不限于:分布式架構、高可擴展、高性能、高并發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階干貨需要的可以免費分享給大家,需要的加群(點擊→)677079770

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/121066.html

標籤:PHP

上一篇:PHP下載遠程圖片到本地的幾種方法總結(tp5.1)

下一篇:go-micro+php+consul簡單的微服實作

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more