Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
談起桌面應(yīng)用開(kāi)發(fā)技術(shù), 我們會(huì)想到.Net下的WinForm, Java下的JavaFX以及Linux下的QT. 這些技術(shù)對(duì)于Web應(yīng)用程序員來(lái)說(shuō)一般比較陌生, 因?yàn)榇蠖郬eb應(yīng)用程序員的開(kāi)發(fā)技能是前端的JavaScript和后端的Java,PHP等語(yǔ)言.
如果Web應(yīng)用程序員想開(kāi)發(fā)桌面應(yīng)用怎么辦? 主流的桌面應(yīng)用開(kāi)發(fā)技術(shù)的學(xué)習(xí)曲線不低, 上手比較困難. 而Electron的出現(xiàn)給Web應(yīng)用程序員帶來(lái)了福音.
Electron簡(jiǎn)介:
Electron 是 Github 發(fā)布跨平臺(tái)桌面應(yīng)用開(kāi)發(fā)工具,支持 Web 技術(shù)開(kāi)發(fā)桌面應(yīng)用開(kāi)發(fā),其本身是基于 C++ 開(kāi)發(fā)的,GUI 核心來(lái)自于 Chrome,而 JavaScript 引擎使用 v8...
簡(jiǎn)單的說(shuō), Electron平臺(tái)就是用Javascript把UI和后臺(tái)邏輯打通, 后臺(tái)主進(jìn)程使用NodeJs豐富的API完成復(fù)雜耗時(shí)的邏輯, 而UI進(jìn)程則借助Chrome渲染html完成交互.
我之前使用SpringBoot開(kāi)發(fā)了一套市長(zhǎng)信箱抓取Web應(yīng)用. 由于沒(méi)服務(wù)器部署, 所以我現(xiàn)在想把同樣的功能移植到桌面端, 作成一個(gè)桌面應(yīng)用. 對(duì)于開(kāi)發(fā)平臺(tái)我有以下需求:
而Electron作為開(kāi)發(fā)平臺(tái)正好能滿(mǎn)足我的這些需求, 通過(guò)一天的摸索, 我完成了這個(gè)桌面應(yīng)用, 并最終打包出Mac平臺(tái)下的DMG安裝文件. 工程代碼: https://github.com/ybak/watcher
下面將介紹我是如何使用Electron平臺(tái)開(kāi)發(fā)這個(gè)桌面應(yīng)用.
回顧: 市長(zhǎng)信箱郵件抓取Web應(yīng)用
動(dòng)手之前, 我先分析一下之前所做的抓取Web應(yīng)用. 它的架構(gòu)如下:
應(yīng)用分可為四部分:
設(shè)計(jì): 使用Electron構(gòu)建抓取桌面應(yīng)用
將要實(shí)現(xiàn)的桌面應(yīng)用, 同樣也需要需要完成這四部分的工作. 我做了以下設(shè)計(jì):
Electron主進(jìn)程借助NodeJs豐富的生態(tài)系統(tǒng)完成網(wǎng)頁(yè)抓取與數(shù)據(jù)存儲(chǔ)與搜索的功能, UI進(jìn)程則完成頁(yè)面的渲染工作.
實(shí)現(xiàn): 使用Electron構(gòu)建抓取桌面應(yīng)用
1. 抓取程序的實(shí)現(xiàn):
市長(zhǎng)信箱郵件多達(dá)上萬(wàn)封, JavaScript異步的特點(diǎn), 會(huì)讓人不小心就寫(xiě)出上千并發(fā)請(qǐng)求的程序, 短時(shí)間內(nèi)大量試圖和抓取目標(biāo)服務(wù)器建立連接的行為會(huì)被服務(wù)器拒絕服務(wù), 從而造成抓取流程失敗. 所以抓取程序要做到:
我使用以下三個(gè)NodeJs組件:
代碼: crawlService.js
//使用request獲取頁(yè)面內(nèi)容 request('http://12345.chengdu.gov.cn/moreMail', (err, response, body)=> { if (err) throw err; //使用cheerio解析html var $=cheerio.load(body), totalSize=$('div.pages script').html().match(/iRecCount=\d+/g)[0].match(/\d+/g)[0]; ...... //使用async控制請(qǐng)求并發(fā), 順序的抓取郵件分頁(yè)內(nèi)容 async.eachSeries(pagesCollection, function (page, crawlNextPage) { pageCrawl(page, totalPageSize, updater, crawlNextPage); }) });
2. 數(shù)據(jù)庫(kù)的實(shí)現(xiàn):
抓取后的內(nèi)容存儲(chǔ)方式有較多選擇:
文本文件雖然保存簡(jiǎn)單, 但不利于查詢(xún)和搜索, 顧不采用.
搜索引擎一般需要獨(dú)立部署, 不利于桌面應(yīng)用的安裝, 這里暫不采用.
獨(dú)立部署的數(shù)據(jù)庫(kù)有和搜索引擎同樣的問(wèn)題, 所以像連接外部Mysql的方式這里也不采用.
綜合考慮, 我需要一種內(nèi)嵌數(shù)據(jù)庫(kù). 幸好NodeJs的組件非常豐富, nedb是一個(gè)不錯(cuò)的方案, 它可以將數(shù)據(jù)同時(shí)保存在內(nèi)存和磁盤(pán)中, 同時(shí)是文檔型內(nèi)嵌數(shù)據(jù)庫(kù), 使用mongodb的語(yǔ)法進(jìn)行數(shù)據(jù)操作.
代碼: dbService.js
//建立數(shù)據(jù)庫(kù)連接 const db=new Datastore({filename: getUserHome()+'/.electronapp/watcher/12345mails.db', autoload: true}); ...... //使用nedb插入數(shù)據(jù) db.update({_id: mail._id}, mail, {upsert: true}, function (err, newDoc) {}); ...... //使用nedb進(jìn)行郵件查詢(xún) let match={$regex: eval('/' + keyword + '/')}; //關(guān)鍵字匹配 var query=keyword ? {$or: [{title: match}, {content: match}]} : {}; db.find(query).sort({publishDate: -1}).limit(100).exec(function (err, mails) { event.sender.send('search-reply', {mails: mails});//處理查詢(xún)結(jié)果 });
3. UI的實(shí)現(xiàn):
桌面應(yīng)用的工程目錄如圖:
我將UI頁(yè)面放到static文件夾下. 在Electron的進(jìn)行前端UI開(kāi)發(fā)和普通的Web開(kāi)發(fā)方式一樣, 因?yàn)镋lectron的UI進(jìn)程就是一個(gè)Chrome進(jìn)程. Electron啟動(dòng)時(shí), 主進(jìn)程會(huì)執(zhí)行index.js文件, index.js將初始化應(yīng)用的窗口, 設(shè)置大小, 并在窗口加載UI入口頁(yè)面index.html.
代碼:index.js
function createMainWindow() { const win=new electron.BrowserWindow({ width: 1200, height: 800 });//初始應(yīng)用窗口大小 win.loadURL(`file://${__dirname}/static/index.html`);//在窗口中加載頁(yè)面 win.openDevTools();//打開(kāi)chrome的devTools win.on('closed', onClosed); return win; }
在UI頁(yè)面開(kāi)發(fā)的過(guò)程中, 有一點(diǎn)需要注意的是: 默認(rèn)情況下頁(yè)面會(huì)出現(xiàn)jQuery, require等組件加載失敗的情況, 這是因?yàn)闉g覽器window加載了NodeJs的一些方法, 和jQuery類(lèi)庫(kù)的方法沖突. 所以我們需要做些特別的處理, 在瀏覽器window中把這些NodeJs的方法刪掉:
代碼:preload.js
// 解決require沖突導(dǎo)致jQuery等組件不可用的問(wèn)題 window.nodeRequire=require; delete window.require; delete window.exports; delete window.module; // 解決chrome調(diào)試工具devtron不可用的問(wèn)題 window.__devtron={require: nodeRequire, process: process}
4. 通信的實(shí)現(xiàn):
在Web應(yīng)用中, 頁(yè)面和服務(wù)的通信都是通過(guò)ajax進(jìn)行, 那我們的桌面應(yīng)用不是也可以采用ajax的方式通信? 這樣理論雖然上可行, 但有一個(gè)很大弊端: 我們的應(yīng)用需要打開(kāi)一個(gè)http的監(jiān)聽(tīng)端口, 通常個(gè)人操作系統(tǒng)都禁止軟件打開(kāi)http80端口, 而打開(kāi)其他端口也容易和別的程序造成端口沖突, 所以我們需要一種更優(yōu)雅的方式進(jìn)行通信.
Electron提供了UI進(jìn)程和主進(jìn)程通信的IPC API, 通過(guò)使用IPC通信, 我們就能實(shí)現(xiàn)UI頁(yè)面向NodeJs服務(wù)邏輯發(fā)起查詢(xún)和抓取請(qǐng)求,也能實(shí)現(xiàn)NodeJs服務(wù)主動(dòng)向UI頁(yè)面通知抓取進(jìn)度的更新.
使用Electron的IPC非常簡(jiǎn)單.
首先, 我們需要在UI中使用ipcRenderer, 向自定義的channel發(fā)出消息.
代碼: app.js
const ipcRenderer=nodeRequire('electron').ipcRenderer; //提交查詢(xún)表單 $('form.searchForm').submit(function (event) { $('#waitModal').modal('show'); event.preventDefault(); ipcRenderer.send('search-keyword', $('input.keyword').val());//發(fā)起查詢(xún)請(qǐng)求 }); ipcRenderer.on('search-reply', function(event, data) {//監(jiān)聽(tīng)查詢(xún)結(jié)果 $('#waitModal').modal('hide'); if (data.mails) { var template=Handlebars.compile($('#template').html()); $('div.list-group').html(template(data)); } });
然后, 需要在主進(jìn)程執(zhí)行的NodeJs代碼中使用ipcMain, 監(jiān)聽(tīng)之前自定義的渠道, 就能接受UI發(fā)出的請(qǐng)求了.
代碼: crawlService.js
const ipcMain=require('electron').ipcMain; ipcMain.on('search-keyword', (event, arg)=> { ....//處理查詢(xún)邏輯 }); ipcMain.on('start-crawl', (event, arg)=> { ....//處理抓取邏輯 });
桌面應(yīng)用打包
解決完以上四個(gè)方面的問(wèn)題后, 剩下的程序?qū)懫饋?lái)就簡(jiǎn)單了. 程序調(diào)試完后, 使用electron-builder, 就可以編譯打包出針對(duì)不同平臺(tái)的可執(zhí)行文件了.
最近筆者終于把H5-Dooring的后臺(tái)管理系統(tǒng)初步搭建完成, 有了初步的數(shù)據(jù)采集和數(shù)據(jù)分析能力, 接下來(lái)我們就復(fù)盤(pán)一下其中涉及的幾個(gè)知識(shí)點(diǎn),并一一闡述其在Dooring H5可視化編輯器中的解決方案. 筆者將分成3篇文章來(lái)復(fù)盤(pán), 主要解決場(chǎng)景如下: 如何使用JavaScript實(shí)現(xiàn)前端導(dǎo)入和導(dǎo)出excel文件(H5編輯器實(shí)戰(zhàn)復(fù)盤(pán)) 前端如何基于table中的數(shù)據(jù)一鍵生成多維度數(shù)據(jù)可視化分析報(bào)表 * 如何實(shí)現(xiàn)會(huì)員管理系統(tǒng)下的權(quán)限路由和權(quán)限菜單
以上場(chǎng)景也是前端工程師在開(kāi)發(fā)后臺(tái)管理系統(tǒng)中經(jīng)常遇到的或者即將遇到的問(wèn)題, 本文是上述介紹中的第一篇文章, 你將收獲: 使用JavaScript實(shí)現(xiàn)前端導(dǎo)入excel文件并自動(dòng)生成可編輯的Table組件 使用JavaScript實(shí)現(xiàn)前端基于Table數(shù)據(jù)一鍵導(dǎo)出excel文件 * XLSX和js-export-excel基本使用
本文接下來(lái)的內(nèi)容素材都是基于H5可視化編輯器(H5-Dooring)項(xiàng)目的截圖, 如果想實(shí)際體驗(yàn), 可以訪問(wèn)H5-Dooring網(wǎng)站實(shí)際體驗(yàn). 接下來(lái)我們直接開(kāi)始我們的方案實(shí)現(xiàn).
在開(kāi)始實(shí)現(xiàn)之前, 我們先來(lái)看看實(shí)現(xiàn)效果.
導(dǎo)入excel文件并通過(guò)antd的table組件渲染table:
編輯table組件:
保存table數(shù)據(jù)后實(shí)時(shí)渲染可視化圖表:
以上就是我們實(shí)現(xiàn)導(dǎo)入excel文件后, 編輯table, 最后動(dòng)態(tài)生成圖表的完整流程.
導(dǎo)入excel文件的功能我們可以用javascript原生的方式實(shí)現(xiàn)解析, 比如可以用fileReader這些原生api,但考慮到開(kāi)發(fā)效率和后期的維護(hù), 筆者這里采用antd的Upload組件和XLSX來(lái)實(shí)現(xiàn)上傳文件并解析的功能. 由于我們采用antd的table組件來(lái)渲染數(shù)據(jù), 所以我們需要手動(dòng)將解析出來(lái)的數(shù)據(jù)轉(zhuǎn)換成table支持的數(shù)據(jù)格式.大致流程如下:
所以我們需要做的就是將Upload得到的文件數(shù)據(jù)傳給xlsx, 由xlsx生成解析對(duì)象, 最后我們利用javascript算法將xlsx的對(duì)象處理成ant-table支持的數(shù)據(jù)格式即可. 這里我們用到了FileReader對(duì)象, 目的是將文件轉(zhuǎn)化為BinaryString, 然后我們就可以用xlsx的binary模式來(lái)讀取excel數(shù)據(jù)了, 代碼如下:
// 解析并提取excel數(shù)據(jù)
let reader=new FileReader();
reader.onload=function(e) {
let data=e.target.result;
let workbook=XLSX.read(data, {type: 'binary'});
let sheetNames=workbook.SheetNames; // 工作表名稱(chēng)集合
let draftObj={}
sheetNames.forEach(name=> {
// 通過(guò)工作表名稱(chēng)來(lái)獲取指定工作表
let worksheet=workbook.Sheets[name];
for(let key in worksheet) {
// v是讀取單元格的原始值
if(key[0] !=='!') {
if(draftObj[key[0]]) {
draftObj[key[0]].push(worksheet[key].v)
}else {
draftObj[key[0]]=[worksheet[key].v]
}
}
}
});
// 生成ant-table支持的數(shù)據(jù)格式
let sourceData=Object.values(draftObj).map((item,i)=> ({ key: i + '', name: item[0], value: item[1]}))
經(jīng)過(guò)以上處理, 我們得到的sourceData即是ant-table可用的數(shù)據(jù)結(jié)構(gòu), 至此我們就實(shí)現(xiàn)了表格導(dǎo)入的功能.
table表格的編輯功能實(shí)現(xiàn)其實(shí)也很簡(jiǎn)單, 我們只需要按照antd的table組件提供的自定義行和單元格的實(shí)現(xiàn)方式即可. antd官網(wǎng)上也有實(shí)現(xiàn)可編輯表格的實(shí)現(xiàn)方案, 如下:
大家感興趣的可以研究一下. 當(dāng)然自己實(shí)現(xiàn)可編輯的表格也很簡(jiǎn)單, 而且有很多方式, 比如用column的render函數(shù)來(lái)動(dòng)態(tài)切換表格的編輯狀態(tài), 或者使用彈窗編輯等都是可以的.
根據(jù)table數(shù)據(jù)動(dòng)態(tài)生成圖表這塊需要有一定的約定, 我們需要符合圖表庫(kù)的數(shù)據(jù)規(guī)范, 不過(guò)我們有了table數(shù)據(jù), 處理數(shù)據(jù)規(guī)范當(dāng)然是很簡(jiǎn)單的事情了, 筆者的可視化庫(kù)采用antv的f2實(shí)現(xiàn), 所以需要做一層適配來(lái)使得f2能消費(fèi)我們的數(shù)據(jù).
還有一點(diǎn)就是為了能使用多張圖表, 我們需要對(duì)f2的圖表進(jìn)行統(tǒng)一封裝, 使其成為符合我們應(yīng)用場(chǎng)景的可視化組件庫(kù).
我們先看看f2的使用的數(shù)據(jù)格式:
const data=[
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 }
];
此數(shù)據(jù)格式會(huì)渲染成如下的圖表:
所以說(shuō)我們總結(jié)下來(lái)其主要有2個(gè)緯度的指標(biāo), 包括它們的面積圖, 餅圖, 折線圖, 格式都基本一致, 所以我們可以基于這一點(diǎn)封裝成組件的可視化組件, 如下:
import { Chart } from '@antv/f2';
import React, { memo, useEffect, useRef } from 'react';
import ChartImg from '@/assets/chart.png';
import styles from './index.less';
import { IChartConfig } from './schema';
interface XChartProps extends IChartConfig {
isTpl: boolean;
}
const XChart=(props: XChartProps)=> {
const { isTpl, data, color, size, paddingTop, title }=props;
const chartRef=useRef(null);
useEffect(()=> {
if (!isTpl) {
const chart=new Chart({
el: chartRef.current || undefined,
pixelRatio: window.devicePixelRatio, // 指定分辨率
});
// step 2: 處理數(shù)據(jù)
const dataX=data.map(item=> ({ ...item, value: Number(item.value) }));
// Step 2: 載入數(shù)據(jù)源
chart.source(dataX);
// Step 3:創(chuàng)建圖形語(yǔ)法,繪制柱狀圖,由 genre 和 sold 兩個(gè)屬性決定圖形位置,genre 映射至 x 軸,sold 映射至 y 軸
chart
.interval()
.position('name*value')
.color('name');
// Step 4: 渲染圖表
chart.render();
}
}, [data, isTpl]);
return (
<div className={styles.chartWrap}>
<div className={styles.chartTitle} style={{ color, fontSize: size, paddingTop }}>
{title}
</div>
{isTpl ? <img src={ChartImg} alt="dooring chart" /> : <canvas ref={chartRef}></canvas>}
</div>
);
};
export default memo(XChart);
當(dāng)然其他的可視化組件也可以用相同的模式封裝,這里就不一一舉例了. 以上的組件封裝使用react的hooks組件, vue的也類(lèi)似, 基本原理都一致.
同樣的, 我們實(shí)現(xiàn)將table數(shù)據(jù)一鍵導(dǎo)出為excel也是類(lèi)似, 不過(guò)方案有所不同, 我們先來(lái)看看在Dooring中的實(shí)現(xiàn)效果.
以上就是用戶(hù)基于后臺(tái)采集到的數(shù)據(jù), 一鍵導(dǎo)出excel文件的流程, 最后一張圖是生成的excel文件在office軟件中的呈現(xiàn).
一鍵導(dǎo)出功能主要用在H5-Dooring的后臺(tái)管理頁(yè)面中, 為用戶(hù)提供方便的導(dǎo)出數(shù)據(jù)能力. 我們這里導(dǎo)出功能也依然能使用xlsx來(lái)實(shí)現(xiàn), 但是綜合對(duì)比了一下筆者發(fā)現(xiàn)有更簡(jiǎn)單的方案, 接下來(lái)筆者會(huì)詳細(xì)介紹, 首先我們還是來(lái)看一下流程:
很明顯我們的導(dǎo)出流程比導(dǎo)入流程簡(jiǎn)單很多, 我們只需要將table的數(shù)據(jù)格式反編譯成插件支持的數(shù)據(jù)即可. 這里筆者使用了js-export-excel來(lái)做文件導(dǎo)出, 使用它非常靈活,我們可以自定義: 自定義導(dǎo)出的excel文件名 自定義excel的過(guò)濾字段 * 自定義excel文件中每列的表頭名稱(chēng)
由于js-export-excel支持的數(shù)據(jù)結(jié)構(gòu)是數(shù)組對(duì)象, 所以我們需要花點(diǎn)功夫把table的數(shù)據(jù)轉(zhuǎn)換成數(shù)組對(duì)象, 其中需要注意的是ant的table數(shù)據(jù)結(jié)構(gòu)中鍵對(duì)應(yīng)的值可以是數(shù)組, 但是js-export-excel鍵對(duì)應(yīng)的值是字符串, 所以我們要把數(shù)組轉(zhuǎn)換成字符串,如[a,b,c]變成'a,b,c', 所以我們需要對(duì)數(shù)據(jù)格式進(jìn)行轉(zhuǎn)換, 具體實(shí)現(xiàn)如下:
const generateExcel=()=> {
let option={}; //option代表的就是excel文件
let dataTable=[]; //excel文件中的數(shù)據(jù)內(nèi)容
let len=list.length;
if (len) {
for(let i=0; i<len; i++) {
let row=list[i];
let obj:any={};
for(let key in row) {
if(typeof row[key]==='object') {
let arr=row[key];
obj[key]=arr.map((item:any)=> (typeof item==='object' ? item.label : item)).join(',')
}else {
obj[key]=row[key]
}
}
dataTable.push(obj); //設(shè)置excel中每列所獲取的數(shù)據(jù)源
}
}
let tableKeys=Object.keys(dataTable[0]);
option.fileName=tableName; //excel文件名稱(chēng)
option.datas=[
{
sheetData: dataTable, //excel文件中的數(shù)據(jù)源
sheetName: tableName, //excel文件中sheet頁(yè)名稱(chēng)
sheetFilter: tableKeys, //excel文件中需顯示的列數(shù)據(jù)
sheetHeader: tableKeys, //excel文件中每列的表頭名稱(chēng)
}
]
let toExcel=new ExportJsonExcel(option); //生成excel文件
toExcel.saveExcel(); //下載excel文件
}
注意, 以上筆者實(shí)現(xiàn)的方案對(duì)任何table組件都使用, 可直接使用以上代碼在大多數(shù)場(chǎng)景下使用. 至此, 我們就實(shí)現(xiàn)了使用JavaScript實(shí)現(xiàn)前端導(dǎo)入和導(dǎo)出excel文件的功能.
所以, 今天你又博學(xué)了嗎?
以上教程筆者已經(jīng)集成到H5-Dooring中,對(duì)于一些更復(fù)雜的交互功能,通過(guò)合理的設(shè)計(jì)也是可以實(shí)現(xiàn)的,大家可以自行探索研究。
地址:H5-Dooring | 一款強(qiáng)大的H5編輯器
如果想學(xué)習(xí)更多H5游戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數(shù)據(jù)可視化等前端知識(shí)和實(shí)戰(zhàn),歡迎在《趣談前端》一起學(xué)習(xí)討論,共同探索前端的邊界。
鄒個(gè)人站點(diǎn):http://www.itzoujie.com/
不懂后端的前端不是一個(gè)大前端,不懂后端的前端會(huì)大大限制你的發(fā)展空間,所以小鄒在網(wǎng)上找了一篇不錯(cuò)的文章來(lái)分享給大伙,這里說(shuō)一下,小鄒的個(gè)人站點(diǎn)技術(shù)棧是(node+express+vue+mysql),跟這篇文章的技術(shù)棧略有不同,當(dāng)然站點(diǎn)里面涉及的組件庫(kù)和小程序等,小鄒這里就不一一說(shuō)了。好了,下面直接開(kāi)始分享:
Vue + vuex + element-ui + webpack + nodeJs + koa2 + mongodb
說(shuō)明:
build 文件講解
說(shuō)明:
1.admin - 后臺(tái)管理界面源碼
src - 代碼區(qū)域:
2.client - web端界面源碼
跟后臺(tái)管理界面的結(jié)構(gòu)基本一樣。
3.server - 服務(wù)端源碼
說(shuō)明:
開(kāi)發(fā)中用的一些依賴(lài)模塊
components
這個(gè)文件夾一般放入常用的組件, 比如 Loading組件等等。
views
所有模塊頁(yè)面。
store
vuex 用來(lái)統(tǒng)一管理公用屬性, 和統(tǒng)一管理接口。
登陸
登陸是采用 jsonwebtoken方案 來(lái)實(shí)現(xiàn)整個(gè)流程的。
1. jwt.sign(payload,secretOrPrivateKey,[options,callback]) 生成TOKEN
2. jwt.verify(token,secretOrPublicKey,[options,callback]) 驗(yàn)證TOKEN
3.獲取用戶(hù)的賬號(hào)密碼。
4.通過(guò) jwt.sign 方法來(lái)生成token:
5.每次請(qǐng)求數(shù)據(jù)的時(shí)候通過(guò) jwt.verify 檢測(cè)token的合法性 jwt.verify(token,secret)。
權(quán)限
通過(guò)不同的權(quán)限來(lái)動(dòng)態(tài)修改路由表。
通過(guò) vue的 鉤子函數(shù) beforeEach 來(lái)控制并展示哪些路由, 以及判斷是否需要登陸。
通過(guò)調(diào)用 getUserInfo方法傳入 token 獲取用戶(hù)信息, 后臺(tái)直接解析 token 獲取里面的信息返回給前臺(tái)。
通過(guò)調(diào)用 setRoutes方法 動(dòng)態(tài)生成路由。
axios 請(qǐng)求封裝,統(tǒng)一對(duì)請(qǐng)求進(jìn)行管理
面包屑 / 標(biāo)簽路徑
上面介紹了幾個(gè)主要以及必備的后臺(tái)管理功能,其余的功能模塊 按照需求增加就好
前臺(tái)展示的頁(yè)面跟后臺(tái)管理界面差不多, 也是用vue+webpack搭建,基本的結(jié)構(gòu)都差不多。
權(quán)限
主要是通過(guò) jsonwebtoken 的verify方法檢測(cè) cookie 里面的 token 驗(yàn)證它的合法性。
日志是采用 log4js 來(lái)進(jìn)行管理的, log4js 算 nodeJs 常用的日志處理模塊,用起來(lái)額也比較簡(jiǎn)單。
log4js 的日志分為九個(gè)等級(jí),各個(gè)級(jí)別的名字和權(quán)重如下:
1.圖。
2.設(shè)置 Logger 實(shí)例的類(lèi)型 logger=log4js.getLogger('cheese')。
3.通過(guò) Appender 來(lái)控制文件的 名字、路徑、類(lèi)型 。
4.配置到 log4js.configure。
5.便可通過(guò) logger 上的打印方法 來(lái)輸出日志了 logger.info(JSON.stringify(currTime:當(dāng)前時(shí)間為${Date.now()}s ))。
設(shè)計(jì)思路
當(dāng)應(yīng)用程序啟動(dòng)時(shí)候,讀取指定目錄下的 js 文件,以文件名作為屬性名,掛載在實(shí)例 app 上,然后把文件中的接口函數(shù),擴(kuò)展到文件對(duì)象上。
讀取出來(lái)的便是以下形式:
app.controller.admin.other.markdown_upload_img
便能讀取到 markdown_upload_img 方法。
在把該形式的方法賦值過(guò)去就行:
router.post('/markdown_upload_img',app.controller.admin.other.markdown_upload_img)
通過(guò) mongoose 鏈接 mongodb
封裝返回的send函數(shù)
注意事項(xiàng):
1. cnpm run server 啟動(dòng)服務(wù)器 //沒(méi)裝cnpm的使用npm命令
2.啟動(dòng)時(shí),記得啟動(dòng)mongodb數(shù)據(jù)庫(kù),賬號(hào)密碼 可以在 server/config.js 文件下進(jìn)行配置
3. db.createUser({user:"cd",pwd:"123456",roles:[{role:"readWrite",db:'test'}]})(mongodb 注冊(cè)用戶(hù))
4. cnpm run dev:admin 啟動(dòng)后臺(tái)管理界面
5.登錄后臺(tái)管理界面錄制數(shù)據(jù)
6.登錄后臺(tái)管理時(shí)需要在數(shù)據(jù)庫(kù) 創(chuàng)建 users 集合注冊(cè)一個(gè)賬號(hào)進(jìn)行登錄
7. cnpm run dev:client 啟動(dòng)前臺(tái)頁(yè)面
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。