中國大陸推排放標準,控管油電混和車排放

大陸環保部30日發布涉及船舶發動機、摩托車、輕便摩托車、輕型混合動力電動汽車和燒鹼、聚氯乙烯(PVC)工業排放的五項國家污染物排放標準,分別為《船舶發動機排氣污染物排放限值及測量方法(中國第1、2階段)》、《摩托車污染物排放限值及測量方法(中國第4階段)》、《輕便摩托車污染物排放限值及測量方法(中國第4階段)》、《輕型混合動力電動汽車污染物排放控制要求及測量方法》和《燒鹼、聚氯乙烯工業污染物排放標準》。上述標準旨在落實《大氣污染防治行動計畫》和《水污染防治行動計畫》,透過制定、修訂重點行業的排放標準力促產業轉型升級。

大陸環保部科技標準司司長鄒首民表示,實施這五項標準將可望大幅削減顆粒物(PM)、氮氧化物(NOx)、二氧化硫(SO2)的污染,有效促進行業技術進步和環境品質的改善。他指出,新標準適用於具有中國船籍在大陸水域航行或作業的船舶裝用的額定淨功率大於37千瓦、新生產船用發動機的環境管理,不適用於遠洋船舶,遠洋運輸船舶執行國際公約的相關規定。

鄒首民指出,上述新標準實施後,按照每年新增船機1,000萬千瓦,壽命期為25年計算,實施第一階段標準3年,所製造投入使用的船機在全壽命期內將減排NOX約140萬噸,PM約40萬噸;若實施第二階段標準3年,也將進一步減排NOX約115萬噸,PM約6萬噸。

另外,對於產量增長迅速的摩托車污染問題也正在引起重視。鄒首民說,為能有效控制摩托車污染,環保部制定了摩托車和輕便摩托車國四標準,自2019年7月1日起,所有新銷售和註冊登記的摩托車和輕便摩托車,應滿足新的標準;以國四標準實施3年估算,這期間,新生產的全部摩托車在其整個使用壽命內,將比實施國三標準減少CO排放約650萬噸、HC排放約200萬噸、NOx排放約30萬噸。

他也指出,近年來大陸國家積極鼓勵發展包括混合動力電動汽車在內的節能與新能源汽車,但由於有電能的輔助,傳統汽車的測量方法無法準確評判混合動力電動汽車的污染物排放狀況;新標準是對《輕型混合動力電動汽車污染物排放測量方法》的修訂,規定了輕型混合動力電動汽車的污染控制要求和測量方法,新標準適用於國四、國五階段的輕型混合動力汽車的環保管理,該測量方法標準的實施,將不會帶來額外的車輛技術升級成本。

(本文內容由授權提供)

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

聚甘新

Tesla台灣旗艦店開幕,Model S 2017年在台上市

不論是在汽車、能源還是科技界,不論發生什麼事情都在大眾目光焦點的特斯拉 (Tesla),既三月份成立臺灣分公司之後有更進一步的動作。特斯拉的臺北旗艦店在今日 (9 月1 日) 在臺北信義商圈開幕,有興趣的人可以到店體驗特斯拉房車Model S,並且預約試駕和進一步訂購,預計明年 (2017) 第一季交車。

特斯拉看中臺灣在科技產業的樞鈕地位,因此在亞太區暨中國、香港、澳門、澳洲之後,選擇臺灣,成為特斯拉全球第25 個設立的國家。而在信義商圈新光三越A11 的台灣旗艦店,則是第204 家店。選在臺灣的首善之都臺北,則是著眼信義商圈是臺北最繁盛的購物商圈,對新事物的接受度高,因此選在新光三越A11 設旗艦店,並且還跟新光三越合作,在百貨公司的地下停車場設立充電站。

電動車要能方便,必須有足夠的的充電站。Tesla香港、澳門及台灣地區區域總監范菁怡表示,目前除了設在車主自家的居家充電站之外,還會與百貨商場、飯店合作,在停車場設置目的地充電站。未來特斯拉也將在高速公路沿線設置超級充電站,服務需長距離駕駛的特斯拉車子。

由於特斯拉代表新一代的潔淨能源運用型式,對於提高都市運輸效率和降低污染有顯著效果,因此除了特斯拉的代表和合作的百貨公司代表以外,臺北市政府也由副市長林欽榮出席。另外還有負責招商相關事務的行政院全球招商及攬才聯合服務中心何怡明執行長,以及經濟部工業局黃裕峰副組長出席。林欽榮致詞時表示,臺北市仍然要繼續推動共享汽車,U-Car 計畫。

儘管目前在臺灣還只能預購特斯拉的Model S 房車車型,但是特斯拉計畫在臺引進平價車款Model 3,定價3 萬5,000 美元,預計明年引進,目前正在商品檢驗階段。

「電動車勢必是未來交通方式的主流,Tesla 一直期望扮演推動永續能源應用的角色。我們樂見台灣對環保、綠色能源的高接受度,也很高興Tesla 能成為這波改革中的一股力量。」Tesla 全球副總裁暨亞太區總裁任宇翔表示:「臺灣特殊的地理和城市發展環境,以及政府對於相關政策和補助的支持,讓Tesla 清楚看到電動車在臺灣的發展性。臺灣廠商不僅是Tesla供應鏈的合作夥伴,更在電動車的推廣上佔有重要地位。隨著Tesla 電動車在台上市與充電站的逐步擴充,Tesla 對臺灣市場的發展潛力深具信心,除了希望對合作夥伴和經濟發展帶來正面影響,更期望與臺灣一起開創電動車的新篇章。」

特斯拉之後將在臺灣設立客服,還有佈建充電網路,當特斯拉的Model S 在臺灣的道路奔馳時,超級充電站和目的地充電站在商圈、景點等地方,形成足夠的網狀分佈,維持特斯拉的輪胎不停轉動。全球有超過9,000 萬臺汽車,目前只有不到0.2% 的汽車是電動車,特斯拉推動電動車,還可以有很大的施力空間。

(首圖:設在新光三越信義A11 地下4 樓停車場的特斯拉目的地充電站,在2017 年特斯拉車子在臺灣道路奔馳之際,這類設在購物商場的充電站將會越來越多。來源:科技新報)

(本文授權轉載自《》──〈〉)

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

FB行銷專家,教你從零開始的技巧

聚甘新

布局之: flex(CSS3新增)

flex 基本概念

  flex布局(flex是flexible box的縮寫), 也稱為彈性盒模型 。將屬性和屬性值(display:flex; )寫在哪個標籤樣式中,誰就是 容器;它的所有子元素自動成為容器成員,稱為項目。

當一個元素的display 取值為flex,所有項目(子元素)會在一行显示;如果所有項目的尺寸之和大於容器,也不會超出父元素的寬、高度。不會換行(每個項目都會自動縮小相應的比例)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>布局之:flex</title>
    <link rel="stylesheet" href="./CSS/normalize.css">
    <style>
        section {
            width: 500px;
            height: 800px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
        }
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
        }
    </style>
</head>
<body>
    <section>
        <div>01</div>
        <div>02</div>
        <div>03</div>
        <div>04</div>
        <div>05</div>
        <div>06</div>
    </section>
</body>
</html>

頁面效果 : 每一個項目都等比例縮小了。

 

  css代碼分為兩種: 一類是適用於容器的 (設置主軸的起始位置、換行、主軸的對齊方式、多跟軸線對齊方式);一類是適用於項目的(設置項目的位置)。

容器常用的屬性和屬性值

由於重複代碼較多,就不一 一上傳代碼了,大家可以自己動手,敲敲代碼,試試看。

一、設置主軸的起始方向  flex-direction:

默認為X軸(行):

<style>
        section {
            width: 500px;
            height: 500px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
            /* flex-direction: row; */
            /* flex-direction: row-reverse; */
            /* flex-direction: column; */
            /* flex-direction: column-reverse; */
        }
        
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
        }
    </style>

 

flex-direction:row; 默認是X軸的起始方向為開始位置 (從左到右依次擺放);
flex-direction:row-reverse; 改變X軸的起始方向為結束位置 (從右到左依次擺放);

設置主軸的起始方向為Y軸(列):

flex-direction:column; 默認是Y軸的起始方向為開始位置(從上到下依次擺放)
flex-direction:column-reverse; 改變Y軸的起始方向為結束位置(從下到上依次擺放)

二、設置項目是否換行  flex-wrap:(默認是不換行)

 <style>
        section {
            width: 400px;
            height: 400px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
            /* flex-wrap: wrap; */
            /* flex-wrap: wrap-reverse; */
        }
        
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
        }
    </style>

flex-wrap: nowrap;  默認值是不換行;(n個項目都會在一行显示.如果項目尺寸之和大於容器主軸的尺寸,則項目會自動縮小相應比列.) (參考第一個代碼 頁面結果展示)

flex-wrap: wrap; 設置換行;(超出主軸的寬,則進行換行。換行后,兩行之間會出現間距,是因為垂直方向有剩餘空間,會平均分配給第二行的上下)

flex-wrap: wrap-reverse; 倒序換行;(如果有兩行,第2行显示在前面,第一行显示在後面)

三、主軸方向的對齊方式  justify-content:

項目是一個時:

 <style>
        section {
            width: 400px;
            height: 400px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
            /* justify-content: flex-start; */
            /* justify-content: flex-end; */
            /* justify-content: center; */
        }
        
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
        }
    </style>

justify-content:flex-start; 以主軸開始方向對齊 (默認)
justify-content:flex-end; 以主軸結束方向對齊

justify-content:center; 主軸方向居中

項目是多個時:

<style>
        section {
            width: 500px;
            height: 500px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
            /* justify-content: space-between; */
            /* justify-content: space-around; */
            /* justify-content: space-evenly; */
        }
        
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
        }
    </style>

justify-content: space-between; 兩端對齊 (第一個項目在容器的起始位置,最後一個項目在容器的結束位置,中間距離相等)

 

justify-content: space-around;  分散對齊

justify-content: space-evenly;  平分剩餘空間,每個項目之間的距離相同

 

四、主軸改變為交叉軸方向的對齊方式

一根軸線:  主軸需改變為Y軸:flex-direction: column;

 

align-items: baseline; 以項目的第一行文字的基線對齊

align-items: stretch; (項目沒有給高的情況下,stretch就是默認值,如果項目沒有設置高度,就是容器的高)

 

 <style>
        section {
width: 500px; height: 500px; border: 2px solid black; margin: 50px auto; display: flex; /* 主軸需改變為Y軸 項目按列擺放 */ flex-direction: column; /* align-items: flex-start; 默認擺放方式 */ /* align-items: center; */ /* align-items: flex-end; */

} div { width: 100px; height: 100px; border: 1px solid tomato; } </style>

 

align-items: flex-start;  交叉軸從開始位置對齊
align-items: center; 交叉軸居中對齊

align-items: flex-end; 交叉軸從結束位置對齊

多根軸線: (所有項目的尺寸之和,必須大於容器的尺寸,使項目換行显示)

<style>
        section {
            width: 500px;
            height: 500px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
            flex-direction: column;
            flex-wrap: wrap;
            /* align-content: center; */
            /* align-content: flex-end; */
            /* align-content: space-between; */
            /* align-content: space-around; */
        }
        
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
        }
    </style>

 

align-content: flex-start; 交叉軸從開始位置對齊
align-content: center; 交叉軸居中對齊

align-content: flex-end; 交叉軸從結束位置對齊

align-content: space-between; 交叉軸兩端對齊

align-content: space-around; 交叉軸分散對齊

align-content: space-evenly; 交叉軸平均分配

 

項目的屬性和屬性值:

一、order 控制項目位置

order:1;
取值 : 正、負數 (默認值是 0)
值越小越靠前 值越大越靠後 。

(適用場景: 1.搜索引擎優化,提升SEO 把重要的信息在html代碼中靠前擺放,但不影響布局 2.調整項目位置)

<style>
        section {
            width: 500px;
            height: 500px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
        }
        
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
        }
        
        div:nth-child(4) {
            order: -1;
        }
    </style>

設置一個或多個[項目]在交叉軸的對齊方式:

 <style>
        section {
            width: 800px;
            height: 400px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
        }
        
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
        }
        
        div:nth-child(2) {
            align-self: center;
        }
        
        div:nth-child(3) {
            align-self: flex-end;
        }
    </style>

align-self: flex-start; 設置項目在交叉軸開始位置擺放 (默認位置)
align-self: center; 設置項目在交叉軸居中擺放

align-self: flex-end; 設置項目在交叉軸結束位置擺放

設置某一個或多個元素放大比例

  條件:所有項目的尺寸之和要小於容器的尺寸
  (沒有剩餘空間,則設置此屬性無效。)

一個元素有 flex-grow 屬性

<style>
        section {
            width: 800px;
            height: 400px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
        }
        
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
        }
        
        div:nth-child(2) {
            flex-grow: 1;
        }
    </style>

多個項目有flex-grow 屬性

<style>
        section {
            width: 800px;
            height: 200px;
            border: 2px solid black;
            margin: 50px auto;
            display: flex;
            box-sizing: border-box;
        }
        
        div {
            width: 100px;
            height: 100px;
            border: 1px solid tomato;
            box-sizing: border-box;
        }
        
        div:nth-child(2) {
            flex-grow: 1;
        }
        
        div:nth-child(4) {
            flex-grow: 2;
        }
    </style>

效果展示

將容器的剩餘空間分成相應的flex-grow的份數,再按照每個項目的份數,分給有flex-grow屬性的項目。

 

  總之,flex使用起來特別方便,可適用於響應式布局,也可使用聖杯布局。只是屬性較多,也要多練、多實踐 ,相信你也能很快熟練使用flex的。

推薦一個小遊戲,很有趣,又能增強關於flex的使用方法 :Flexbox Froggy  http://blog.xiaoboswift.com/flexbox/#zh-cn  去幫助小青蛙回家吧~~

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

聚甘新

循序漸進VUE+Element 前端應用開發(11)— 圖標的維護和使用,循序漸進VUE+Element 前端應用開發(5)— 表格列表頁面的查詢,列表展示和字段轉義處理,循序漸進VUE+Element 前端應用開發(9)— 界面語言國際化的處理

在VUE+Element 前端應用中,圖標是必不可少點綴界面的元素,因此整合一些常用的圖標是非常必要的,還好Element界面組件裏面提供了很多常見的圖標,不過數量不是很多,應該是300個左右吧,因此考慮擴展更多圖標,我引入了vue-awesome組件,它利用了Font Awesome的內置圖標,實現了更多圖標的整合,可以在項目中使用更多的圖標元素了,另外在本隨筆的圖標管理中,提供了對圖標名稱進行搜索,並根據圖標顏色樣式生成對應圖標的代碼,非常方便使用。

Vue-Awesome 是基於 Vue.js 的 SVG 圖標組件,內置圖標來自  Font Awesome。

本篇隨筆先來上一個圖標管理的界面效果,然後在逐一進行介紹Element內置圖標和Vue-Awesome的圖標吧。

Element圖標管理界面如下:

基於Vue-Awesome的圖標管理如下所示。

其中查詢提供了名稱進行圖標查詢,以及限制一次性展示多少個,另外提供一個自定義顏色選項,從而可以改變圖標的展示顏色。

  

1、Vue-Awesome的使用介紹

  Vue-Awesome 的 npm的安裝命令如下所示:

npm install vue-awesome

安裝方式如下所示

import Vue from 'vue'

/* 在下面兩種方式中任選一種 */

// 僅引入用到的圖標以減小打包體積
import 'vue-awesome/icons/flag'

// 或者在不關心打包體積時一次引入全部圖標
import 'vue-awesome/icons'

/* 任選一種註冊組件的方式 */

import Icon from 'vue-awesome/components/Icon'

// 全局註冊(在 `main .js` 文件中)
Vue.component('v-icon', Icon)

// 或局部註冊(在組件文件中)
export default {
  components: {
    'v-icon': Icon
  }
}

界面使用代碼如下所示,詳細Demo可以參考https://justineo.github.io/vue-awesome/demo/ 了解。

<!-- 基礎用法 -->
<v-icon name="beer"/>

<!-- 添加選項 -->
<v-icon name="sync" scale="2" spin/>
<v-icon name="comment" flip="horizontal"/>
<v-icon name="code-branch" label="Forked Repository"/>

<!-- 堆疊圖標 -->
<v-icon label="No Photos">
  <v-icon name="camera"/>
  <v-icon name="ban" scale="2" class="alert"/>
</v-icon>

Vue-Awesome圖標提供了一些prop的屬性設置,參考下面列表所示。

  • name: string

    圖標名稱。如果本組件沒有用作圖標堆棧的容器,那麼這個字段是必須的。所有合法的值都對應於圖標文件相對於 icons 目錄的路徑。請注意當你在 FontAwesome 官網查找到圖標名詞后,需要確認一下圖標集的名稱。比如,在 500px 這個圖標的詳情頁會有一個 URL 參數 style=brands,故圖標名稱就是 brands/500px

    默認情況下,只能使用 FontAwesome 的免費圖標,另外由於 solid 樣式中的圖標最多,我們將其設為了默認圖標集,所以路徑前綴可以省略。

    當傳入 null 時,整個組件將不會渲染。

  • scale: number|string

    用來調整圖標尺寸,默認值為 1

  • spin: boolean

    用來指定圖標是否需要旋轉。默認值為 false。(不能與 pulse 一同使用。)

  • pulse: boolean

    用來指定圖標是否有脈衝旋轉的效果。默認值為 false。(不能與 spin 一同使用。)

  • inverse: boolean

    為 true 時圖標顏色將被設置為 #fff。默認值為 false

  • flip: 'vertical'|'horizontal'|'both'

    用來指定圖標是否需要翻轉。

  • label: string

    當指定時會設置圖標的 aria-label

  • title: string

    為圖標設置標題。

另外,我們也可以註冊自定義圖標,如下所示。

import Icon from 'vue-awesome/components/Icon'

Icon.register({
  baidu: {
    width: 23.868,
    height: 26,
    d: 'M3.613 13.701c2.827-.608 2.442-3.986 2.357-4.725-.138-1.139-1.477-3.128-3.296-2.971C.386 6.21.052 9.515.052 9.515c-.309 1.528.74 4.793 3.561 4.186zm3.002 5.875c-.083.238-.268.846-.107 1.375.315 1.187 1.346 1.24 1.346 1.24h1.48v-3.619H7.749c-.713.213-1.057.767-1.134 1.004zM8.86 8.035c1.562 0 2.823-1.797 2.823-4.019C11.683 1.796 10.421 0 8.86 0 7.301 0 6.036 1.796 6.036 4.016c0 2.222 1.265 4.019 2.824 4.019zm6.724.265c2.087.271 3.429-1.956 3.695-3.644.272-1.686-1.074-3.644-2.552-3.98-1.48-.339-3.329 2.032-3.497 3.578-.2 1.89.271 3.778 2.354 4.046zm5.114 9.923s-3.229-2.498-5.113-5.198c-2.555-3.981-6.185-2.361-7.399-.337-1.209 2.024-3.093 3.305-3.36 3.644-.271.334-3.9 2.293-3.095 5.871.806 3.576 3.635 3.508 3.635 3.508s2.085.205 4.504-.336c2.42-.537 4.503.134 4.503.134s5.652 1.893 7.199-1.751c1.545-3.645-.874-5.535-.874-5.535zm-9.671 5.423H7.352c-1.587-.316-2.219-1.4-2.299-1.584-.078-.188-.528-1.059-.29-2.539.686-2.219 2.642-2.379 2.642-2.379h1.956V14.74l1.666.025v8.881zm6.844-.025h-4.229c-1.639-.423-1.716-1.587-1.716-1.587v-4.677l1.716-.027v4.203c.104.447.661.529.661.529h1.742v-4.705h1.825v6.264zm5.986-12.486c0-.808-.671-3.239-3.159-3.239-2.492 0-2.825 2.295-2.825 3.917 0 1.548.131 3.71 3.227 3.641 3.096-.068 2.757-3.507 2.757-4.319z'
  }
})

如果你的 SVG 文件有多個路徑或多邊形,以及/或者你想預定義一些樣式,可以用如下方式進行註冊:

路徑方式:

import Icon from 'vue-awesome/components/Icon'

Icon.register({
  webpack: {
    width: 1200,
    height: 1200,
    paths: [
      {
        style: 'fill:#8ED6FB',
        d: 'M1035.6 879.3l-418.1 236.5V931.6L878 788.3l157.6 91zm28.6-25.9V358.8l-153 88.3V765l153 88.4zm-901.5 25.9l418.1 236.5V931.6L320.3 788.3l-157.6 91zm-28.6-25.9V358.8l153 88.3V765l-153 88.4zM152 326.8L580.8 84.2v178.1L306.1 413.4l-2.1 1.2-152-87.8zm894.3 0L617.5 84.2v178.1l274.7 151.1 2.1 1.2 152-87.8z'
      },
      {
        style: 'fill:#1C78C0',
        d: 'M580.8 889.7l-257-141.3v-280l257 148.4v272.9zm36.7 0l257-141.3v-280l-257 148.4v272.9zm-18.3-283.6zM341.2 436l258-141.9 258 141.9-258 149-258-149z'
      }
    ]
  }
})

多邊形方式:

import Icon from 'vue-awesome/components/Icon'
Icon.register({
  vue: {
    width: 256,
    height: 221,
    polygons: [
      {
        style: 'fill:#41B883',
        points: '0,0 128,220.8 256,0 204.8,0 128,132.48 50.56,0 0,0'
      },
      {
        style: 'fill:#35495E',
        points: '50.56,0 128,133.12 204.8,0 157.44,0 128,51.2 97.92,0 50.56,0'
      }
    ]
  }
})

對於自定義的這些圖標,我們可以把它們一起放在一個獨立的JS文件裏面進行定義,然後全局統一加入即可。

 

 使用上和其他的圖標沒有差異,只是名稱不同而已。

    <div style="height:100px;padding:10px">
      <span>vue-Awesome 自定義圖標:(在utils/awesome-icon-customed.js中引入)</span>
      <v-icon name="baidu" scale="2" :style="iconStyle" />
      <v-icon name="vue" scale="2" />
      <v-icon name="webpack" scale="2" spin />
      <v-icon name="html5-c" scale="2" spin />
    </div>

 

2、導入Element 圖標和Vue-Awesome圖標

在我們進行頁面管理的時候,我們需要提取Element 圖標和Vue-Awesome圖標,以便能夠進行界面的展示處理。

Element圖標,我們只需要在一個JS文件裏面,包含它的名稱進去一個列表裡面即可,如下定義所示。

const elementIcons = [
  'platform-eleme', 'eleme', 'delete-solid', 'delete', ..........
]

export default elementIcons

在其中錄入對應Element的圖表名稱,移除el-icon-的前綴即可構成所需列表的每項內容。

而對於Vue-Awesome圖標,我們安裝對應的組件后,它的圖標資源肯定也一定下載下來了,我們找到對應的node_modules 目錄下的文件就可以看到了,如下截圖所示。

 可以看到它的每個圖標對應一個js文件,而且不同樣式還有不同的目錄的,我們只需要自動加入對應的文件名稱即可。

定義一個js文件,如vue-awesome-icon.js,用來獲取對應Awesome圖標名稱,如下邏輯所示 

// Vue-Awesome圖標自動加入
const req = require.context('vue-awesome/icons', true, /\.js$/)
const requireAll = requireContext => requireContext.keys()

const re = /\.\/(.*)\.js/

const vueAwesomeIcons = requireAll(req).filter((key) => {
  return key.indexOf('index.js') < 0
}).map(i => {
  return i.match(re)[1]
})

export default vueAwesomeIcons

通過 require.context 的操作以及僅需filter的數組過濾,我們就可以獲得對應的Awesome圖標名稱了。

在管理頁面裏面,我們需要引入Element和Vue-Awesome的圖標管理文件,如下所示。

import elementIcons from './element-icons' // 引入Element圖標
import vueAwesomeIcons from './vue-awesome-icons' // 引入vue-awesome圖標

然後構造頁面的data數據,如下所示,其中searchForm 是用來承載查詢條件的。

export default {
  name: 'Icons',
  data() {
    return {
      // 查詢表單
      searchForm: {
        label: '',
        pagesize: 50,
        color: '#409EFF'
      },
      // 自定義svg圖標集合
      svgIcons,
      // element圖標集合
      elementIcons,
      // vueAwesome圖標集合
      vueAwesomeIcons
    }
  },

然後增加幾個Computed函數,用來處理數據的過濾查詢等操作。

 computed: {
    iconStyle: function() {
      return { color: this.searchForm.color }
    },
    elementIconsFiltered: function() {
      const that = this
      var list = that.elementIcons.filter(item => {
        return item.indexOf(that.searchForm.label) >= 0
      })
      if (that.searchForm.pagesize > 0) {
        return list.slice(0, that.searchForm.pagesize)
      } else {
        return list
      }
    },
    vueAwesomeIconsFiltered: function() {
      const that = this
      var list = that.vueAwesomeIcons.filter(item => {
        return item.indexOf(that.searchForm.label) >= 0
      })
      if (that.searchForm.pagesize > 0) {
        return list.slice(0, that.searchForm.pagesize)
      } else {
        return list
      }
    }
  },

然後在method裏面,對常規的圖標進行生成處理即可。

  methods: {
    generateElementIconCode(symbol) {
      return `<i class="el-icon-${symbol}" style="color:${this.searchForm.color};"/>`
    },
    generateAwesomeIconCode(symbol) {
      return `<v-icon name="${symbol}" style="color:${this.searchForm.color};"/>`
    },
    handleClipboard(text, event) {
      if (text) {
        clipboard(text, event)
      }
    }
  }

對於界面的展示,我們以Vue-awesome圖標展示為例介紹,如下所示。

      <el-tab-pane label="Vue-Awesome 圖標">
        <div
          v-for="item of vueAwesomeIconsFiltered"
          :key="item"
          @click="handleClipboard(generateAwesomeIconCode(item),$event)"
        >
          <el-tooltip placement="top">
            <div slot="content">{{ generateAwesomeIconCode(item) }}</div>
            <div class="icon-item">
              <v-icon :name="item" scale="2" :style="iconStyle" />
              <span>{{ item }}</span>
            </div>
          </el-tooltip>
        </div>
      </el-tab-pane>

這樣就可以實現對應圖標的動態過濾和展示了。

 

 

列出一下前面幾篇隨筆的連接,供參考:

循序漸進VUE+Element 前端應用開發(1)— 開發環境的準備工作

循序漸進VUE+Element 前端應用開發(2)— Vuex中的API、Store和View的使用

循序漸進VUE+Element 前端應用開發(3)— 動態菜單和路由的關聯處理

循序漸進VUE+Element 前端應用開發(4)— 獲取後端數據及產品信息頁面的處理

循序漸進VUE+Element 前端應用開發(5)— 表格列表頁面的查詢,列表展示和字段轉義處理

循序漸進VUE+Element 前端應用開發(6)— 常規Element 界面組件的使用

循序漸進VUE+Element 前端應用開發(7)— 介紹一些常規的JS處理函數

循序漸進VUE+Element 前端應用開發(8)— 樹列表組件的使用

循序漸進VUE+Element 前端應用開發(9)— 界面語言國際化的處理

 

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

【其他文章推薦】

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

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

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

※超省錢租車方案

FB行銷專家,教你從零開始的技巧

聚甘新

Spring系列.事務管理

Spring提供了一致的事務管理抽象。這個抽象是Spring最重要的抽象之一, 它有如下的優點:

  • 為不同的事務API提供一致的編程模型,如JTA、JDBC、Hibernate和MyBatis數據庫層 等;
  • 提供比大多數事務API更簡單的,易於使用的編程式事務管理API;
  • 完美整合Spring數據訪問抽象;
  • 支持Spring聲明式事務管理;

這篇博客就來介紹Spring事務管理相關的內容。

事務簡介

什麼是事務

事務(Transaction)一般是指對數據庫的一個或一組操作單元。

事務的作用

1、為數據庫操作提供了一個從失敗中恢復到正常狀態的方法,同時提供了數據庫即使在異常狀態下仍能保持一致性的方法。
2、當多個應用程序在併發訪問數據庫時,可以在這些應用程序之間提供一個隔離方法,以防止彼此的操作互相干擾。

當一個事務被提交給了DBMS(數據庫管理系統),則DBMS需要確保該事務中的所有操作都成功完成且其結果被永久保存在數據庫中,如果事務中有的操作沒有成功完成,則事務中的所有操作都需要被回滾,回到事務執行前的狀態(要麼全執行,要麼全都不執行);同時,該事務對數據庫或者其他事務的執行無影響,所有的事務都好像在獨立的運行。

事務的特點

事務具有4個屬性:原子性、一致性、隔離性、持久性。這四個屬性通常稱為ACID特性。

原子性(Atomicity):事務作為一個整體被執行,包含在其中的對數據庫的操作要麼全部被執行,要麼都不執行。
一致性(Consistency):事務應確保數據庫的狀態從一個一致狀態轉變為另一個一致狀態。一致狀態的含義是數據庫中的數據應滿足完整性約束。
隔離性(Isolation):多個事務併發執行時,一個事務的執行不應影響其他事務的執行。
持久性(Durability):一個事務一旦提交,他對數據庫的修改應該永久保存在數據庫中。

事務的隔離級別

在多個事務併發操作的過程中,如果控制不好隔離級別,就有可能產生臟讀、不可重複讀或者幻讀等讀現象。數據操作過程中利用數據庫的鎖機制或者多版本併發控制機制獲取更高的隔離等級。但是,隨着數據庫隔離級別的提高,數據的併發能力也會有所下降。所以,如何在併發性和隔離性之間做一個很好的權衡就成了一個至關重要的問題。

ANSI/ISO SQL定義的標準隔離級別有四種,從高到底依次為:可序列化(Serializable)、可重複讀(Repeatable reads)、提交讀(Read committed)、未提交讀(Read uncommitted)。

  1. 讀未提交
    未提交讀(READ UNCOMMITTED)是最低的隔離級別。通過名字我們就可以知道,在這種事務隔離級別下,一個事務可以讀到另外一個事務未提交的數據。未提交讀會導致臟讀

事務在讀數據的時候並未對數據加鎖。

務在修改數據的時候只對數據增加行級共享鎖。

  1. 讀已提交
    提交讀(READ COMMITTED)也可以翻譯成讀已提交,通過名字也可以分析出,在一個事務修改數據過程中,如果事務還沒提交,其他事務不能讀該數據。讀已提交會導致不可重複讀

事務對當前被讀取的數據加 行級共享鎖(當讀到時才加鎖),一旦讀完該行,立即釋放該行級共享鎖;
事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加 行級排他鎖,直到事務結束才釋放。

  1. 可重複讀
    可重複讀能保障一個事務在事務內讀到的某條數據是一致的。但是可重複讀不能解決幻讀的問題。就是在事務還沒結束時,其他事務又插入了一條新的數據。

事務在讀取某數據的瞬間(就是開始讀取的瞬間),必須先對其加 行級共享鎖,直到事務結束才釋放;
事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加 行級排他鎖,直到事務結束才釋放

  1. 序列化
    可序列化(Serializable)是最高的隔離級別,前面提到的所有的隔離級別都無法解決的幻讀,在可序列化的隔離級別中可以解決。

事務在讀取數據時,必須先對其加 表級共享鎖 ,直到事務結束才釋放;
事務在更新數據時,必須先對其加 表級排他鎖 ,直到事務結束才釋放。

下面是臟讀、不可重複讀和幻讀的解釋。

臟讀就是指當一個事務正在訪問數據,並且對數據進行了修改,而這種修改還沒有提交(commit)到數據庫中,這時,另外一個事務也訪問這個數據,然後使用了這個數據。因為這個數據是還沒有提交的數據,那麼另外一個事務讀到的這個數據是臟數據,依據臟數據所做的操作可能是不正確的。
不可重複讀:在一個事務內,多次讀同一個數據。在這個事務還沒有結束時,另一個事務也訪問該同一數據。那麼,在第一個事務的兩次讀數據之間。由於第二個事務的修改,那麼第一個事務讀到的數據可能不一樣,這樣就發生了在一個事務內兩次讀到的數據是不一樣的,因此稱為不可重複讀,即原始讀取不可重複。
幻讀指的是一個事務在前後兩次查詢同一個範圍的時候,后一次查詢看到了前一次查詢沒有看到的數據行。幻讀專指“新插入的行”是不可重複讀(Non-repeatable reads)的一種特殊場景

Spring事務

Spring事務模型的優勢

事務可以分為本地事務和全局事務,這兩種事務都有一定程度的局限性,Spring框架的事務管理支持解決全局和本地事務模型的局限性。

1. 全局事務
全局事務可以讓你跨多個事務進行工作,比如你的事務同事包含多個關係型數據庫,也可以包含關係型數據庫和JMS事務。一般情況下都是通過JTA來實現全局事務,但是JTA一般需要具體的應用容器來支持,這就導致代碼的通用性較低。

下面舉個全局事務的列子,方便理解。

在電商網站上,在消費者點擊購買按鈕后,交易後台會進行庫存檢查、下單、減庫存、更新訂單狀態等一連串的服務調用,每一個操作對應一個獨立的服務,服務一般會有獨立的數據庫,因此會產生分佈式事務問題。分佈式事務就是一種比較常見的全局事務。

2. 本地事務

本地事務和具體的某個事務關聯,比如說JDBC事務。本地事務比較簡單,但是不能實現分佈式事務的功能。

Spring提供了統一方便的事務編程模型,可以解決上面本地事務和全局事務的局限。使用Spring的事務API進行事務管理,底層可以適應各種事務資源。

Spring事務抽象

Spring為提供統一的事務編程模型,提供相關的接口。主要接口如下:

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

    void commit(TransactionStatus status) throws TransactionException;

    void rollback(TransactionStatus status) throws TransactionException;
}

上面接口的getTransaction方法接收一個TransactionDefinition參數,返回一個TransactionStatus 值。其中TransactionStatus 可能代表一個新的事務,或者返回一個已經存在本次調用棧中的事務。(TransactionStatus 和具體的線程綁定。可以自己寫代碼測試下)

TransactionStatus接口定義如下。

public interface TransactionStatus extends SavepointManager {

    boolean isNewTransaction();

    boolean hasSavepoint();

    void setRollbackOnly();

    boolean isRollbackOnly();

    void flush();

    boolean isCompleted();
}

聲明式事務管理

使用Spring的事務管理,推薦使用聲明式事務管理。Spring的聲明式事務管理是通過Spring的AOP功能實現的。

因為平時在開發過程中都是使用註解的方式使用聲明式事務。下面就介紹註解的方式。

step1:添加@EnableTransactionManagement註解

@Configuration
@EnableTransactionManagement
@MapperScan("com.csx.demo.spring.boot.dao")
public class MyBatisConfig {

}

step2:添加@Transactional註解到接口的實現。

@Service
@Transactional(readOnly = true,rollbackFor = Exception.class)
public class SysUserServiceImpl implements SysUserService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public int saveSysUser(SysUser user) {
        int i = sysUserMapper.insert(user);
        return i;
    }
}

使用Spring的聲明式事務就這麼簡單。

當你使用Spring的AOP方式來使用事務的話,你添加@Transactional註解的方法一定要是public的,不然事務不會生效。

假如你需要讓非public的方法生效,你需要使用AspectJ 的AOP實現。(說明:Spring的AOP功能有兩種實現方式,一種是Spring自己實現的AOP功能,主要是通過JDK動態代理或者CGLIB動態代理實現的。還有一種方式是整合AspectJ 這個第三方AOP框架實現的)

另外,@Transactional註解可以添加到接口、接口中的方法定義、類和類裏面的方法。Spring團隊建議將註解加到具體的類和方法實現上,而不是加到接口定義上(原因見下面英文描述)。當然,您可以將@Transactional註釋放在接口(或接口方法)上,但是只有在使用基於接口的代理時,才會像您期望的那樣工作。

The fact that Java annotations are not inherited from interfaces means that, if you use class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), the transaction settings are not recognized by the proxying and weaving infrastructure, and the object is not wrapped in a transactional proxy.

@Transactional註解的配置

@Transactional註解可以進行以下配置。

Property Type Description
value String 一個項目中可以存在多個事務管理器,這個值用於指定具體使用哪個事務管理器。
propagation enum: Propagation 設置傳播機制
isolation enum: Isolation 設置隔離級別(只有當傳播機制設置成 REQUIRED or REQUIRES_NEW時這個配置才生效)
timeout int (in seconds of granularity) 設置超時時間(以秒為單位,只有當傳播機制設置成 REQUIRED or REQUIRES_NEW時這個配置才生效)
readOnly boolean 只讀事務配置(只有當傳播機制設置成 REQUIRED or REQUIRES_NEW時這個配置才生效)
rollbackFor Array of Class objects, which must be derived from Throwable. 回滾的異常
rollbackForClassName Array of class names. The classes must be derived from Throwable.
noRollbackFor Array of Class objects, which must be derived from Throwable. 不回滾的異常
noRollbackForClassName Array of String class names, which must be derived from Throwable.

假如我們沒有配置上面的屬性,這些屬性也都是有默認值的

  • The propagation setting is PROPAGATION_REQUIRED.
  • The isolation level is ISOLATION_DEFAULT.
  • The transaction is read-write.
  • The transaction timeout defaults to the default timeout of the underlying transaction system, or to none if timeouts are not supported.
  • Any RuntimeException triggers rollback, and any checked Exception does not.(默認回滾RuntimeException )

多事務管理器

有時候項目中可能會存在多個事務管理器,比如JDBC事務,比如JMS事務。這時候我們可以通過transactionManager屬性指定。

public class TransactionalService {

    @Transactional("jdbc")
    public void setSomething(String name) { ... }

    @Transactional("jms")
    public void doSomething() { ... }
}

上面的jdbc和jms是指兩個事務管理器在Spring容器中Bean的名字。

事務的傳播機制

在TransactionDefinition這個類中定義了6中傳播機制的類型。

1. PROPAGATION_REQUIRED

2. PROPAGATION_REQUIRES_NEW

3. PROPAGATION_NESTED

只支持JDBC事務。

編程式事務管理

Spring框架提供兩種方式來進行編程式事務管理:

  • The TransactionTemplate.
  • PlatformTransactionManager 的實現。

Spring團隊推薦使用第一種方式進行編程式事務管理。

1. 使用TransactionTemplate進行事務管理

下面是使用TransactionTemplate進行事務管理的一個例子。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TxApp.class)
public class TxTest {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Test
    public void selectUserTest() {

        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        //同一個sqlSession創建的Mapper
        SysUserMapper mapper = sqlSession1.getMapper(SysUserMapper.class);
        SysUser sysUser = new SysUser();
        sysUser.setUsername("zyzl");
        sysUser.setPassword("11");

        //有返回值的操作
        transactionTemplate.execute(new TransactionCallback() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
                try {
                    return mapper.insert(sysUser);
                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;
                }
            }
        });

        //沒返回值的操作
        transactionTemplate.executeWithoutResult(new Consumer<TransactionStatus>() {
            @Override
            public void accept(TransactionStatus transactionStatus) {
                try {
                    mapper.insert(sysUser);
                } catch (Exception e) {
                    transactionStatus.setRollbackOnly();
                    throw e;
                }
            }
        });
    }

}

我們也可以通過TransactionTemplate來設定事務的隔離級別等屬性。

//設置隔離級別
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
//設置超時時間
transactionTemplate.setTimeout(30);
//設置傳播機制
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

對於不同的事務操作,如果需要不同的隔離級別和傳播機制的話,請使用不同的transactionTemplate。也就是說,你要創建不同的transactionTemplate對象來進行操作。

2. 使用PlatformTransactionManager進行事務管理

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
// 設置傳播機制
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//開啟事務
TransactionStatus status = txManager.getTransaction(def);
try {
    // execute your business logic here
}
catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
//提交事務
txManager.commit(status);

事務綁定事件

使用@TransactionalEventListener可以在事務提交前後,回滾后等階段觸發某些操作。但是這個功能暫時還沒想到很好的使用場景。後續有需要再來用。

@Component
public class MyComponent {

    @TransactionalEventListener
    public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
        // ...
    }
}

重要類和接口

  • PlatformTransactionManager:事務管理器,用於獲取事務,提交回滾事務;
  • TransactionDefinition:
  • TransactionStatus:代表一個事務

進一步閱讀

Distributed transactions in Spring, with and without XA is a JavaWorld presentation in which Spring’s David Syer guides you through seven patterns for distributed transactions in Spring applications, three of them with XA and four without.(Spring實現分佈式事務的介紹)

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

【其他文章推薦】

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

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

※超省錢租車方案

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

網頁設計最專業,超強功能平台可客製化

聚甘新

.Net Core Configuration Etcd數據源

前言

    .Net Core為我們提供了一套強大的Configuration配置系統,使用簡單擴展性強。通過這套配置系統我們可以將Json、Xml、Ini等數據源加載到程序中,也可以自己擴展其他形式的存儲源。今天我們要做的就是通過自定義的方式為其擴展Etcd數據源操作。

何為Etdc

    在使用etcd之前我們先介紹一下Etcd,我相信很多同學都早有耳聞。Etcd是一款高可用、強一致的分佈式KV存儲系統,它內部採用raft協議作為一致性算法,本身也是基於GO語言開發的,最新版本為v3.4.9,具體版本下載地址可參閱官方GitHub地址。相信了解過K8S的同學對這個肯定不陌生,它是K8S的數據管理系統。官方地址為https://etcd.io/。
    在此之前,我相信大家已經了解過很多存儲系統了,Etcd到底能實現了什麼功能呢?其一用於配置中心和服務發現,再者也可以實現分佈式鎖和消息系統。它本身就是基於目錄型存儲,並且內部有一套強大的Watch機制可以監聽針對節點和數據的操作變化,每次對節點的事務操作都會有對於的版本信息。

Etcd VS Zookeeper

通過上面的介紹是不是感覺和Zookeeper有點類似呢,網上有很多很多關於Etcd和Zookeeper的對比文章,大致如下可以得到以下結論

功能 Etcd Zookeeper
分佈式鎖 有(採用節點版本號信息) 有(採用臨時節點和順序臨時節點)
watcher
一致性算法 raft zab
選舉
元數據(metadata)存儲
應用場景 Etcd Zookeeper
發布與訂閱(配置中心) 有(不限次Watch) 有(一次性觸發的,需要重新註冊Watch)
軟負載均衡
命名服務(Naming Service)
服務發現 有(基於租約節點) 有(基於臨時節點)
分佈式通知/協調
集群管理與Master選舉
分佈式鎖
分佈式隊列

說白了就是Zookeeper能幹的活,Etcd也能幹。那既然有了Zookeeper為啥還要選擇Etcd,主要基於以下原因

  • 更輕量級(Etcd基於GO語言開發,Zookeeper基於Java開發)、更易用(開箱即用)
  • 高負載下的穩定讀寫
  • 數據模型的多版本併發控制
  • 穩定的watcher功能,通知訂閱者監聽值的變化(Zookeeper基於數據的監聽是一次性的,每次監聽完成還需重新註冊)
  • 客戶端協議使用GRPC協議,支持語言更廣泛

一言以蔽之,就是不僅實現了Zookeeper的功能,還在很多方面吊打Zookeeper,這麼強大的東西忍不住都要試一試。

在.Net Core中使用Etcd

    在Nuget上可以搜索到很多.Net Core的Etcd客戶端驅動程序,我使用了下載量最多的一個名字叫dotnet-etcd的驅動包,順便找到了它在GayHub上,不好意思手滑打錯了GitHub上的項目地址,大概學習了一下基本的使用方式。其實我們結合Configuration配置這一塊,只需要兩個功能。一個是Get獲取數據,另一個是Watch節點變化(更新數據會用到)。個人認為,前期有目有邊界的學習還是非常重要的。

Configuration擴展Etcd

前面我們講到過自定義擴展Configuration是非常方便的,相信了解過Configuration相關源碼的小夥伴們已經非常熟悉了,大致總結一下分為三步:

  • 編寫IConfigurationBuilder擴展方法,我們這裏叫AddEtcd
  • 編寫實現IConfigurationSource的配置源信息類,我們這裏叫EtcdConfigurationSource
  • 編寫繼承自ConfigurationProvider的ConfigurationSource的配置數據提供類,我們這裏叫EtcdConfigurationProvider

因為微軟已經給我們提供了一部分便利,所以編寫起來還是非常的簡單的。好了,接下來我們開始編寫具體的實現代碼,重點的地方我會在代碼中註釋說明。

首先是定義擴展類EtcdConfigurationExtensions,這個類是針對IConfigurationBuilder的擴展方法,實現如下

public static class EtcdConfigurationExtensions
{
    /// <summary>
    /// AddEtcd擴展方法
    /// </summary>
    /// <param name="serverAddress">Etcd地址</param>
    /// <param name="path">讀取路徑</param>
    /// <returns></returns>
    public static IConfigurationBuilder AddEtcd(this IConfigurationBuilder builder, string serverAddress,string path)
    {
        return AddEtcd(builder, serverAddress:serverAddress, path: path,reloadOnChange: false);
    }

    /// <summary>
    /// AddEtcd擴展方法
    /// </summary>
    /// <param name="serverAddress">Etcd地址</param>
    /// <param name="path">讀取路徑</param>
    /// <param name="reloadOnChange">如果數據發送改變是否刷新</param>
    /// <returns></returns>
    public static IConfigurationBuilder AddEtcd(this IConfigurationBuilder builder, string serverAddress, string path, bool reloadOnChange)
    {
        return AddEtcd(builder,options => {
            options.Address = serverAddress;
            options.Path = path;
            options.ReloadOnChange = reloadOnChange;
        });
    }

    public static IConfigurationBuilder AddEtcd(this IConfigurationBuilder builder, Action<EtcdOptions> options)
    {
        EtcdOptions etcdOptions = new EtcdOptions();
        options.Invoke(etcdOptions);
        return builder.Add(new EtcdConfigurationSource { EtcdOptions = etcdOptions });
    }
}

這裏我還定義了一個EtcdOptions的POCO,用於承載讀取Etcd的配置屬性

public class EtcdOptions
{
    /// <summary>
    /// Etcd地址
    /// </summary>
    public string Address { get; set; }

    /// <summary>
    /// Etcd訪問用戶名
    /// </summary>
    public string UserName { get; set; }

    /// <summary>
    /// Etcd訪問密碼
    /// </summary>
    public string PassWord { get; set; }

    /// <summary>
    /// Etcd讀取路徑
    /// </summary>
    public string Path { get; set; }

    /// <summary>
    /// 數據變更是否刷新讀取
    /// </summary>
    public bool ReloadOnChange { get; set; }
}

接下來我們定義EtcdConfigurationSource,這個類非常簡單就是返回一個配置提供對象

public class EtcdConfigurationSource : IConfigurationSource
{
    public EtcdOptions EtcdOptions { get; set; }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new EtcdConfigurationProvider(EtcdOptions);
    }
}

真正的讀取操作都在EtcdConfigurationProvider里

public class EtcdConfigurationProvider : ConfigurationProvider
{
    private readonly string _path;
    private readonly bool _reloadOnChange;
    private readonly EtcdClient _etcdClient;

    public EtcdConfigurationProvider(EtcdOptions options)
    {
        //實例化EtcdClient
        _etcdClient = new EtcdClient(options.Address,username: options.UserName,password: options.PassWord);
        _path = options.Path;
        _reloadOnChange = options.ReloadOnChange;
    }

    /// <summary>
    /// 重寫加載方法
    /// </summary>
    public override void Load()
    {
        //讀取數據
        LoadData();
        //數據發生變化是否重新加載
        if (_reloadOnChange)
        {
            ReloadData();
        }
    }

    private void LoadData()
    {
        //讀取Etcd里的數據
        string result = _etcdClient.GetValAsync(_path).GetAwaiter().GetResult();
        if (string.IsNullOrEmpty(result))
        {
            return;
        }
        //轉換一下數據結構,這裏我使用的是json格式
        //讀取的數據只要賦值到Data屬性上即可,IConfiguration真正讀取的數據就是存儲到Data的字典數據
        Data = ConvertData(result);
    }

    private IDictionary<string,string> ConvertData(string result)
    {
        byte[] array = Encoding.UTF8.GetBytes(result);
        MemoryStream stream = new MemoryStream(array);
        //JsonConfigurationFileParser是將json數據轉換為Configuration可讀取的結構(複製JsonConfiguration類庫里的)
        return JsonConfigurationFileParser.Parse(stream);
    }

    private void ReloadData()
    {
        WatchRequest request = new WatchRequest()
        {
            CreateRequest = new WatchCreateRequest()
            {
                //需要轉換一個格式,因為etcd v3版本的接口都包含在grpc的定義中
                Key = ByteString.CopyFromUtf8(_path)
            }
        };
        //監聽Etcd節點變化,獲取變更數據,更新配置
        _etcdClient.Watch(request, rsp =>
        {
            if (rsp.Events.Any())
            {
                var @event = rsp.Events[0];
                //需要轉換一個格式,因為etcd v3版本的接口都包含在grpc的定義中
                Data = ConvertData(@event.Kv.Value.ToStringUtf8());
                //需要調用ConfigurationProvider的OnReload方法觸發ConfigurationReloadToken通知
                //這樣才能對使用Configuration的類發送數據變更通知
                //比如IOptionsMonitor就是通過ConfigurationReloadToken通知變更數據的
                OnReload();
            }
        });
    }
}

使用方式如下

builder.AddEtcd("http://127.0.0.1:2379", "service/mydemo", true);

順便給大家推薦一個Etcd可視化管理工具ETCD Manager,以便更好的學習Etcd。
到這裏,基本上就結束了,是不是非常簡單。主要還是Configuration本身的設計思路比較清晰,所以實現起來也不費勁。

總結

    以上代碼都已經上傳了我的GitHub,該倉庫還擴展了其他數據源的讀取比如Consul、Properties文件、Yaml文件的讀取,實現思路也都大致相似,有興趣的同學可以自行查閱。由於主要是講解實現思路,可能許多細節並未做處理還望見諒。如果有疑問或者更好的建議,歡迎評論區交流指導。

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

聚甘新

Redis 數據結構 之 SDS

SDS(simple dynamic string),簡單動態字符串。s同時它被稱為 Hacking String。hack 的地方就在 sds 保存了字符串的長度以及剩餘空間。sds 的實現在 sds.c 中。

C語言字符串使用長度為n+1的字符數組來表示長度為n的字符串,並且字符數組的最後一個元素總是空字符’\0’,這樣的方式存儲,時存在安全隱患的,並且它不能滿足效率方面的需求。

因此Redis沒有使用C原生的string而是自己構建了SDS。在Redis里,C語言字符串只用於一些無須對字符串值進行修改的地方,比如:日誌。

在Redis中,包含字符串值的鍵值對都是使用SDS實現的,除此之外,SDS還被用於AOF緩衝區、客戶端狀態的輸入緩衝區。

SDS定義

struct sdshdr{
     //字節數組
     char buf[]; 
     //buf數組中已使用字節數量
     int len;
     //buf數組中未使用字節數量
     int free;
}

如上圖所示,len表示該SDS保存了一個6字節長度(不包含結束符)的字符串,free表示該SDS還有6個字節的未使用空間,buf是一個char類型的數組 ,保存了該SDS所存儲的字符串值。

高效

相比C語言字符串,使獲取字符串長度時間複雜度降為O(1)而C原生的獲取長度為O(N) 遍歷整個數組。

安全

同時SDS杜絕緩衝區溢出,不會像C那樣造成數組數據不安全,絕對不會越界。

當需要對SDS進行修改時,API會先檢查SDS當前剩餘空間是否滿足修改之後所需的空間,如果不滿足的話API會自動將SDS的空間擴展至足夠用的空間然後才進行下一步操作,所以SDS不會出現緩衝區溢出問題。

減少內存分配

C語言字原生符串底層是使用一個n+1個字符長度的char類型數據實現的,所以每次增長或縮短一個原生字符串,程序都要對這個字符串數組進行一次內存重分配操作:

同時因為內存重分配涉及複雜的算法,並且可能需要執行系統調用,所以它通常是一個比較耗時的操作。Redis經常被用於速度要求嚴苛、數據被頻繁修改的場合,如果每次修改字符串都需要執行一次內存重分配的話,那麼對於性能會造成很大影響。

SDS 在分配了內存之後(往往空間會存在盈餘,也就是空間的預分配),然後自己通過len 和 free 來維護已使用的和未使用的內存,不再依賴系統來重新劃分,這樣能有效的提升性能。

空間預分配

用於字符串增長操作,當字符串增長時,程序會先檢查需不需要對SDS空間進行擴展,如果需要擴展,程序不僅會為SDS分配修改所必要的空間,還會為SDS分配額外的未使用空間,額外分配的未使用空間公式如下:

SDS空間 < 1MB

如果對SDS修改之後,SDS的長度(修改之後len屬性的值)小於1MB,那麼則分配和len屬性同樣大小的未使用空間,這時SDS的len屬性和free屬性的值相同。如:如果修改之後SDS的len將變為10字節,那麼程序也會分配10字節的未使用空間,SDS的buf數組實際長度變為10 + 10 + 1 = 21(額外一個字節用於保存結束符\n)

SDS空間 > 1MB

如果對SDS修改之後,SDS的長度大於等於1MB,那麼程序會分配1MB的未使用空間。如:修改之後的len將變為10MB,那麼程序會分配1MB的未使用空間,SDS的bug數組長度為10MB + 1MB + 1byte

SDS空間 > 512MB

Game over~ 報錯!

惰性空間釋放

用於優化SDS的字符串收縮操作,當字符串收縮時,程序不會立即執行內存重分配來回收收縮后內存多出來的空間,而是使用free屬性記錄下來,以備將來使用。

通過空間預分配,Redis可以減少連續執行字符串增長操作所需的內存重分配次數,通過惰性空間釋放,SDS避免了縮短字符串時所需的內存重分配操作,併為將來由可能的增長操作提供了優化。

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

FB行銷專家,教你從零開始的技巧

聚甘新

法國新任環境部長:不排除改組法電公司

摘錄自2018年9月10日法廣報導

法國世界報在本周一(10日)發布了一篇對法國新任環境部長德魯吉的專訪,其中數點提到了法國電力公司。

法電公司此前一直要求政府儘快落實法國境內新一座壓水反應堆核電廠的建造。對此,德魯吉不置可否,但強調「法電公司首先要證明,壓水反應堆核電廠是能用的,現在情況沒有體現出來壓水反應堆核電廠可用,沒人能保證現有的壓水反應堆核電廠什麼時候能啟動。法電公司還需要證明,壓水反應堆核電廠在費用方面具有競爭力。」德魯吉表示,無論如何,除了法國最老舊的,仍然運轉的核電廠費森海姆被關閉之外,要關閉的核電廠還有很多。法國將在今年10月底公布系列核電廠反應堆的關閉日程表。

對於辭職的前任環境部長於洛曾經提到的改組法電公司的可能性,新任環境部長德魯吉表示,已經對改組與否有了想法。他表示,法電公司不僅要進行能源轉型,而且要關注企業債務問題。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

聚甘新

WTO檢討 促台推動農產品貿易自由化

摘錄自2018年9月11日中央社布魯塞爾報導

經濟部次長王美花率團出席世界貿易組織(WTO)對台灣第4次貿易政策檢討會議,歐盟代表在會中讚台灣經濟基本面良好,但呼籲台灣加速制定殘留許可限制,推動農產品貿易自由化。

台灣第4次貿易政策檢討會議12日至14日在WTO瑞士日內瓦總部召開,由經濟部次長王美花率團與會,與會代表包括行政院經貿談判辦公室、外交部、農委會、財政部、金管會、經濟部工業局、智慧財產局及國際貿易局等單位。

根據經濟部發布新聞稿,王美花在會中說明台灣過去4年經貿政策,重申支持自由多邊貿易體系及WTO,表示將與會員合作改善WTO;也說明台灣正實行推動加入跨太平洋夥伴全面進步協定(CPTPP)、推動數位經濟及前瞻計畫等經貿政策,並以新南向政策強化與該地區連結。

此外,台灣正大力推動永續能源政策,目標在2025年達到再生能源占比20%目標,藉此鼓勵投資與創造就業,並承諾協助其他WTO開發中會員共同達到聯合國永續發展目標。

擔任與談人的歐盟駐WTO大使范亥克倫(Marc Vanheukelen)彙整22個會員國提出的400多項書面問題,主要關注議題包括簡化外人投資審查程序、食品安全應採用國際標準,並基於科學證據及簡化農藥殘留容許量的程序、農業進口稅率遠高於工業產品、履行農業境內支持通知義務、漁業補貼、擴大政府採購開放範圍、擴大對低度開發國家產品進口優惠。

范亥克倫強調,台灣應加速制訂殘留許可限制(MRL),推動農產品貿易自由化,以及推動人才培養與經濟永續發展。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

※超省錢租車方案

FB行銷專家,教你從零開始的技巧

聚甘新

MIT 認為核電不可或缺,小型模組式核反應爐為發展重點

摘錄自2018年9月12日科技新報美國報導

麻省理工能源研究計畫(MITEI)最新研究,若要在低成本與對社會影響低的情況下實現低碳未來,核能是不可或缺的元素之一,建議應捨棄傳統的大型電廠,發展成本低與裝置更靈活的小型模組式核反應爐。

先前美國核能管理委員會(NRC)也放行英商 NuScale Power 的模組式反應爐的第一階段審核,根據官網資料,該小型核反應爐大小 23×5 公尺,重量僅 700 公噸,熱容量達 160 MWt、可產生 50 MW 電力,其發電性能不差、體積更是遠比傳統的核反應爐還要小。

處於實驗室階段的第四代核電廠行波反應爐也屬於模組式設計,製造成本則比傳統核反應爐更加便宜,有別於 LWR 等前幾代核技術,行波反應爐不需要濃縮鈾,使用核廢料貧化鈾就可以運行,自產的核廢料也能回收利用。假如該技術成功跨出商業化門檻,核廢料問題將可大大減少。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※超省錢租車方案

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

網頁設計最專業,超強功能平台可客製化

聚甘新