特斯拉 Model S 自駕模式「autopilot」將於 3 個月內推出

特斯拉執行長 Elon Musk 透露未來將透過 7.0 版本升級,為 Model S 車款帶來全新自動駕駛(self-driving)模式「autopilot」,預計在 3 至 4 個月內釋出軟體更新。  
  在新聞發佈會上,Elon Musk 公佈下一波 6.2 版本升級,新增里程保證(Range Assurance)和旅程規劃(Trip Planner)兩大關鍵功能。里程保證在於行駛過程中,系統會背景監控電力狀況並即時告知車主;旅程規劃則是在車主設定目的地之後,系統自動判斷行駛過程中需要充電的地點,規劃出最佳路線,這都是為了減輕部分車主的「里程焦慮」(Range Anxiety)問題。除了上述新功能之外,Elon Musk 還介紹了一些和主動安全相關的輔助功能,例如自動緊急剎車、盲區警告以及側面碰撞警告等。   不過,新聞發佈會上最令人興奮的是,Elon Musk 透露未來將透過 7.0 版本升級,為 Model S 車款帶來全新自駕模式「autopilot」。   Elon Musk 指出,擁有 Model S 車款的車主基本上可透過 autopilot 模式,做到往返舊金山和西雅圖之間無須任何操控動作。不過他也謹慎地表示,這還不算是真正的自動駕駛技術,只不過是強大的自動轉向系統。autopilot 不足之處,在於它僅適用於行駛在高速公路上,以該公司目前的技​​術,可能還無法安全地駛入郊區,畢竟街上難免還是會有孩童或路人竄出。欲使用 autopilot 模式,車主還需要選配特斯拉所提供價值 4,250 美元的 optional tech 方案。     本文全文授權轉載自《科技新報》─〈〉

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

上海環保計畫出爐 新能源車將達1.3萬輛

19日,上海市政府官網發佈了《上海市2015年-2017年環境保護和建設三年行動計畫》。   上海在計畫中提出將大力推廣新能源汽車,到2015年累計推廣新能源汽車1.3萬輛,2017年進一步推廣。在公車、環境衛生、計程車等產業和政府機關,新增或更新的公車中新能源和清潔燃料車的比例達60%以上。上海還將實施集裝箱運輸車隊清潔能源試點,推廣應用LNG集裝箱運輸車輛1000輛以上。加快充電樁、加氣站等配套設施建設,2015年底前累計建成6000個充電樁。   此外,計畫還提出了一系列具體目標,包括:到2017年細顆粒物(PM2.5)年均濃度比2013年下降20%左右;到2017年上海飲用水水源地水質實現達標,重要水功能區主要水質達成率(扣除上游來水)達60%;城市森林覆蓋率達15.5%,上海全市城鎮汙水處理率達90%以上,生活垃圾無害化處理率達100%,農藥化肥施用強度下降10%。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

特斯拉更新軟體 不再擔心電動車電量問題

特斯拉(Tesla)執行長 Elon Musk 日前才剛透過 Twitter 宣稱,他要終結特斯拉電動車主的「里程焦慮」(range anxiety,就是車主擔心電動車上路後會面臨電量不夠的問題),這顯然不是說說而已。特斯拉 19 日發布了 Model S 電動轎車軟體更新「Version 6.2」,Musk 更誇下海口,宣稱本次更新可讓 Model S 車主不需擔心電量問題!   Musk 19 日在對記者召開的電話會議上表示,Version 6.2 多了「里程保險」(range assurance)的程式,這項程式能夠與特斯拉的超級充電站溝通,在汽車快要沒電之際對車主示警,然後找到最近的充電站。   Version 6.2 另一個重要更新則是「旅程規劃」程式,可將超級充電站、Model S 與導航系統的網絡全面整合,為車主設計出最佳的長途旅行路線。也就是說,Model S 的系統會隨時確認目前的地理位置、最接近的超級充電站、電池所剩電量以及距離目的地還有多遠。Version 6.2 預計 2 週內就能正式釋出。    

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※新北清潔公司,居家、辦公、裝潢細清專業服務

這些新能源汽車 保證你一見到就心動!

人類在能源探索的道路上從未止步,不論是迫于傳統能源殆盡的危機,還是脫困於大氣污染迫切要求,新一輪的能源挑戰已經開始。這是一場腦洞大開的遊戲,無論是專業的汽車廠家還是奇思妙想的技術達人都紛紛接招,用或精於科技或詼諧幽默的方式,帶給我們一場奇幻的新能源之旅。  
1 、雪佛蘭EN-V    

通用日前發佈了一款名為雪佛蘭EN-V或者Electric Networked-Vehicle)的新電動概念車。這款概念車配備了兩個座椅,能在尖端衛星導航和感測器系統的説明下自主駕駛。該車配備了一個全電動的鋰離子動力傳動系統,能提供大約40公里的最大續航里程。此外,這款概念車還採用了未來感十足的車身設計和溫度控制系統。而一系列感測器和GPS驅動技術,使得這款EN-V能夠自主駕駛。  
2、標緻Shoo

  標緻Shoo是最具未來派色彩的太陽能概念車之一,其最大特色就是三角形外形設計和為發動機提供能量的太陽能電池板車頂。車頂上配置了太陽能面板將太陽能轉化成為電能,進而驅動該車的電動馬達行駛。依靠綠色能源行駛,綠色環保。而三角形設計,又相對穩定,同樣也讓該車擁有更多充裕的內部空間。   
3、日產Pivo

  日產汽車展出電動車Pivo。這款概念車以鋰電池驅動,座艙能360度旋轉,可適應駕駛人的全方位需求。Pivo最特別的地方是車廂可做180度旋轉,當你駕駛Pivo時,從此不用再倒車入庫,只要將車頭做180度旋轉,即可正向開車入庫。同時,Pivo的車廂和車架可以分離。   
4、AntroSolo

  匈牙利人研製的Antro Solo利用太陽能與汽電混合動力,燃燒每加侖(約合3.8升)汽油可行駛150英里(約合241公里),可謂一個驚人數字。天氣狀況良好時,車頂上的太陽能電池板提供的能量足以讓AntroSolo行駛15至25公里。當碰到多雲天氣,Antro Solo會預設使用一小型電動引擎或者由所搭載的乘客踩下腳踏開關。   
5、科尼賽克Quant

  位於瑞典的超級跑車製造商已研製出一款名為「Quant」的混合動力概念車——將太陽能和黃鐵礦(又名「愚人金」)這兩種最不可能「捆綁」在一起的能源加以混合。科尼賽克發言人表示,Quant的行駛距離可達到300英里(約合482公里),完全充電時間只有20分鐘。   
6、Jetcar

德國東部Neuruppin,電動汽車Jetcar設計者開著這輛電動汽車。這輛車子是電池提供動力,時速可達到160公里。  
7、Nissan終極智能燒烤車

  最後一款是吃貨的福音啦!所有人都愛燒烤,但清理現場又十分麻煩。現在問題解決了,Nissan推出了一款全新終極智慧燒烤車。這台車採用純電力驅動設計。為滿足燒烤需求,該車特別搭配了一台1500瓦的車載電源。車頂上的「人工蚊帳」系統可發射出半徑超聲波和防蟲香熏,能避免燒烤時蚊蟲干擾。    同時,這台終極智慧燒烤車還配有一台電視顯示幕,使用者可自行連接智慧手機看視頻或K歌。最為重要的是——當燒烤結束後,汽車內部自帶的垃圾處理箱和車載迷你接收器可以協助車主清理垃圾。   文/聰捕頭   文章來源:自媒體「排氣管」

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※幫你省時又省力,新北清潔一流服務好口碑

※別再煩惱如何寫文案,掌握八大原則!

鴻海攜手騰訊、和諧汽車 打造互聯網智慧電動車

鴻海於 3 月 23 日宣布,將與騰訊、和諧汽車攜手簽訂「互聯網+智慧電動車」戰略合作協議,預計選擇中國河南省鄭州市積極展開此項領域創新發展。   鴻海將與騰訊及和諧汽車等三方共同合組專業工作團隊,藉由騰訊在互聯網應用發展的深入洞見,以及互聯網創意開放平台,進一步搭配鴻海在高科技行動裝置、智慧電動車的創新整合設計與生產製造技術,打造高效便捷且節能環保、安全可靠的「互聯網+智慧電動車」。同時,後續也將借重和諧汽車在高階汽車車款營銷及服務領域的領先優勢,共同提出可行的「互聯網+ 智慧電動車」共贏商業模式。   而在 2014 年年底期間,鴻海已與和諧汽車達成協議,將由鴻海向和諧汽車提供增資,並且持有其 11.76% 股權,同時針對心能源與電動車製造相關技術投資。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

增長率為76% 全球電動車市場達74萬輛車

德國Baden-Württemberg省的太陽能和氫能研究中心(ZSW)日前發佈的一份報告透露,全球電動汽車市場目前已達74萬輛車,其中幾乎有一半(32萬)註冊於2014年。基於電動車約為76%的增長率,去年汽車電池供應商的收益為20億歐元。   其中,美國市場增長69%,本土道路上的電動汽車數量增至29萬輛,占全球的三分之一。而中國是世界上第三最強大的電動車市場,2014年增加了約5萬4千輛,增長了120%,全國道路上接近有10萬輛電動車,僅次於擁有11萬電動車(2014年45%的速度增長)的日本。   該德國中心發現,這三個主要國家的扶持政策説明加速電動汽車的採用。在中國,例如,國產電動車是被補貼的,對終端消費者來講比較便宜。而德國相反,沒有市場激勵機制,從而只有11700新車註冊。   此外,該報告還發現,日產的Leaf是最流行的電動車品牌,創下了自2010年以來15萬的全球註冊記錄。第二是通用汽車公司的雪佛蘭Volt,全球註冊75000輛,第三為6萬註冊量的豐田Prius。而特斯拉S型已售出5萬輛,遙遙領先15000輛的寶馬的i3,事實上,i3才在市場上超過12個月,因此在這麼短時間內已具有這樣的市場份額,是令人印象深刻的。   2012年和2014年之間新車註冊數量每年增加兩倍。“如果近幾年的勢頭依然不減,在短短幾個月的時間裡,全球電動車的數量將超過百萬。”ZSW電化學能源技術事業部主任Werner Tillmetz表示。 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

Day12-微信小程序實戰-交友小程序-搭建服務器與上傳文件到後端並控制雲開發數據庫-項目總結與github代碼發布流程(附上項目全部完整代碼學習使用)

要搞一個小型的cms內容發布系統

因為小程序上線之後,直接對數據庫進行操作的話,慧出問題的,所以一般都會做一個管理系統,讓工作人員通過這個管理系統來對這個數據庫進行增刪改查

微信小程序其實給我們提供了這樣的能力了

 

 

 (也就是可以在自己已有的服務器來進行雲操作,所以就可以通過這個CMS內容管理系統來對雲數據庫進行修改)

我們就要建立自己的web服務器–》搭建一個簡易的服務器

https://koa.bootcss.com/

這個是要node版本是7以上,可以在node官網去搭建,我這邊之前按照過了,直接cmd打開,通過 node -v查看版本

 

然後還要下載一個 cnpm,這個主要是下載第三方模塊用的

 

 https://www.cnblogs.com/biglovevolcaner/p/6707746.html

打開cmd,直接輸入這位大佬博客裏面的語句進行安裝即可了

這些都準備好了之後,就可以開始koa2的服務器搭建了

 

我們選擇koa的腳手架 koa-generator

https://blog.csdn.net/sinat_39049092/article/details/104575018

(跟這個博客到第三步就行)

然後我們就可以到想要搭建系統的文件中(我在d盤新建了一個weapp文件)

在cmd中輸入 D:\weapp 之後輸入 d:即可跳轉

輸入 koa2 miaomiao-cms -e

(後面的-e表示的是選擇ejs模板)

 

然後安裝提示,我們進入到這個建立的東西 cd miaomiao-cms

然後安裝一些初始的模塊

 

 

 輸入 cnpm i

 

 

 

創立完之後,就可以去啟動了,我們通過 npm start  

 

 

 啟動好之後,我們在網頁中 輸入 localhost:3000

 

 

 如果看到了這個界面的話,說明web服務器就已經搭建好了,就可以在這個web服務器下做一個簡易的cms系統了

之後就可以在d盤找到這個文件了

 

 

 其中的public主要是放一些靜態資源的

在vscode裏面打開我們的文件

這個index其實就是類似於可以在前端显示的

 

實現引入 axios.min.js 可以通過npm安裝,也可以使用網上開源的

<script src=“https://unpkg.com/axios/dist/axios.min.js”></script>

通過設置:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  </head>
  <body>
    <h1><%= title %></h1>
    <p>EJS Welcome to <%= title %></p>
    <label for="">
      上傳圖片 : <input type="file" id="uploadBtn">
    </label>
  </body>
</html>

我們可以看到

 

 

 注意:假如網頁打不開,或者是沒更新出現的html結構的話,就重新的在這個miaomiao.cms下面 npm start重新打開

隨便選一張圖片,onchange就是只要選擇了圖片的話,就會觸發這個事件了,file就是拿到的我們上傳的文件了

拿到這個圖片要怎麼傳輸給後台呢,這個時候就要進行文件操作了FormData這個對象來實現了

通過append 給這個param對象添加一個key為file value為 。也就是通過這個append來產生一個鍵值對

然後把這個對象通過axios來傳輸到後端

 

這就是axios中傳輸給後端文件的代碼 

在傳輸之前,先對 config 配置文件 進行設置,告訴我們後端這個是一個文件數據流

 

 配置好了之後,就可以通過post把圖片傳輸給後台的接口 uploadBannerImg

通過下面的代碼

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  </head>
  <body>
    <h1>與你相遇-CMS管理系統</h1>
    <label for="">
      上傳圖片 : <input type="file" id="uploadBtn">
    </label>

    <script>
      var uploadBtn = document.getElementById('uploadBtn');
      uploadBtn.onchange = function(ev){
        var file = ev.target.files[0];
        var param = new FormData();
        param.append('file' , file);

        var config = {
          headers : {
            'Content-Type' : 'multipart/form-data'
          }
        };

        axios.post('/uploadBannerImg' , param , config).then((res)=>{
          console.log( res.data );
        });
      };
    </script>
  </body>
</html>

然後就是開始搞 定義 uploadBannerImg 這個接口了

在routes-》index.js裏面,添加上這個代碼

router.post('/uploadBannerImg' , async(ctx , next)=>{
  var files = ctx.request.files;
  console.log( files );

})

 

 

 我們添加一個圖片,然後可以看到在後端中

 

 

 會發現404了,我們再通過 npm start來開啟

先要結束上面的操作,通過 ctrl+c 彈出

 

 

 然後輸入y之後,通過npm start,然後再次上傳圖片

 

 

 打印出來了這個,說明file為undefined 也就是沒拿到這個圖片了

這個是因為koa默認是得不到我們上傳文件的東西的,還需要下載一個第三方的模塊來輔助完成這個功能才行

通過在miaomiao-cms目錄下的cmd 輸入  cnpm i -S koa-body

 

下載好了之後,在app.js裏面,引入koa-body

const koaBody = require('koa-body')

然後在app.js裏面做一個簡單的配置

app.use(koaBody({
  multipart : true,//指定是否可以上傳多張
  formidable : {
    maxFileSize : 200*1024*1024   //設置上傳文件大小最大限制,默認2M
  }
}))

(不配置這個,用默認的也是可以的)

搞好之後,再把項目 npm start啟動一下

上傳圖片之後,還是显示 undefined

 

 

 原因就是index.js裏面的files少了一個s

 二、把拿到的文件上傳到雲開發中

c

 

 這裏的use多了一個r

 把這兩個代碼書寫錯誤改好了之後,再上傳就可以看到結果了

 

所以就實現了把圖片傳給後台了,然後我們就要把這個信息傳給雲平台了(以上完成了前台的文件傳輸到了後台)

 https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/uploadFile.html

通過:

POST https://api.weixin.qq.com/tcb/uploadfile?access_token=ACCESS_TOKEN

通過這個代碼其實是進行身份驗證拿到一個通行證Token,才可以使用這樣的功能

 

https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/uploadFile.html

通過:

GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

可見它需要的是APP 的id還有密鑰,這兩個都可以在

https://mp.weixin.qq.com/wxamp/wxaalarm/get_jserr?token=590850009&lang=zh_CN 

開發-》開發設置(就可以拿到id和密鑰了)

兩個都拿到的話,就可以通過get來獲得Token了,然後再用post即可了

 

首先在

 

在外層寫一個配置文件,因為這個id和密鑰都是比較隱私的,為了不讓其他人看到的話,最好就是寫一個配置文件了

 

 

把用戶名和密鑰都寫到這個配置文件中去,然後開始打碼

先在config.js裏面提供一個對外接口

(裏面的數據寫入自己的即可) 

module.exports = {
    appid : '',
    secret : ''
};

然後在index.js裏面引入這個配置文件

const config = require('./config.js');

然後在koa2中,我們用的是request和request-promise,這樣的一些第三方的模塊,如果要安裝的話,可以在github裏面看看

https://github.com/request/request-promise

 

然後我們把後台關掉,開始下載一下這些東西

輸入 cnpm i -S request request-promise 

 就可以安裝這兩個東西了

 

 就可以看到已經下載成功,我們就可以開始使用了

const request = require('request-promise');

還有一個內置的fs用來操作文件的模塊,我們可以直接引入,就不用下載了

const fs = require('fs');

 

然後在路由的index.js文件中的router.post裏面添加:

  try{
    let options = {
      uri: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' +
      config.appid + '&secret=' + config.secret + '',
      json : true
    }
    let {access_token} = await request(options)
    console.log( access_token );
  } catch(err){
    console.log(err.stack)
  }

但是出現了報錯

 

 

 少了一個點,要。。/才行

 

 

 

 這樣的話我們就拿到了access_token了(注意 哪個密匙的話最好用最新的,重新更新一下不然可能調用失敗的)

得到這個access_token之後我們就可以用post請求了來得到我們要用到的信息

 

 

 這個env就是指定了雲環境id ,我們這裏通過一個date設置時間戳的文件地址給filepath ,然後我們就把options拿去請求了,請求成功的話就返回賦值給res

這個res包括什麼,可以在微信開發文檔裏面看到的

 

 

 拿到這些數據之後,就要調用下一個接口了,來返回最新的數據

注意有些參數 是 uri 而不是url的

然後把我們res拿到的值映射到,下面這些參數中去

 

 

 

const router = require('koa-router')()
const config = require('../config.js');
const request = require('request-promise');
const fs = require('fs');
router.get('/', async (ctx, next) => {
  await ctx.render('index', {
    title: 'Hello Koa 2!'
  })
})

router.get('/string', async (ctx, next) => {
  ctx.body = 'koa2 string'
})

router.get('/json', async (ctx, next) => {
  ctx.body = {
    title: 'koa2 json'
  }
})

router.post('/uploadBannerImg' , async(ctx , next)=>{
  // console.log( ctx.request )
  var files = ctx.request.files;

  // console.log( files );

  try{
    let options = {
      uri: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='+config.appid + '&secret=' + config.secret + '',
      json : true
    }
    let {access_token} = await request(options);
    // console.log( access_token );
    let fileName = `${Date.now()}.jpg`;
    let filePath = `banner/${fileName}`;
    options = {
      method : 'POST',
      uri : 'https://api.weixin.qq.com/tcb/uploadfile?access_token=' + access_token + '',
      body : {
        "env" : 'gogocj-6skcv',
        "path" : filePath,
      },
      json : true
    }
    let res = await request(options);
    options =  {
      method : 'POST',
      uri : res.url,
      formData : {
        "Signature" : res.authorization ,
        "key" : filePath,
        "x-cos-security-token" : res.token,
        "x-cos-meta-fileid" : res.cos_file_id,
        "file" : {
          value : fs.createReadStream(file.path),
          options : {
            filename : fileName,
            contentType : file.type
          }
        }
      }
    }
    await request(options);
    ctx.body = res;
  } catch(err){
    console.log(err.stack)
  }

})

module.exports = router

綜上所述其實我們要調用三個接口,先用get來拿到我們的token,然後通過post來拿到我們其他上傳的具體信息,然後通過這些res的具體信息來調用另外一個接口賴完成最終上傳的任務

 

 

 但是我們在雲開發中 查看存儲的時候,並沒有看到我們上傳過來的東西(最後就是在前端也加上一些提示)就不用來看數據庫了

在數據庫的存儲中沒有生成 banner

上面黑圖中,後面其實都是一些報錯的

 

 

 這裏少了一句對file進行定義的語句了,寫上之後,全部的報錯都消失了

 

 

 然後在雲開發的存儲中:

 

 

 就上傳成功了

POST https://api.weixin.qq.com/tcb/databaseadd?access_token=ACCESS_TOKEN

這樣也是通過傳入access_token 來傳入

 

 

 

 

 

 所以以上就實現了在web服務器端把圖片上傳到雲開發的存儲中,但是我們的目的是要在前端在banner中把這個圖片放在輪播圖上的,但是無法直接從存儲中讀取出來,要把存儲文件的這個id寫入到數據庫中(表單中)

我們在雲開發的數據庫中新建一個叫做 banner 的集合

也就是說不僅要上傳到雲開發的存儲中,還要上傳到這個banner集合中

查看開發文檔:

https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseAdd.html

const router = require('koa-router')()
const config = require('../config.js');
const request = require('request-promise');
const fs = require('fs');
router.get('/', async (ctx, next) => {
  await ctx.render('index', {
    title: 'Hello Koa 2!'
  })
})

router.get('/string', async (ctx, next) => {
  ctx.body = 'koa2 string'
})

router.get('/json', async (ctx, next) => {
  ctx.body = {
    title: 'koa2 json'
  }
})

router.post('/uploadBannerImg' , async(ctx , next)=>{
  // console.log( ctx.request )
  var files = ctx.request.files;
  var file = files.file;//這個file就是文件的一個二進制的數據了
  // console.log( files );

  try{
    let options = {
      uri: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='+config.appid + '&secret=' + config.secret + '',
      json : true
    }
    let {access_token} = await request(options);
    // console.log( access_token );
    let fileName = `${Date.now()}.jpg`;
    let filePath = `banner/${fileName}`;
    options = {
      method : 'POST',
      uri : 'https://api.weixin.qq.com/tcb/uploadfile?access_token=' + access_token + '',
      body : {
        "env" : 'gogocj-6skcv',
        "path" : filePath,
      },
      json : true
    }
    let res = await request(options);
    let file_id = res.file_id;
    options = {
      method : 'POST',
      uri : 'https://api.weixin.qq.com/tcb/databaseadd?access_token=' + access_token + '',
      body : {
        "env" : 'gogocj-6skcv',
        "query" : "db.collection(\"banner\").add({data:{fileId:\""+ file_id+"\"}})"
      },
      json : true

    }

    await request(options)

    options =  {
      method : 'POST',
      uri : res.url,
      formData : {
        "Signature" : res.authorization ,
        "key" : filePath,
        "x-cos-security-token" : res.token,
        "x-cos-meta-fileid" : res.cos_file_id,
        "file" : {
          value : fs.createReadStream(file.path),
          options : {
            filename : fileName,
            contentType : file.type
          }
        }
      }
    }
    await request(options);
    ctx.body = res;
  } catch(err){
    console.log(err.stack)
  }

})

module.exports = router

router/index.js

 

我們再次上傳的時候,就發現語句寫入到banner這個集合裏面了

然後我們再上傳第二張圖片試試

 可以看到也是上傳成功的了,這兩條數據都是比較簡單的,保存的就只是一個fileId的

然後就可以回到微信開發者工具去打代碼了,就可以直接讀取banner這個集合裏面的圖片了

在index.js裏面對那個imgurl進行操作

其實可以在getBannerList函數裏面定義我們從集合中限制拿幾張圖片的

(注意記得給這個banner數據庫集合設置 好權限,不然可能就訪問不到了

在index.js裏面的onready中觸發這個函數

  getBannerList(){
    db.collection('banner').get().then((res)=>{
      console.log( res.data );
    });
  }

通過這個,我們打印出東西來看看

 

然後我們就可以把得到的數組映射到data裏面的imgUrl即可了

然後還要在wxml中,把src變成是item.fileId才行

 

 所以通過代碼:

  getBannerList(){
    db.collection('banner').get().then((res)=>{
      // console.log( res.data );
      this.setData({
        imgUrls : res.data
      });
    });
  }
<block wx:for="{{imgUrls}}" wx:key="{{index}}">
          <swiper-item>
            <image  src="{{item.fileId}}"  ></image>
          </swiper-item>
        </block>

得到的效果就是:

 

 

 這兩個圖片就是我們通過cms內容管理系統上傳的圖片了

其實雖然這個系統實現的功能就一個,但是是可以擴展的,比如用來管理用戶,就是用戶的頭像如果是違規的話

或者是發布一些系統的消息或者是公告的東西了(就是好友消息和系統消息都是可以有的,然後做一個好友消息和系統消息切換的分支即可)

 

 以上就完成了這個項目的初始內容了,下面就是通過預覽,或者是通過真機調試(實時監聽用戶的操作)所以在調試完了之後,就是發布了,發布就是點擊上傳按鈕

上傳代碼完成之後,就可以在微信公眾平台,打開版本管理,可以先不用上傳審核,而是變成是一個體驗的版本,就可以得到一個二維碼了

這個體驗的權限就是通過(成員管理-》體驗成員設置,

當體驗的感覺沒問題之後,就可以提交審核了(如果審核不通過,就可能使banner中的圖片和我們餓內容使不符合的,就使要把這個小程序改成和實際差不多的再進行提交審核才行的

審核通過之後就會生成一個線上版本,這樣的話如何的用戶都可以進行訪問了

以上就是小程序發布的流程了的

 

下面就是把代碼上傳到github中進行共享,我們把cms的文件和這個小程序的代碼文件放一起

文件放一起之後,就可以打開gitbub進行上傳了

如何我們通過git插件來上傳的,可以下載一個git插件

https://git-scm.com/downloads

如然後在要上傳的文件裏面,右鍵點擊git bash

 

 

可以在這個頁面中查看我們如何通過git插件來實現代碼的上傳的了

 

https://github.com/gogocj/wxproject-miaomiao

 

 

 

 

 

 

 也就是點開git工具,然後輸入 git init

然後查看狀態 git status

然後就是 git add .  (注意後面是一個空格然後一個點)

然後就是 git commit -m “up 1”

上傳好了之後,就可以通過git status 來看看我們是否已經上傳成功了

之後就可以設置一下遠端了(remote)

輸入:git remote add origin https://github.com/gogocj/wxproject-miaomiao.git

上傳完畢之後,刷新一下就可以看到上傳的東西了

 

 

 

 可以看到我們上傳的東西都在這裏了,但是蝦米那的這個README.md其實是小程序中默認的,我們可以修改一下的

可以直接在github裏面對這個文件在線的編輯

 

 https://github.com/gogocj/wxproject-miaomiao

這就是我上傳到github上面的代碼了

 感謝大家!

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

使用Apache Hudi構建大規模、事務性數據湖

一個近期由Hudi PMC & Uber Senior Engineering Manager Nishith Agarwal分享的Talk

關於Nishith Agarwal更詳細的介紹,主要從事數據方面的工作,包括攝取標準化,數據湖原語等。

什麼是數據湖?數據湖是一個集中式的存儲,允許以任意規模存儲結構化和非結構化數據。你可以存儲原始數據,而不需要先轉化為結構化的數據,基於數據湖之上可以運行多種類型的分析,如dashboard、大數據處理的可視化、實時分析、機器學習等。

接着看看對於構建PB級數據湖有哪些關鍵的要求

第一個要求:增量攝取(CDC)

企業中高價值的數據往往存儲在OLTP中,例如下圖中,users表包含用戶ID,國家/地區,修改時間和其他詳細信息,但OLTP系統並未針對大批量分析進行優化,因此可能需要引入數據湖。同時一些企業採用備份在線數據庫的方式,並將其存儲到數據湖中的方法來攝取數據,但這種方式無法擴展,同時它給上游數據庫增加了沉重的負擔,也導致數據重寫的浪費,因此需要一種增量攝取數據的方法。

第二個要求:Log Event去重

考慮分析大規模時間序列數據的場景,這些事件被寫入數據管道,並且數量非常大,可達數十億,每秒可達百萬的量。但流中可能有重複項,可能是由於至少一次(atleast-once)保證,數據管道或客戶端失敗重試處理等發送了重複的事件,如果不對日誌流進行重複處理,則對這些數據集進行的分析會有正確性問題。下圖是一個示例日誌事件流,其中事件ID為唯一鍵,帶有事件時間和其他有效負載。

第三個要求:存儲管理(自動管理DFS上文件)

我們已經了解了如何攝取數據,那麼如何管理數據的存儲以擴展整個生態系統呢?其中小文件是個大問題,它們會導致查詢引擎的開銷並增加文件系統元數據的壓力。而如果寫入較大的文件,則可能導致攝取延遲增加。一種常見的策略是先攝取小文件,然後再進行合併,這種方法沒有標準,並且在某些情況下是非原子行為,會導致一致性問題。無論如何,當我們寫小文件並且在合併這些文件之前,查詢性能都會受到影響。

第四個要求:事務寫(ACID能力)

傳統數據湖在數據寫入時的事務性方面做得不太好,但隨着越來越多的業務關鍵處理流程移至數據湖,情況也在發生變化,我們需要一種機制來原子地發布一批數據,即僅保存有效數據,部分失敗必須回滾而不會損壞已有數據集。同時查詢的結果必須是可重複的,查詢端看不到任何部分提取的數據,任何提交的數據都必須可靠地寫入。Hudi提供了強大的ACID能力。

第五個要求:更快地派生/ETL數據(增量處理)

僅僅能快速攝取數據還不夠,我們還需要具有計算派生數據的能力,沒有這個能力,數據工程師通常會繞過原始表來構建其派生/ETL並最終破壞整個體繫結構。下面示例中,我們看到原始付款表(貨幣未標準化)和發生貨幣轉換的派生表。

擴展此類數據管道時很有挑戰,如僅對變更進行計算,或者基於窗口的Join的挑戰。對基礎數據集進行大規模重新處理不太可能,這會浪費計算資源。需要在數據湖上進行抽象以支持對上游表中已更改的行(數據)進行智能計算。

第六個要求:法律合規/數據刪除(更新&刪除)

近年來隨着新的數據保護法規生效,對數據保留有了嚴格的規定,需要刪除原始記錄,修複數據的正確性等,當需要在PB級數據湖中高效執行合規性時非常困難,如同大海撈針一般,需要高效的刪除,如進行索引,對掃描進行優化,將刪除記錄有效地傳播到下游表的機制。

要求回顧(匯總)

  • 支持增量數據庫變更日誌攝取。
  • 從日誌事件中刪除所有重複項。
  • Data Lake必須為其數據集提供有效的存儲管理
  • 支持事務寫入
  • 必須提供嚴格的SLA,以確保原始表和派生表的數據新鮮度
  • 任何數據合規性需求都需要得到有效的支持
  • 支持唯一鍵約束
  • 有效處理遲到的數據

有沒有能滿足上面所有需求的系統呢?接下來我們引入Apache Hudi,HUDI代表Hadoop Upserts Deletes and Incrementals。從高層次講,HUDI允許消費數據庫和kafa事件中的變更事件,也可以增量消費其他HUDI數據集中的變更事件,並將其提取到存儲在Hadoop兼容,如HDFS和雲存儲中。在讀取方面,它提供3種不同的視圖:增量視圖,快照視圖和實時視圖。

HUDI支持2種存儲格式:“寫時複製”和“讀時合併”。

首先來看看寫時複製。如下圖所示,HUDI管理了數據集,並嘗試將一批數據寫入數據湖,HUDI維護稱為“提交時間軸(commit timeline)”的內容,以跟蹤HUDI管理的數據集上發生的操作/更改,它在提交時間軸上標記了一個“inflight”文件,表示操作已開始,HUDI會寫2個parquet文件,然後將“inflight”文件標記為已完成,這從原子上使該新數據寫入HUDI管理的數據集中,並可用於查詢。正如我們提到的,RO視圖優化查詢性能,並提供parquet的基本原始列存性能,無需增加任何額外成本。
現在假設需要更新另一批數據,HUDI在提交時間軸上標記了一個“inflight”文件,並開始合併這些更新並重寫Parquet File1。此時,由於提交仍在進行中,因此用戶看不到正在寫入任何這些更新(這就是我們稱為“快照隔離”)。最終以原子方式發布提交后,就可以查詢版本為C2的新合併的parquet文件。

COW已經在Uber投入運行多年,大多數數據集都位於COW存儲類型上。

儘管COW服務於我們的大多數用例,但仍有一些因素值得我們關注。以Uber的行程表為例,可以想象這可能是一個很大的表,它在旅程的整個生命周期中獲取大量更新。每隔30分鐘,我們就會獲得一組新旅行以及對舊旅行的一些更新,在Hive上的旅行數據是按天劃分分區的,因此新旅行最終會在最新分區中寫入新文件,而某些更新會在舊分區中寫入文件。使用COW,我們只能重寫那些更新所涉及的文件,並且能夠高效地更新。由於COW最終會重寫某些文件,因此可以像合併和重寫該數據一樣快。在該用例中通常大於15分鐘。再來看另外一種情況,由於某些業務用例(例如GDPR),必須更新大量歷史行程,這些更新涉及過去幾個月數據,從而導致很高的寫入延遲,並一遍又一遍地重寫大量數據,寫放大也會導致大量的IO。若為工作負載分配的資源不足,可能就會嚴重損害攝取延遲。

在真實場景中,會將ETL鏈接在一起來構建數據管道,問題會變得更加複雜。

對問題進行總結如下:在COW中,太多的更新(尤其是雜亂的跨分區/文件)會嚴重影響提取延遲(由於作業運行時間較長且無法追趕上入流量),同時還會引起巨大的寫放大,從而影響HDFS(相同文件的48個版本+過多的IO)。合併更新和重寫parquet文件會限制我們的數據的新鮮度,因為完成此類工作需要時間 = (重寫parquet文件所花費的時間*parquet文件的數量)/(并行性)。

在COW中,我們實際上並沒有太大的parquet文件,因為即使只有一行更新也可能要重寫整個文件,因為Hudi會選擇寫入小於預期大小的文件。

MergeOnRead將所有這些更新分組到一個文件中,然後在稍後的時刻創建一個新版本。對於重更新的表,重寫大文件會導致開銷變大。

如何解決上述寫放大問題呢?除了將更新合併並重寫parquet文件之外,我們將更新寫入增量文件中,這可以幫助我們降低攝取延遲並獲得更好的新鮮度。

將更新寫入增量文件將需要在讀取端做額外的工作以便能夠讀取增量文件中記錄,這意味着我們需要構建更智能,更智能的讀取端。

首先來看看寫時複製。如下圖所示,HUDI管理了數據集,並嘗試將一批數據寫入數據湖,HUDI維護稱為“提交時間軸(commit timeline)”的內容,以跟蹤HUDI管理的數據集上發生的操作/更改,它在提交時間軸上標記了一個“inflight”文件,表示操作已開始,HUDI會寫2個parquet文件,然後將“inflight”文件標記為已完成,這從原子上使該新數據寫入HUDI管理的數據集中,並可用於查詢。正如我們提到的,RO視圖優化查詢性能,並提供parquet的基本原始列存性能,無需增加任何額外成本。

現在需要進行第二次更新,與合併和重寫新的parquet文件(如在COW中一樣)不同,這些更新被寫到與基礎parquet文件對應的增量文件中。RO視圖繼續查詢parquet文件(過時的數據),而RealTime View(Snapshot query)會合併了parquet中的數據和增量文件中的更新,以提供最新數據的視圖。可以看到,MOR是在查詢執行時間與較低攝取延遲之間的一個權衡。

那麼,為什麼我們要異步運行壓縮?我們實現了MERGE_ON_READ來提高數據攝取速度,我們希望儘快攝取較新的數據。而合併更新和創建列式文件是Hudi數據攝取的主要耗時部分。

因此我們引入了異步Compaction步驟,該步驟可以與數據攝取同時運行,減少數據攝取延遲。

Hudi將事務引入到了大規模數據處理中,實際上,我們是最早這樣做的系統之一,最近,它已通過其他項目的類似方法獲得了社區認可。

Hudi支持多行多分區的原子性提交,Hudi維護一個特殊的文件夾.hoodie,在該文件夾中記錄以單調遞增的時間戳表示的操作,Hudi使用此文件夾以原子方式公開已提交的操作;發生的部分故障會透明地回滾,並且不會影響讀者和後面的寫入;Hudi使用MVCC模型將讀取與併發攝取和壓縮隔離開來;Hudi提交協議和DFS存儲保證了數據的持久寫入。

下面介紹Hudi在Uber的使用情況

Hudi管理了超過150PB數據湖,超過10000張表,每天攝入5000億條記錄。

接着看看Hudi如何替代分析架構。利用Hudi的upsert原語,可以在攝取到數據湖中時實現<5分鐘的新鮮度,並且能繼續獲得列式數據的原始性能(parquet格式),同時使用Hudi還可以獲得實時視圖,以5-10分鐘的延遲提供dashboard,此外HUDI支持的增量視圖有助於長尾效應對數據集的突變。

為方便用戶能快速使用Hudi,Hudi提供了一些開箱即用的工具,如HoodieDeltaStreamer,在Uber內部,HoodieDeltaStreamer用來對全球網絡進行近實時分析,可用來消費DFS/Kafka中的數據。

除了DeltaStreamer,Hudi還集成了Spark Datasource,也提供了開箱即用的能力,基於Spark,可以快速構建ETL管道,同時也可無縫使用Hudi + PySpark。

接着介紹更高級的原語和特性。

如何從損壞的數據中恢復?例如線上由於bug導致寫入了不正確的數據,或者上游系統將某一列的值標記為null,Hudi也可以很好的處理上述場景,可以將表恢復到最近的一次正確時間,如Hudi提供的savepoint就可以將不同的commit保存起來,用於後續恢復,注意MoR表暫時不支持savepoint;Hudi還提供了文件的版本號,即可以保存多個版本的文件,這對於CoW和MoR表都適用,但是會佔用一些存儲空間。

Hudi還提供便於增量ETL的高級特性,通過Spark/Spark便可以輕鬆增量拉取Hudi表的變更。

除了增量拉取,Hudi也提供了時間旅行特性,同樣通過Spark/Hive便可以輕鬆查詢指定版本的數據,其中對於Hive查詢中指定hoodie.table_name.consume.end.timestamp也馬上會得到支持。

下面看看對於線上的Hudi Spark作業如何調優。

下面列舉了幾個調優手段,設置Kryo序列化器,使用Shuffle Service,利用開源的profiler來進行內存調優,當然Hudi也提供了Hudi生產環境的調優配置,可參考【調優 | Apache Hudi應用調優指南】

下面介紹社區正在進行的工作,敬請期待。

即將發布的0.6.0版本,將企業中存量的parquet表高效導入Hudi中,與傳統通過Spark讀取Parquet表然後再寫入Hudi方案相比,佔用的資源和耗時都將大幅降低。以及對於查詢計劃的O(1)時間複雜度的處理,新增列索引及統一元數據管理以消除對DFS的文件list操作。

還有一些值得關注的特性,比如支持行級別的索引,該功能將極大降低upsert的延遲;異步數據clustering以優化存儲和查詢性能;支持Presto對MoR表的快照查詢;Hudi集成Flink,通過Flink可將數據寫入Hudi數據湖。

整個分享就介紹到這裏,歡迎觀看。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

你已經是個成熟的程序員了,該學會用程序幫自己省錢了————狄克斯特拉算法

  說起回家,路途漫漫,行李滿滿,尤其我等村裡交通不發達的地方,可能連直達的票都沒有,雖說條條大陸通羅馬,但畢竟還是想找個換乘最少的路線,畢竟誰不想回家更輕鬆點呢(*^_^*),下面就是我回家的所有路線。

 

  思路很簡單,先找起點看是否能到,不能到的話,看起點能到的點的下一步是否能到

 

  話不多說,擼代碼:

public static void main(String[] args) {
    HashMap<String,List<String>> data = new HashMap<String, List<String>>();
    List<String> list1 = new ArrayList<String>();
    data.put("起點",list1);
    list1.add("A");
    list1.add("B");
    List<String> list2 = new ArrayList<String>();
    data.put("A",list2);
    list2.add("終點");
    List<String> list3 = new ArrayList<String>();
    data.put("B",list3);
    list3.add("A");
    list3.add("終點");
    query(data,"終點","起點");
}

public static void query(Map<String,List<String>> data, String queryValue, String start){
    if(data==null || queryValue ==null){
        return;
    }
    Queue<String> queue = new LinkedList<String>();
    Map quaryLog  = new HashMap();
    Map<String,List<String>> routes = new HashMap<String, List<String>>();
    queue.offer(start);
    quaryLog.put(start,"");
    String parent = null;
    while (!queue.isEmpty()){
        parent = queue.poll();
        List<String> values = data.get(parent);
        for(String value:values){
            List<String> r = new ArrayList<String>();
            if(routes.containsKey(parent)){
                r.addAll(routes.get(parent));
            }
            r.add(parent);
            routes.put(value,r);
            if(queryValue.equals(value)){
                routes.get(value).add(value);
                System.out.println(routes.get(value));
                return;
            }
            if(!quaryLog.containsKey(value)){
                queue.offer(value);
                quaryLog.put(value,"");
            }
        }
    }
    return ;
}

  

  run 一把,結果出來了

  [起點, A, 終點]

  終於,結果出來了,先到A地,再從A到終點,其實這就是廣度優先搜索,so easy興沖衝去買票,發現錢不夠,哎,沒有考慮票價啊!!!我的票價是這樣的:

 

  按照現在的規劃需要700元,可是我只有650元,不夠啊,沒辦法,修改算法把,這次需要把價錢考慮進去,我需要最便宜的路線

  思路也類似,先從起點開始走,分別計算最便宜的路線

 

  終點暫時到不了,我們把到終點的距離記作無窮,接着我們從B點開始往下找,計算最便宜的價錢如下:

 

  然後再計算A點走的話,最便宜的路線,比從B點走便宜的話我們就更新,不便宜的話代表原來的價錢已經是最便宜的了

 

  找到了,最便宜的路線是600,但是程序要如何做呢,畢竟我以後不僅要回家,還要去旅遊,還要去丈母娘家,我要每次都最便宜!!!,擼碼如下:


public static void main(String[] args) {
HashMap<String,HashMap<String,Integer>> data = new HashMap<String, HashMap<String, Integer>>();
HashMap<String,Integer> map1 = new HashMap<String, Integer>();
data.put("起點",map1);
map1.put("A",600);
map1.put("B",200);
HashMap<String,Integer> map2 = new HashMap<String, Integer>();
data.put("A",map2);
map2.put("終點",100);
HashMap<String,Integer> map3 = new HashMap<String, Integer>();
data.put("B",map3);
map3.put("終點",500);
map3.put("A",300);
queryMinPrice(data,"起點","終點");
}

public static void queryMinPrice(HashMap<String,HashMap<String,Integer>> data,String start,String end){
HashMap<String,Integer> costs = new HashMap<String, Integer>();
HashMap<String,List<String>> route = new HashMap<String, List<String>>();
for(Map.Entry<String,Integer> entry: data.get(start).entrySet()){
costs.put(entry.getKey(),entry.getValue());
List<String> list = new ArrayList<String>();
list.add(entry.getKey());
route.put(entry.getKey(),list);
}
costs.put(end,Integer.MAX_VALUE);
HashMap<String,String> queryLog = new HashMap<String, String>();
String key = findMinPriceKey(costs,queryLog);
while (key != null){
queryLog.put(key,"");
if(data.get(key) == null){
break;
}
for(Map.Entry<String,Integer> entry:data.get(key).entrySet()){
if(costs.containsKey(entry.getKey())){
if(entry.getValue()+costs.get(key)<costs.get(entry.getKey())){
costs.put(entry.getKey(),entry.getValue()+costs.get(key));
List<String> list = new ArrayList<String>();
list.addAll(route.get(key));
list.add(entry.getKey());
route.put(entry.getKey(),list);
}
}else {
costs.put(entry.getKey(),entry.getValue()+costs.get(key));
List<String> list = new ArrayList<String>();
list.addAll(route.get(key));
route.put(entry.getKey(),list);
}
}
key = findMinPriceKey(costs,queryLog);
}
System.out.println("最小花費:"+costs.get(end));
System.out.println("最小花費路徑:"+route.get(end));
}
private static String findMinPriceKey(HashMap<String,Integer> data,HashMap<String,String> queryLog){
String key = null;
for(Map.Entry<String,Integer> entry : data.entrySet()){
if(!queryLog.containsKey(entry.getKey()) && key == null ){
key = entry.getKey();
}
if(!queryLog.containsKey(entry.getKey()) && entry.getValue()<data.get(key)){
key = entry.getKey();
}
}
return key;
}

  運行結果:

  最小花費:600

  最小花費路徑:[B, A, 終點]

  結果出來了,先買到B的票,然後在到A,再回家,只要600塊,還能省50塊,完美!!這就是大名鼎鼎的狄克斯特拉算法。

      PS:這不是標準的狄克斯特拉算法,只是本例中的數據少,數據多的話遍歷成本是很高的,標準的狄克斯特拉算法利用的是貪婪算法思想,求局部最優解,要在可以到達終點時就返回(此註釋基於評論,本來自己寫着玩兒的,沒想會有人認真來看,避免產生誤解,誤導他人,水平有限深感慚愧)

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

基於 Angular Material 的 Data Grid 設計實現

自 Extensions 組件庫發布以來,Data Grid 成為了使用及諮詢最多的組件。最開始 Data Grid 的設計非常簡陋,經過一番重構,組件質量有了質的提升。
Extensions 組件庫: https://github.com/ng-matero/extensions
Data Grid 示例: https://ng-matero.github.io/extensions/data-grid

距離 Extensions Data Grid 重構已經過去了兩個多月,因工作忙碌而遲遲沒有介紹 Extensions Data Grid 的細節。這幾天又重構了一下官網示例,目前的 API 文檔放在了 gitbook 上,暫時還沒有和官網整合,國內訪問會比較慢。本文會介紹 Data Grid 的使用方法及比較好的一些功能實現。說點題外話,開發一款插件最大的難度不在於功能的實現,而在於如何去設計插件。

什麼是 Data Grid?

Data Grid 本質上就是通過 數據+列定義+配置項 來渲染表格的插件。這比寫一堆 DOM 結構要簡潔很多,可以說是 CRUD 業務中的大殺器之一。目前市面上功能最全的 Data Grid 是 ag-grid,很多組件庫也有自己的 Data Grid 實現,比如 Ignite UI,Kendo UI。但是市面上這些優秀的插件基本都要收費,另外就是遇到變態需求時,第三方插件的功能定製會遇到很多問題,這也是我自研 Data Grid 的初衷。

Angular Material 對於 table 的封裝已經足夠靈活,但是模板的定義依然很繁瑣,也缺少很多剛需功能。Extensions Data Grid 幾乎整合了 Angular Material 表格的所有功能,同時又增加了很多實用功能。

Extensions Data Grid 簡介

Extensions Data Grid 的功能實現參考了 ag-grid 以及其它插件,重構時對變量及參數命名進行了很細緻的考究。目前 Extensions Data Grid 已經實現的功能如下:

  • Paging(分頁,包括前端分頁和後端分頁)
  • Sorting(排序,目前只支持單值排序)
  • Sticky columns(列的固定)
  • Column hiding(列的显示隱藏)
  • Column moving(列的移動排序)
  • Checkbox selection(數據選擇)
  • Row selection(行選取,可多選)
  • Cell selection(單元格選取,暫時只支持單選)
  • Expandable row(可展開的表格行)
  • Data Formatting(數據格式化)
  • Customized cell(自定義單元格)
  • Template(各種模板)

因文章篇幅有限,本文主要介紹一些重點功能,其它功能可以參考官網示例。

基本用法

官網示例:Basic

定義組件參數

<mtx-grid [data]="list" 
          [columns]="columns">
</mtx-grid>

定義數據及列

export class AppComponent {
  columns: MtxGridColumn[] = [
    { header: 'Name', field: 'name' },
    { header: 'Weight', field: 'weight' },
    { header: 'Gender', field: 'gender' },
    { header: 'Mobile', field: 'mobile' },
    { header: 'City', field: 'city' },
  ];

  list = EXAMPLE_DATA;
}

補充介紹一下,市面上 Data Grid 定義列的方式主要有兩種:

1、JS 定義,比如 ag-grid

var gridOptions = {
    // define 3 columns
    columnDefs: [
        { headerName: 'Athlete', field: 'athlete' },
        { headerName: 'Sport', field: 'sport' },
        { headerName: 'Age', field: 'age' }
    ],

    // other grid options here...
}

2、模板定義,比如 Ignite UI

<igx-grid igxPreventDocumentScroll #grid1 [data]="data | async" [height]="'500px'" width="100%" [autoGenerate]='false' [allowFiltering]="true">
    <igx-column [field]="'Category'" [width]="'120px'"></igx-column>
    <igx-column [field]="'Type'" [width]="'150px'" [filterable]='false'></igx-column>
    <igx-column [field]="'Open Price'" [width]="'120px'" dataType="number" [formatter]="formatCurrency">
    </igx-column>
    <igx-column [field]="'Price'" [width]="'120px'" dataType="number" [formatter]="formatCurrency"></igx-column>
</igx-grid>

權衡各種利弊,Extensions Data Grid 選擇了第一種定義方法,接口定義如下:

export interface MtxGridColumn {
  field: string;
  header?: string;
  hide?: boolean;
  disabled?: boolean;
  pinned?: 'left' | 'right';
  left?: string;
  right?: string;
  width?: string;
  resizable?: boolean;
  sortable?: boolean | string;
  type?: 'tag' | 'button' | 'link' | 'image' | 'number' | 'currency' | 'percent' | 'boolean';
  tag?: MtxGridColumnTag;
  buttons?: MtxGridColumnButton[];
  formatter?: (rowData: any, colDef?: any) => void;
  cellTemplate?: TemplateRef<any> | null;
  showExpand?: boolean;
  description?: string;
  i18n?: string;
  summary?: ((colData: any, colDef?: any) => void) | string;
}

模板

模板是 angular 組件極其靈活的一個功能。大部分優秀的第三方組件都具有自定義模板的能力,而在 Data Grid 中,模板更是一個不可或缺的功能。Extensions Data Grid 的模板功能已經比較完善,單元格模板除了基本的方法外,還增加了更為簡單易用的方法。

普通方法

<mtx-grid [data]="list"
          [columns]="columns">
</mtx-grid>

<ng-template #statusTpl let-row let-index="index" let-col="colDef">
  <mat-slide-toggle [checked]="row.status">Slide me!</mat-slide-toggle>
</ng-template>
export class AppComponent implements OnInit {
  @ViewChild('statusTpl', { static: true }) statusTpl: TemplateRef<any>;

  columns: MtxGridColumn[] = [];

  list = EXAMPLE_DATA;

  ngOnInit() {
    this.columns = [
      { header: 'Name', field: 'name' },
      { header: 'Weight', field: 'weight' },
      { header: 'Gender', field: 'gender' },
      { header: 'Mobile', field: 'mobile' },
      { header: 'City', field: 'city' },
      { header: 'Status', field: 'status', cellTemplate: this.statusTpl },
    ];
  }
}

官網示例:Custom cell template

引用模板實例是一種很常見的思路,但是弊端就是必須將列定義寫在 ngOnInit 中,而且要先引用所用的自定義模板實例。這種寫法很不靈活。

升級方案

<mtx-grid [data]="list"
          [columns]="columns"
          [cellTemplate]="{ city: cityTpl }">
</mtx-grid>

<ng-template #cityTpl let-row let-index="index" let-col="colDef">
  <button mat-raised-button color="primary">{{row.city}}</button>
</ng-template>

官網示例:Custom cell template 2

這種方法直接在組件參數中定義了模板實例 [cellTemplate]="{ city: cityTpl }",其中 city 是列定義中的 field,除此之外不需要再寫其它任何代碼,非常簡單!

除了單元格模板之外,還有 headerTemplate、summaryTemplate、toolbarTemplate 等,可以滿足大部分的個性化需求,詳情見官網示例。

選取

官網示例:Row selectable

表格的行選取是一個很常見的需求,用途廣泛。默認開啟單元格選取,可以設置 [cellSelectable]="false" 以關閉單元格選取。

通過 [rowSelectable]="true" 可以開啟行選取。

<mtx-grid [data]="list"
          [columns]="columns"
          [rowSelectable]="rowSelectable"
          (rowSelectionChange)="log($event)"
          (cellSelectionChange)="log($event)">
</mtx-grid>

通過 [multiSelectable]="true" 可以設置多選行。這裡有一個細節,按住 ctrl 並單擊才可以多選,或者直接點擊 checkbox 也可以。如果需要隱藏 checkbox,只需要設置 [hideRowSelectionCheckbox]="true"。

如果初始化表格時希望默認選中某些行,則只需要定義 [rowSelected]=[...]。

不可選取

設置不可選取行的方式有兩種,一種是設置 checkbox 為 disabled,另一種是隱藏 checkbox。配置非常簡單,只需要通過 rowSelectionFormatter 過濾數據即可。

<mtx-grid [data]="list"
          [columns]="columns"
          [rowSelectable]="true"
          [rowSelectionFormatter]="rowSelectionFormatter">
</mtx-grid>
export class AppComponent {
  columns: MtxGridColumn[] = [
    { header: 'Name', field: 'name' },
    { header: 'Weight', field: 'weight' },
    { header: 'Gender', field: 'gender' },
    { header: 'Mobile', field: 'mobile' },
    { header: 'City', field: 'city' },
  ];

  list = EXAMPLE_DATA;

  rowSelectionFormatter: MtxGridRowSelectionFormatter = {
    disabled: (data) => data.name === 'Boron',
    hideCheckbox: (data) => data.name === 'Helium',
  };
}

行展開

官網示例:Expandable row

行展開的實現藉助了 Angular Material 表格的 multiTemplateDataRows 參數,實現細節很多。Data Grid 的代碼如下:

設置 expandable 和 expansionTemplate

<mtx-grid [data]="list"
          [columns]="columns"
          [expandable]="true"
          [expansionTemplate]="expansionTpl">
</mtx-grid>

<ng-template #expansionTpl let-row>
  {{row.name}}
</ng-template>

在列定義中設置 showExpand, 確定在哪個列显示展開符號。

export class AppComponent {
  columns: MtxGridColumn[] = [
    { header: 'Name', field: 'name', showExpand: true },
    { header: 'Weight', field: 'weight' },
    { header: 'Gender', field: 'gender' },
    { header: 'Mobile', field: 'mobile' },
    { header: 'City', field: 'city' },
  ];

  list = EXAMPLE_DATA;
}

列操作

官網示例:Column hiding & moving

列的显示隱藏以及排序是非常常見的需求,這類需求曾被產品經理折磨了無數次。目前的列操作 UI 只有菜單方式,之後還會添加側邊欄的 UI,暫時不支持列的橫向拖拽。

列的操作完全可以移到組件之外,通過設置 columns 實現,並不一定非要用 Data Grid 集成好的功能。

總結

因篇幅有限,很多 Extensions Data Grid 的功能沒有詳細介紹。從我遇到的需求來看,目前的 Data Grid 已經可以覆蓋九成的需求了,還有很多高級功能正在開發當中,歡迎大家提出建設性意見。如果大家在使用組件的過程中遇到問題,可以在 GitHub 中提交 issues 或者進討論群提問。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!