盡管web應(yīng)用有著不可比擬的優(yōu)勢,但在一些應(yīng)用場景里葱淳,考慮到某些因素(安全钝腺、客戶需求、通信效率等)不得不使用客戶端赞厕。然而艳狐,要達到同樣的視覺效果,相比于web坑傅,客戶端程序的界面設(shè)計及制作十分繁雜僵驰。因此,將web前端和客戶端開發(fā)結(jié)合起來是個不錯的想法唁毒。
而web前端中蒜茴,作為三大主流框架之一,vue
能大大降低開發(fā)成本浆西,節(jié)省開發(fā)時間粉私,并在頁面渲染和交互上有著良好表現(xiàn),因此本文選用Vue
作為web前端開發(fā)框架近零。
Electron
是當前一個比較成熟的將web程序打包的框架诺核,應(yīng)用廣泛,其實現(xiàn)也方便簡單久信。因此窖杀,本文使用Electron
作為打包工具。
Thrift
是Facebook公布的一款開源跨語言的RPC框架(選用RPC通信是出于安全考慮裙士,其通信原理見博客)入客,在web程序和python之間通信表現(xiàn)良好。
本文參考了一篇博客,對其進行了復(fù)現(xiàn)的同時加入了Vue框架并補充了部分細節(jié)桌硫。
環(huán)境配置
本文開發(fā)使用的環(huán)境:
- Windows 10
- Sublime text 3
- Python 3.7
- Pip 20.2.2
- Node 10.16.0
- Npm 6.9.0
- 安裝thrift:
pip install thrift
- 全局安裝
Electron
:
npm install electron -g
如果因網(wǎng)絡(luò)不佳導(dǎo)致安裝失敗夭咬,可考慮換成cnpm
進行安裝,cnpm
安裝教程見博客铆隘,安裝命令為:
cnpm install electron -g
- 全局安裝
vue-cli
:
npm install @vue/cli -g
- 找一個風水好的地方新建文件夾
electronApp
- 進入該文件夾卓舵,執(zhí)行命令
vue init simulatedgreg/electron-vue
,期間會出現(xiàn)一些輸入項膀钠,選擇打包工具時掏湾,有builder
和packager
兩個選項,一個是打包成安裝包托修,一個是打包成可直接運行的程序忘巧,根據(jù)需要選擇即可,其他直接enter
默認即可 - 在該文件夾執(zhí)行命令安裝本地環(huán)境:
npm install
- 在文件夾
src
->rederer
中新建文件夾lib
睦刃,進入lib
文件夾
新建接口文件test.thrift
砚嘴,輸入以下內(nèi)容:
service userService {
string test1(1:string name)
}
- 下載thrift.exe,并配置環(huán)境變量:
重命名該文件為thrift.exe
涩拙,在E盤(其他盤也可以)新建文件夾thrift
际长,將該文件放進去
右鍵單擊計算機,選擇屬性
兴泥,在彈框中工育,依次選擇高級系統(tǒng)設(shè)置
>環(huán)境變量
,在Path
中添加該文件地址
在cmd窗口中輸入thrift -version
如能正常顯示則配置成功 - 生成各自的接口文件:
thrift -out 存儲路徑 --gen 接口語言 thrift接口文件名
這里以當前路徑搓彻,生成nodejs:
thrift -out ./ --gen js:node test.thrift
生成完之后文件夾內(nèi)會多出兩個js文件
同理如绸,生成python:
thrift -out ./ --gen py test.thrift
在根目錄新建文件夾py
,將生成的文件夾test
和文件_init_.py
放入其中
代碼編寫
客戶端代碼
回到lib
目錄下旭贬,引入thrift
新建文件common.js
怔接,輸入以下內(nèi)容:
import Vue from 'vue'
class Api {
static importThrift = () => {
var thrift = require('thrift');
var userService = require('./userService.js');
var thriftConnection = thrift.createConnection('127.0.0.1', 8000);
var thriftClient = thrift.createClient(userService,thriftConnection);
thriftConnection.on("error",function(e){
console.error(e);
});
return thriftClient;
}
}
export default {
install(Vue) {
Vue.prototype.$api = Api;
Vue.prototype.$thrift = Api.importThrift;
}
}
新建文件index.js
,輸入以下內(nèi)容:
import Vue from 'vue'
import common from './common'
export default {
install(Vue) {
Vue.use(common)
}
}
編輯renderer
文件夾內(nèi)的main.js
稀轨,添加以下內(nèi)容:
import lib from './lib'
Vue.use(lib)
編輯src
->main
目錄下的文件index.js
扼脐,在末尾添加以下內(nèi)容:
const path=require('path')
let pyProc = null
let pyPort = null
const createPyProc = () => {
// let port = '4242'
let script = path.join(__dirname, 'py', 'thrift_server.py')
pyProc = require('child_process').spawn('python', [script])
if (pyProc != null) {
console.log('child process success')
}
}
const exitPyProc = () => {
pyProc.kill()
pyProc = null
pyPort = null
}
app.on('ready', createPyProc)
app.on('will-quit', exitPyProc)
調(diào)用
在任意Vue頁面文件里的<script></script>
標簽內(nèi)的函數(shù)里書寫以下代碼即可調(diào)用test1:
this.$thriftClient.test1(JSON.stringify(user), (error, res) => {
if(error) {
console.error(error)
} else {
console.log(res)
}
})
服務(wù)端代碼
進入py
目錄,新建文件thrift_server.py
:
import json
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
from test import userService
class Test:
def test1(self, dic):
print("one")
dic = json.loads(dic)
return f'Hello, {dic["name"]}!'
if __name__ == "__main__":
port = 8000
ip = "127.0.0.1"
# 創(chuàng)建服務(wù)端
handler = Test() # 自定義類
processor = userService.Processor(handler) # userService為python接口文件自動生成
# 監(jiān)聽端口
transport = TSocket.TServerSocket(ip, port) # ip與port位置不可交換
# 選擇傳輸層
tfactory = TTransport.TBufferedTransportFactory()
# 選擇傳輸協(xié)議
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
# 創(chuàng)建服務(wù)端
server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)
print("start server in python")
server.serve()
print("Done")
項目啟動
在py
目錄下執(zhí)行命令python thrift-server.py
在electronApp
目錄下執(zhí)行命令npm run dev
即可運行項目:
項目打包
寫好之后的項目需要打包成exe文件奋刽,便于移植
工具安裝
安裝打包工具:
pip install pyinstaller
在根目錄運行命令安裝Electron打包模塊:
npm install electron-packager --save-dev
環(huán)境配置
在package.json
的scripts
中加入"build-python":"pyinstaller ./py/thrift_server.py --clean"
瓦侮。
然后在根目錄下運行npm run build-python
編譯一下。編譯完了可以把根目錄下生成的build
文件夾和thrift_server.spec
刪了佣谐。
之前子進程是通過調(diào)用python命令運行的肚吏,現(xiàn)在我們要換成生成的可執(zhí)行程序。修改src
->main
下的index.js
:
// let script = path.join(__dirname, 'py', 'thrift_server.py')
// pyProc = require('child_process').spawn('python', [script])
let script = path.join(__dirname, 'py', 'dist','thrift_server')
pyProc = require('child_process').execFile(script)
然后將"pack-app": "./node_modules/.bin/electron-packager . --overwrite --ignore=py$"
寫入package.json
的scripts
中狭魂。
打包程序
運行npm run pack-app
打包程序罚攀,最后會生成可執(zhí)行文件吁断,復(fù)制到別的電腦也可以運行。
所有代碼見Github