20萬大空間/高顏值轎車 媳婦喜歡丈母娘滿意

國內消費者最關心的乘坐空間,2805mm軸距的起亞表現的很好,以175cm的體驗者為例,前後排可活的一拳的頭部空間,後排頭部空間超兩拳,提供了1。6T/2。0L/2。0T三種排量可供選擇,搭配6擋手自一體或者7擋雙離合變速箱,選擇性很強。

國人買東西都有一個共同的特點

就是大大大大大大大大大大大大

手機必須上大屏的

鑽戒要買大的

那車子當然是越大越好

前段時間一條火爆的廣告刷爆了朋友圈

致25歲還一無是處的本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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

能兼顧到家用還開着爽 這幾款車只需要10萬起!

6L、1。8L以及2。0L三款發動機,傳動系統配備5擋手動以及大家最熟悉的CVT變速箱。CVT變速箱動力輸出十分平順,也非常適合在日常城市道路駕馭。硬朗的底盤以及韌性不錯的懸挂,加上ASC車身穩定系統,能給駕駛者足夠的信心。一汽-大眾-速騰指導價:13。

前言

對於80後部分朋友已成家立室,上有老下有小,買車必須要考慮到家用,而心中存在着一份激情,開着也能讓自己爽。所以對於這部分朋友來說,選擇操控好,還能兼顧到家用,也是他們首要的目標。

長安馬自達-馬自達3 Axela昂克賽拉

指導價:11.49-15.99萬

昂克賽拉沿用了馬自達最新“魂動”家族化設計, 前臉造型如同獵豹,視覺感受更加富有攻擊性以及活力的風格,尾部設計較為簡潔,整體設計風格時尚年輕。

內飾正是昂克賽拉的創新所在,雖然簡潔,但整體內飾氛圍更具運動感,車廂做工用料方面,比較厚道!

昂克賽拉更有兩個版本可選,三廂以及兩廂車型,空間方面,能夠滿足日常出行,三廂版/兩廂版行李箱的容積為419L、350L,長途駕駛三廂版實用性更高。

昂克賽拉搭載了1.5L以及2.0L兩款自然吸氣發動機,也是馬自達最新“創馳藍天”發動機,我相信大家也非常了解這款發動機,其優點就是能擁有相對低的油耗還能兼顧到充沛的動力輸出,傳動系統配備了6擋手動、6擋手自一體變速箱。底盤的質感高級,從容紮實,懸挂的調校偏運動,能有很好的操控性還能兼顧舒適性。

東南汽車-翼神

指導價:9.58-13.98萬

翼神外觀採用了三菱經典的鯊魚嘴仿生學造型設計,黑色的大嘴結合成一體,尾部設計較為驚艷,有層次感。翼神整體的設計更加霸氣有力!

翼神內飾主要以黑色為主,中控設計布局簡潔以及在物理按鍵上很到位,整體車廂氛圍很有戰鬥感。

翼神車身長寬高為4570*1760*1490mm,軸距為2635mm,空間表現,寬敞也能輕鬆翹個二郎腿,座椅填充物軟硬適中,包裹性也很足。

動力方面,翼神搭載了1.6L、1.8L以及2.0L三款發動機,傳動系統配備5擋手動以及大家最熟悉的CVT變速箱。CVT變速箱動力輸出十分平順,也非常適合在日常城市道路駕馭。硬朗的底盤以及韌性不錯的懸挂,加上ASC車身穩定系統,能給駕駛者足夠的信心。

一汽-大眾-速騰

指導價:13.18-21.88萬

速騰外觀設計依然還是很大眾,家族式設計並沒有太多的亮點,圓滑的車身造型以及流暢動感線條,速騰依然不失時尚感。

內飾設計依然還是大眾風格,雖然是大眾風格,但其整體設計風格很耐看,甚至會有那麼一絲高級感,做工用料上採用了些許硬質材料,視覺效果並不差,依然簡潔。

速騰車身長寬高為4655*1780*1453mm,軸距為2651mm,空間表現,可以說是速騰最引以為傲的地方,蹺二郎腿毫無壓力。

動力方面,速騰搭載了1.2T、1.4T.1.6T以及2.0T四款發動機,可供消費者選擇較多,傳動系統方面配備5擋手動、6擋手自一體、7擋雙離合變速箱,購買雙離合車型的消費者也無需擔心其的耐用性以及平順性,大眾也做了特別多的優化。底盤依然是大眾一貫的風格調校,紮實,速騰懸挂調校也偏向舒適。

全文總結

整體來說,這三款車都有運動基因的底子,能兼顧到家用以及在操控性方面也不錯,產品力也很強!加上現在優惠幅度也比較大,也值得入手。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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

都是六萬多,這三個漂亮的、配置高的SUV哪個是你的菜

如果車長真的達到4420mm,軸距也不會只有2510mm。雖然都是“3”,但是瑞虎3和DX3是截然不同的兩種設計風格。DX3走的完全是時尚路線,瑞虎3則成熟穩重許多。沒有改款前的內飾看起來比較過時,如今2016款的造型還說的過去。變得更加有層次感,看起來也年輕許多了。

六萬多的裸車,想買一台不錯的車子,只有考慮自主品牌的車子了,因為這個價位合資車幾乎沒有什麼好的選擇,要麼就是丑到家,要麼就是配置很寒磣。

但是如果選擇自主品牌的話,那麼路一下子就會變得特別寬,可以有很多不錯的選擇,尤其是對於自主品牌密集布局的SUV領域。所以小編選出了下面三台車子,看看哪台是你的菜。

東南汽車-東南DX3

指導價:6.79-10.09萬

DX3的車身尺寸為4354*1840*1670mm,軸距為2610mm,因為DX7的外觀獲得了不少消費者的讚譽,所以這次DX3的設計還是由賓尼法利納設計中心完成。不得不說,DX3的外觀確實比較驚艷,犀利的前臉,凌厲的腰線,懸浮式車頂設計,這一切都讓DX3看起來非常時尚。

內飾和外觀一樣,不僅好看,更重要的是原創性也非常高。據DX3的設計師設計透露,DX3的內飾設計風格為“永恆之美”,反正我也不知道什麼叫做永恆之美,只知道看起來挺時尚的。不過內飾的配色也很豐富,可以提供棕+黑、紅+黑兩種配色。

DX3的空間表現很好,後排空間較為寬裕,在同級別中處於中等偏上的水準。它的動力系統為1.5L 120馬力+5擋手動,1.5T 156馬力+CVT變速箱。其實如果預算比較吃緊的話,1.5L的發動機就可以滿足日常家用了,即使是最低配,也會配備車身穩定系統、胎壓監測、上坡輔助、陡坡緩降、后視鏡電動調節。安全配置和實用配置都有,所以對於資金不充足的消費者來說,低配就夠了。

奇瑞汽車-瑞虎3

指導價:6.89-9.29萬

瑞虎3的車身尺寸為4420*1760*1670mm,軸距為2510mm。不要被數據蒙蔽了,其實虎3的車長是加上那個外掛的備胎了。如果車長真的達到4420mm,軸距也不會只有2510mm。雖然都是“3”,但是瑞虎3和DX3是截然不同的兩種設計風格。DX3走的完全是時尚路線,瑞虎3則成熟穩重許多。

沒有改款前的內飾看起來比較過時,如今2016款的造型還說的過去。變得更加有層次感,看起來也年輕許多了。尤其是中控大屏,可以立馬增加中控的檔次感。

瑞虎3的動力系統為1.6L 126馬力+5擋手動/CVT變速箱。老款的瑞虎3沒有車身穩定系統,遭到了吐槽,現在瑞虎3終於標配了ESp,性價比提升了很多。同時奇瑞的瑞虎系列也有了一定的歷史了,質量還是挺讓人放心的,不管是手動擋還是CVT車型,質量方面都有着比較穩定的表現。

凱翼汽車-凱翼X3

指導價:6.66-9.69萬

凱翼X3的車身尺寸為4335*1796*1665mm,軸距為2530mm。凱翼X3也是小型SUV,車身尺寸在同級別並不佔什麼優勢,雖然凱翼X3的外觀經過了重新的設計,變得年輕時尚許多,但是在車身側面和車尾,仍有一些瑞虎3的影子。

中控內飾極其簡約,沒有什麼複雜的線條做映襯,可以看出來設計師是盡量追求簡介的設計風格,中控台的按鍵數目屈指可數。不過中控台的用料很不錯。部分區域採用了搪塑工藝,手感較好。

凱翼X3的動力系統為1.6L 126馬力+5擋手動/CVT,動力表現和瑞虎3較為相近。其實就配置而言,凱翼X3的配置要低於DX3和瑞虎3的。不過凱翼X3也有着自己的特色,比如更加討人喜歡的外觀。

總結:相對來說DX3和瑞虎3的性價比都很高,配置很實在,DX3的外觀看起來更年輕,瑞虎3則更適合比較穩重的消費者,至於凱翼X3,如果你覺得瑞虎3的外觀有點過於成熟的話,那麼可以看看凱翼X3,雖然它的性價比沒有瑞虎3那麼高。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

※回頭車貨運收費標準

要是明年別克將這車國產 告訴我你買不買賬?

基於輕量化平台打造后,新君威不僅車重減輕,車身和軸距都相應加長了55mm和92mm,加上車尾採用的溜背設計,未來新君威的後排空間必定提升不少。新君威在未來也有望搭載1。5T/2。0T發動機,其中1。5T車型極有可能搭載7速雙離合變速箱。

相信大家對別克君威都不陌生,這輛中級轎車從以前主打舒適穩重的風格向後期年輕化的運動范轉變。而最近它的姊妹車歐寶Insignia實車也亮相了,新一代君威的外觀基本會與其相同。

可能很多人已經淡忘了歐寶這個品牌,實際上作為通用旗下的子品牌,歐寶、別克和沃克斯豪爾(Vaxuhall)都存在着換標車型。同一款車彼此換上不同的logo,在不同的國家地區發售。

而歐寶Insignia所對應的車型分別是別克的君威和霍頓的Commodore(沒錯,霍頓同樣是通用的子品牌)。這輛未來的新君威走了略帶豪華的運動風格,不論是前臉還是腰線的設計都顯得非常運動,只不過到時進來國產的時候,外觀肯定會有一些調整,而這款Insignia則有可能在明年日內瓦車展發布,而新君威則有望在明年國產。

基於輕量化平台打造后,新君威不僅車重減輕,車身和軸距都相應加長了55mm和92mm,加上車尾採用的溜背設計,未來新君威的後排空間必定提升不少。

新君威在未來也有望搭載1.5T/2.0T發動機,其中1.5T車型極有可能搭載7速雙離合變速箱。只不過在國內眾多消費者對於別克的變速箱印象都很一般,未來國產車型還是得要多花點心思好好調整下了。

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

【其他文章推薦】

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

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

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

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

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

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

※回頭車貨運收費標準

看懂就是省錢!賣一輛車4S店可以賺你多少錢?

汽車廠家整車利潤據網上資料显示,在國內,主流汽車廠家的整車利潤一般在10%左右,這個数字可能大家看了都不相信,因為在中國,很多人都認為汽車廠家是超賺錢的,當然,這10%其實不包括其中零散配件的價格利潤,現在是全球化時代,許多汽車廠家都會和許多知名的汽車配件,發動機和變速箱公司合作,其中這些核心部件在買賣當中究竟是有着多少利潤可言,關於這個問題,汽車廠家則以汽車技術不外露為理由,並沒有公開給我們廣大消費者。

相信大家在買車的時候都相信一個道理,絕大多數的汽車,具有一個官方的廠商指導價,但一般我們在4S店裡購買的話,在這個基礎價格上,還能有着幾千上萬的優惠幅度,放眼全國,也存在着30萬的車降價7萬,20萬的車降價3萬元的情況,降價幅度如此之大,不由得讓人懷疑,這樣子4S店為何還能賺到錢?而且一輛車的成本是有多低?

許多消費者在買車的時候,似乎不會去關注這個問題,認為只要車合適價格滿意,這就達成了購買的協議,但一輛車為何能夠降價這麼多,例如花了20萬元買了台雅閣,其中有多少錢真正屬於這輛車的?繼續往下看。

買一輛車的錢,可以分為5個部分,分別是:稅費,技術轉讓費,汽車廠家整車利潤,4S店利潤,轎車成本。

稅費

廠家需要繳納的稅費:消費稅,增值稅

消費者需要繳納是稅費:購置稅

從網上相關數據的查閱中發現,每一輛車需要繳納的稅收佔著汽車價格的23%左右,消費者購車后繳納10%的車輛購置稅(雖然精準的購置稅算法為發票÷1.17×10%,但我們姑且算個大概),所以這麼一來,一輛車從生產到消費者手中需要繳納的稅收就約佔汽車價格的33%左右。

除此之外,汽車廠家還要繳納教育附加的地方教育費,總費用合計在5%左右,這麼加起來,一輛車從生產出來直到消費者手中,其中所需要的稅費總的加起來就高達38%,稅費真的讓人防不勝防。

技術轉讓費

對於我們國內一些汽車合資品牌來說,每生產出一台合資車,都需要給外方支付10%的技術轉讓費,比如你買了一台20萬的轎車,其中技術轉讓費就高達2萬元,哦我的天,怪不得在同級轎車中,如果購買相同配置的話,合資車總要貴那麼幾萬塊,如此高的技術轉讓費,會導致國外一些價格較低的車型,很難引入國內,畢竟引入后,在價格戰上,始終斗不過寶駿310,或者長安奔奔的。

汽車廠家整車利潤

據網上資料显示,在國內,主流汽車廠家的整車利潤一般在10%左右,這個数字可能大家看了都不相信,因為在中國,很多人都認為汽車廠家是超賺錢的,當然,這10%其實不包括其中零散配件的價格利潤,現在是全球化時代,許多汽車廠家都會和許多知名的汽車配件,發動機和變速箱公司合作,其中這些核心部件在買賣當中究竟是有着多少利潤可言,關於這個問題,汽車廠家則以汽車技術不外露為理由,並沒有公開給我們廣大消費者。

4S店利潤

終於說到大家非常關心的問題了,據數據統計,在30萬元以下的車型,銷售一輛車的平均利潤為5%左右,賣一輛30萬的車4S店的利潤才1.5萬塊?怎麼可能!單純賣車賺的錢肯定不夠一整個4S店的開支(地租,人工費,設備耗損費,水電費),而且據了解,現在很多4S店由於資金不足,所以都把現車的合格證和主鑰匙抵押給銀行去貸款,等到這輛車賣出去了再去銀行贖回來,但也出現過賣車后無力贖回車輛的合格證的情況,導致車主無法按時上牌,所以這麼來說,許多4S店其實單車賣出來賺的利潤不多,主要還是靠拚命地賣車,在年底拿廠家返點。

那麼賣一輛車,4S店如何通過其他方式賺到你的錢呢?

保險費:對於一般人來說,在店裡買車,大多數人還是會在這裏把保險順便買了,方便以後出險的時候,這裏也有保險專員可以幫你跟進車輛的情況,更加方便,服務到位,大部分4S店都要求客戶買車的時候,保險也一定要在本店購買,更離譜的還要求必須買一定金額的保險,買個全險六七千,其中的利潤還是有一兩千的。

上牌費:其實上牌費也就是500塊錢而已,但是在一二線城市例如廣州,上個牌需要收取3000塊錢手續費,且一定要在本店執行,客戶不能夠提裸車,而如果需要上比較偏遠城市的外地牌,手續費去到6000元也有。

精品加裝費:對於一些熱銷車型來說,4S店肯定要大賺一筆,加價加價繼續加價,但是直接加價會影響市場,被稅局查到也有影響,所以都會利用一些其他方式來執行這種加價的“套路”,很簡單,通過一大堆高昂的精品加裝,價值就能夠上到一兩萬元,確實是炒高了價的“淘寶貨”啊。

售後維修服務:雖然說4S店通過正兒八經的方式確實掙不到什麼錢,但是售後服務這個大蛋糕,確實一直讓他們吃得挺爽的,一般新車都規定3個月或者5000公里後進行首保,但是4S店一般會在3000公里的時候,就提醒客戶該過來首保了,雖然說免費,但送的就是服務,且在質保期內如果在其他地方維修出現什麼其他問題,4S店也不承認,所以很多人在質保期內,還是會乖乖地去4S店裡做一下保養,收費可都是外面的好幾倍。

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

【其他文章推薦】

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

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

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

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

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

※回頭車貨運收費標準

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

真的假的?10萬級的國產SUV已經擁有媲美合資的能力了!

東風風神AX5新車指導價:8。97-12。87萬在外觀方面東風風神AX5擁有一個極高的原創外觀,採用了雙橫幅的鍍鉻前格柵,下部進氣口採用梯形設計,同時保險杠兩側還配備有類似進氣口造型的豎條狀LED日間行車燈,此外紅色卡鉗以及使用18寸風火輪式輪轂更能彰顯AX5的運動氣質,而AX5的離地間距達到190mm,處於中上游水準。

合資水平是目前眾多國產車廠商一直追求境界。為什麼總有的人會說國產車追不上合資車型?在看來最主要的原因是個人的感受方面。

國產品牌與合資到底差在哪兒?

品牌影響力上的差距!“國產”“合資”看起來就覺得合資更高端,在這裏也存在一種崇洋媚外的心理。現在的消費者買車更看重面子!國產品牌在眾多人心中依舊是“山寨”“廉價”的代名詞,如果讓親戚朋友看到你開一台國產車,總是會覺得低人一等。在很多人看來,為什麼要買國產車?並不是因為愛過情懷,而是錢不夠。

外觀內飾設計上的差距?認為設計是一種很主觀的東西,但凡有一些比較潮流的設計出現,喜歡的人會被吸引進來,不喜歡的人只會吐槽。所以在汽車設計方面越平庸的車型越受廣大消費者所喜愛,而且中國人更喜歡“大”這一個詞語,於是現在的新款車型在尺寸方面都越做越大。至於合資和國產是否存在差距?覺得現在國產車的設計已經相當不錯,除了那幾個不爭氣堅持模仿的廠商,大多都擁有了自己的一套家族式設計語言,而且原創度都相當高!

行駛質感的差距!有的人說國產車型開上幾年底盤感覺就像要散掉一般,跟合資車型完全無法比較。決定汽車行駛整體的質感與汽車廠家的調校功力成正比關係,就像法系車能把扭力梁調得比你的獨立懸挂更牛逼一樣,幾乎所有的廠家將自己那套底盤數據當成國家機密一樣。而調校就是國產品牌的硬傷,有能力的國產品牌可以選擇直接向合資廠家買比較過時的底盤數據、或者直接給錢外包給國外的調校團隊,投入資金是相龐大的。說句難聽點的,有部分的國產廠商的車型在看來壓根就是跳過了“調校”這個步驟。

國產品牌就這麼菜?

其實並不是,相反10萬左右的購車預算,選擇國產車型性價比更高!首先是配置更高、而且車子比合資車型更為大氣!有的人說國產車質量不行,國產車型的故障率是稍高,但這是對於故障率極低的品牌而言(就像豐田這些),不是所有的合資品牌故障率都很低的!10年前的國產車都在路上跑着,也不要說現在的新車型了。

外觀夠大氣、配置夠高、內飾檔次夠高、車型質量過關!是判斷一台國產車型能否擁有與合資車競爭的最主要因素!

東風風神AX5

新車指導價:8.97-12.87萬

在外觀方面東風風神AX5擁有一個極高的原創外觀,採用了雙橫幅的鍍鉻前格柵,下部進氣口採用梯形設計,同時保險杠兩側還配備有類似進氣口造型的豎條狀LED日間行車燈,此外紅色卡鉗以及使用18寸風火輪式輪轂更能彰顯AX5的運動氣質,而AX5的離地間距達到190mm,處於中上游水準。

中控台設計層次感挺高,採用了軟性材料覆蓋給到的質感也非常不錯,而且最讓喜歡的是它的實用性配置上,像副駕駛地下的鞋盒給愛穿高跟鞋的女生提供了放鞋的地方、配備了獨立的8英寸液晶屏和一鍵啟動等配置,內置的Windlink系統支持與安卓手機的連接。

AX5提供1.4T渦輪增壓發動機,與之匹配的是一台5擋手動/6擋擋雙離合,在質量方面值得肯定,另外AX5的底盤平台源自東風與pSA集團共同研發的DF2平台,在行駛質感方面真心不錯。

榮威RX5

新車指導價:9.98-18.68萬

榮威RX5在上市之初一直以“網紅”的形式登場,極高的顏值受到廣泛消費者的關注,作為榮威“律動設計”理念下的首款車型,“展翼格柵”的中控與矩陣式LED大燈相連,整體造型時尚大氣,原創度極高,逼格十足。

採用黃金比例進行打造設計的中控台也是滿滿的逼格,大面積使用軟材料包裹,摸到哪兒都是軟的,中控10.4英寸的大显示屏更是成為了中控台的點睛之筆,整體給人的質感相當高檔。另外與阿里共同打造出來的車載互聯繫統更是將其“網紅”的定位推上了頂峰。

在動力方面,1.5T的動力更適合家用、2.0T的動力能帶給你非常不俗的駕駛樂趣,在質量方面,榮威背後有着通用這個大集團的撐腰,無論在品控還是質量方面都值得肯定。

合資的选手實力也不俗!

雪鐵龍C3-XR

新車指導價:10.88-17.18萬

法系車一直不被人看好,車頭採用了更多平直的線條,彰顯飽滿風格。大燈簡單耐看,內部線條與前格柵相連接,整體感更強。而側面的線條緊湊動感,不規則的輪圈樣式也頗為個性。儘管它擁有着同級領先的底盤調校技術,但是配置搭配不合理是它主要的缺點,不過法系車也就有一個優點:那就是底盤紮實好開。

現代ix25

新車指導價:11.98-18.68萬

韓國車一直以高顏值作為賣點,所以無論旗下哪款車型,無疑不是顏值極高的选手,當然韓系車另外一個賣點就是配置比同級別的合資車型配置更高,而且韓系車在終端優惠方面很大,所以在新車落地價上會比較便宜。也可以這麼說,現代ix25在實用性與家用兩方面是做得相當不錯的。

國產車型配置高、價格更低,性價比十足。很多人對國產車存在偏見,但是這個困境將會隨着國產車型的日益發展得到改善,如果國產車的整體質量上來了,你還會覺得國產車比不上合資嗎?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※回頭車貨運收費標準

台中搬家公司費用怎麼算?

LeetCode 75,90%的人想不出最佳解的簡單題

本文始發於個人公眾號:TechFlow,原創不易,求個關注

今天是LeetCode專題的44篇文章,我們一起來看下LeetCode的75題,顏色排序 Sort Colors。

這題的官方難度是Medium,通過率是45%,點贊2955,反對209(國際版數據),從這份數據上我們大概能看得出來,這題的難度不大,並且點贊遠遠高於反對,說明題目的質量很不錯。事實上也的確如此,這題足夠簡單也足夠有趣,值得一做。

題意

給定一個n個元素的數組,數組當中的每一個元素表示一個顏色。一共有紅白藍三種顏色,分別用0,1和2來表示。要求將這些顏色按照大小進行排序,返回排序之後的結果。

要求不能調用排序庫sort來解決問題。

桶排序

看完題目應該感受到了,如果沒有不能使用sort的限制,這題毫無難度。即使加上了限制難度也不大,我們既然不能調用sort,難道還不能自己寫個sort嗎?Python寫個快排也才幾行而已。

自己寫sort當然是可以的,顯然這是下下策。因為元素只有3個值,互相之間的大小關係也就只有那麼幾種,排序完全沒有必要。比較容易想到,我們可以統計一下這三個數值出現的次數,幾個0幾個1幾個2,我們再把這些數拼在一起,還原之前的數據不就可以了嗎?

這樣的確可行,但實際上這也是一種排序方案,叫做基數排序,也稱為桶排序,還有些地方稱為小學生排序(大概是小學生都能懂的意思吧)。基數排序的思想非常簡單,我們創建一個數組,用它的每一位來表示某個元素是否在原數組當中出現過。出現過則+1,沒出現過則一直是0。我們標記完原數組之後,再遍歷一遍標記的數組,由於下標天然有序,所以我們就可以得到排序之後的結果了。

如果你還有些迷糊也沒有關係,我們把代碼寫出來就明白了,由於這題讓我們提供一個inplace的方法,所以我們在最後的時候需要對nums當中的元素重新賦值。

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """  Do not return anything, modify nums in-place instead.  """
        bucket = [0 for _ in range(3)]
        for i in nums:
            bucket[i] += 1

        ret = []
        for i in range(3):
            ret += [i] * bucket[i]

        nums[:] = ret[:]

和排序相比,我們只是遍歷了兩次數據,第一次是遍歷了原數組獲得了其中0,1和2的數量,第二次是將獲得的數據重新填充回原數組當中。相比於快排或者是其他一些排序算法的耗時,桶排序只遍歷了兩次數組,明顯要快得多。但遺憾的是這並不是最佳的方法,題目當中明確說了,還有隻需要遍歷一次原數組的方法。

two pointers

在我們介紹具體的算法之前,我們先來分析一下問題。既然顏色只有三種,那麼當我們排完序之後,整個數組會被分成三個部分,頭部是0,中間是1,尾部是2。

我們可以用一個區間來收縮1的範圍,假設我們當前區間的首尾元素分別是l和r。當我們讀到0的時候,我們就將它和l交換,然後將l向後移動一位。當我們讀到2的時候,則將它和r進行交換,將r向左移動一位。也就是說我們保證l和r之間的元素只有1。

我們之前曾經介紹過這種維護一個區間的做法,雖然都是維護了一個區間,但是操作上是有一些區別的。之前介紹的two pointers算法,也叫做尺取法,本質上是通過移動區間的右側邊界來容納新的元素,通過移動左邊界彈出數據的方式來維護區間內所有元素的合法性。而當前的做法中,一開始獲得的就是一個非法的區間,我們通過元素的遍歷以及區間的移動,最後讓它變得合法。兩者的思路上有一些細微的差別,但形式是一樣的,就是通過移動左右兩側的邊界來維護或者是達到合法。

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """  Do not return anything, modify nums in-place instead.  """
        l, r = 0, len(nums)-1
        i = 0
        while i < len(nums):
            if i > r:
                break
   # 如果遇到0,則和左邊交換
            if nums[i] == 0:
                nums[l], nums[i] = nums[i], nums[l]
                l += 1
            # 如果遇到2,則和右邊交換
            # 交換之後i需要-1,因為可能換來一個0
            elif nums[i] == 2:
                nums[r], nums[i] = nums[i], nums[r]
                r -= 1
                continue
            i += 1

這種方法我們雖然只遍歷了數組一次,但是由於交換的次數過多,整體運行的速度比上面的方法還要慢。所以遍歷兩次數組並不一定就比只遍歷一次要差,畢竟兩者都是的算法,相差的只是一個常數。遍歷的次數只是構成常數的部分之一。

除了這個方法之外,我們還有其他維護區間的方法。

維護區間

接下來要說的方法非常巧妙,我個人覺得甚至要比上面的方法還有巧妙。

我們來假想一下這麼一個場景,假設我們不是在原數組上操作數據,而是從其中讀出數據放到新的數組當中。我們先不去想應該怎麼擺放這個問題,我們就來假設我們原數組當中的數據已經放好了若干個,那麼這個時候的新數組會是什麼樣?顯然,應該是排好序的,前面若干個0,中間若干個1,最後若干個2。

那麼問題來了,假設這個時候我們讀到一個0,那麼應該怎麼放呢?為了簡化敘述我們把它畫成圖:

我們假設藍色部分是0,綠色部分是1,粉色部分是2。a是0最右側的下標,b是1部分最右側的下標,c是2部分最右側的下標。那麼這個時候,當我們需要放入一個0的時候,應該怎麼辦?

我們結合圖很容易想明白,我們需要把0放在a+1的位置,那麼我們需要把後面1和2的部分都往右側移動一格,讓出一格位置出來放0。我們移動數組顯然帶來的開銷會過於大,實際上沒有必要移動整個部分,只需要移動頭尾元素即可。比如1的部分左側被0佔掉了一格,那麼為了保持長度不變,右側也需要延伸一格。同理,2的部分右側也需要延伸一格。那麼整個操作用代碼來表示就是:nums[a+1] = 0,nums[b+1] = 1, nums[c+1] = 2。

假設我們讀入的數是1,那麼我們需要把b延長一個單位,但是這樣帶來的後果是2的部分被侵佔,所以需要將2也延長,補上被1侵佔的一個單位。如果讀到的是2,那麼直接延長2即可,因為2後面沒有其他顏色了。

假設我們有一個空白的數組,我們可以這麼操作,但其實我們沒有必要專門創建一個數組,我們完全可以用原數組自己填充自己。因為我們從原數組上讀取的數和擺放的數是一樣的,我們直接把数字擺放在原數組的頭部,佔用之前讀取的數即可。

光說可能還有些迷糊,看下代碼馬上就清楚了:

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """  Do not return anything, modify nums in-place instead.  """
        # 記錄0,1和2的末尾位置
        zero, one, two = -1, -1, -1
        n = len(nums)
        for i in range(n):
            # 如果擺放0
            # 那麼1和2都往後平移一位,讓一個位置出來擺放0
            if nums[i] == 0:
                nums[two+1] = 2
                nums[one+1] = 1
                nums[zero+1] = 0
                zero += 1
                one += 1
                two += 1
            elif nums[i] == 1:
                nums[two+1] = 2
                nums[one+1] = 1
                one += 1
                two += 1
            else:
                nums[two+1] = 2
                two += 1

總結

到這裏,這道題的解法基本上都講完了。

相信大家也都看出來了,從難度上來說這題真的不難,相信大家都能想出解法來,但是要想到最優解還是有些困難的。一方面需要我們對題目有非常深入的理解,一方面也需要大量的思考。這類題目沒有固定的解法,需要我們根據題目的要求以及實際情況自行設計解法,這也是最考驗思維能力以及算法設計能力的問題,比考察某個算法會不會的問題要有意思得多。

希望大家都能從這題當中獲得樂趣,如果喜歡本文,可以的話,請點個關注,給我一點鼓勵,也方便獲取更多文章。

本文使用 mdnice 排版

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

【其他文章推薦】

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

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

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

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

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

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

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

詳解 Seata Golang 客戶端 AT 模式及其使用

源碼seata-golang

概述

  我們知道 Seata Java Client 的 AT 模式,通過代理數據源,實現了對業務代碼無侵入的分佈式事務協調機制,將與 Transaction Coordinator (TC) 交互的邏輯、Commit 的邏輯、Rollback 的邏輯,隱藏在切面和代理數據源相應的代碼中,使開發者無感知。那如果這個方法,要用 Golang 來實現一遍,應該如何操作呢?關於這個問題,我想了很久,最初的設想是,對 database/sql 的 mysql driver 進行增強,在對包 github.com/go-sql-driver/mysql 研究了一段時間后,還是沒有頭緒,不知如何下手,最後轉而增強 database/sql 包。由於 AT 模式必須保證本地事務的正確處理,在具體業務開發時,首先要通過 db.Begin() 獲得一個 Tx 對象,然後再 tx.Exec() 執行數據庫操作,最後 tx.Commit() 提交或 tx.Rollback() 回滾。這種處理方式算是一個 Golang 數據庫事務處理的基本操作。 所以對 database/sql 的增強,我們重點關注這幾個方法 db.Begin()tx.Exec()tx.Commit()tx.Rollback

事務提交、回滾

  通過 Seata Java Client 的相關代碼,我們知道,在本地事務提交的時候,主要是將分支事務註冊到 TC 上,並將數據庫操作產生的 undoLog 一起寫入到 undoLog 表;本地事務回滾的時候,需要將分支事務(即本地事務)的執行狀態報告給 TC,使 TC 好知道是否通知參与全局事務的其他分支回滾。

func (tx *Tx) Commit() error {
        //註冊分支事務
	branchId,err := tx.register()
	if err != nil {
		return errors.WithStack(err)
	}
	tx.tx.Context.BranchId = branchId

	if tx.tx.Context.HasUndoLog() {
                //將 undoLog 寫入 undoLog 表
		err = manager.GetUndoLogManager().FlushUndoLogs(tx.tx)
		if err != nil {
			err1 := tx.report(false)
			if err1 != nil {
				return errors.WithStack(err1)
			}
			return errors.WithStack(err)
		}
		err = tx.tx.Commit()
		if err != nil {
			err1 := tx.report(false)
			if err1 != nil {
				return errors.WithStack(err1)
			}
			return errors.WithStack(err)
		}
	} else {
		return tx.tx.Commit()
	}
	if tx.reportSuccessEnable {
		tx.report(true)
	}
	tx.tx.Context.Reset()
	return nil
}

  db.Begin() 會產生一個 Tx 對象,tx.Exec() 會產生 undoLog,tx.Commit() 將 undoLog 刷到數據庫中。那麼 undoLog 保存到哪裡呢?答案是 TxContext 中。

type TxContext struct {
	*context.RootContext
	Xid string
	BranchId int64
	IsGlobalLockRequire bool

	LockKeysBuffer *model.Set
	SqlUndoItemsBuffer []*undo.SqlUndoLog
}

  Commit() 方法中的 tx.tx.Context,第一個 tx 是封裝的 Tx 對象,第二個 tx 是 database/sql 的 Tx,tx.tx.Context 則是 TxContext。UndoLogManager 則是操作 undoLog 的核心對象,處理 undoLog 的插入、刪除,並查詢出 undoLog 用於回滾。

func (tx *Tx) Rollback() error {
	err := tx.tx.Rollback()
	if tx.tx.Context.InGlobalTransaction() && tx.tx.Context.IsBranchRegistered() {
                // 報告 TC 分支事務執行失敗
		tx.report(false)
	}
	tx.tx.Context.Reset()
	return err
}

  通過上面的代碼呢,我們知道增強型 Tx 對象需要向 TC 註冊分支事務,並報告分支事務的執行狀態,相應代碼如下:

func (tx *Tx) register() (int64,error) {
	return dataSourceManager.BranchRegister(meta.BranchTypeAT,tx.tx.ResourceId,"",tx.tx.Context.Xid,
		nil,tx.tx.Context.BuildLockKeys())
}

func (tx *Tx) report(commitDone bool) error {
	retry := tx.reportRetryCount
	for retry > 0 {
		var err error
		if commitDone {
			err = dataSourceManager.BranchReport(meta.BranchTypeAT, tx.tx.Context.Xid, tx.tx.Context.BranchId,
				meta.BranchStatusPhaseoneDone,nil)
		} else {
			err = dataSourceManager.BranchReport(meta.BranchTypeAT, tx.tx.Context.Xid, tx.tx.Context.BranchId,
				meta.BranchStatusPhaseoneFailed,nil)
		}
		if err != nil {
			logging.Logger.Errorf("Failed to report [%d/%s] commit done [%t] Retry Countdown: %d",
				tx.tx.Context.BranchId,tx.tx.Context.Xid,commitDone,retry)
			retry = retry -1
			if retry == 0 {
				return errors.WithMessagef(err,"Failed to report branch status %t",commitDone)
			}
		}
	}
	return nil
}

  和 TC 進行通信的主要邏輯還是在 DataSourceManager 裏面。AT 模式涉及的兩個關鍵對象 DataSourceManager、UndoLogManager 就浮出水面。一個用於遠程 TC 交互,一個用於本地數據庫處理。

事務執行

func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error) {
	var parser = p.New()
        // 解析業務 sql
	act,_ := parser.ParseOneStmt(query,"","")
	deleteStmt,isDelete := act.(*ast.DeleteStmt)
	if isDelete {
		executor := &DeleteExecutor{
			tx:            tx.tx,
			sqlRecognizer: mysql.NewMysqlDeleteRecognizer(query,deleteStmt),
			values:        args,
		}
		return executor.Execute()
	}

	insertStmt,isInsert := act.(*ast.InsertStmt)
	if isInsert {
		executor := &InsertExecutor{
			tx:            tx.tx,
			sqlRecognizer: mysql.NewMysqlInsertRecognizer(query,insertStmt),
			values:        args,
		}
		return executor.Execute()
	}

	updateStmt,isUpdate := act.(*ast.UpdateStmt)
	if isUpdate {
		executor := &UpdateExecutor{
			tx:            tx.tx,
			sqlRecognizer: mysql.NewMysqlUpdateRecognizer(query,updateStmt),
			values:        args,
		}
		return executor.Execute()
	}

	return tx.tx.Tx.Exec(query,args)
}

  執行業務 sql,並生成 undoLog 的關鍵,在於識別業務 sql 執行了什麼操作:插入?刪除?修改?這裏使用 tidb 的 sql parser 去解析業務 sql,再使用相應的執行器去執行業務 sql,生成 undoLog 保存在 Tx_Context 中。

事務開啟

  db.Begin() 返回增強型的 Tx 對象。

func (db *DB) Begin(ctx *context.RootContext) (*Tx,error) {
	tx,err := db.DB.Begin()
	if err != nil {
		return nil,err
	}
	proxyTx := &tx2.ProxyTx{
		Tx:         tx,
		DSN:        db.conf.DSN,
		ResourceId: db.GetResourceId(),
		Context:    tx2.NewTxContext(ctx),
	}
	return &Tx{
		tx: proxyTx,
		reportRetryCount: db.conf.ReportRetryCount,
		reportSuccessEnable: db.conf.ReportSuccessEnable,
	},nil
}

seata-golang at 模式的使用

sample 代碼

  • 首先執行 scripts 腳本,初始化數據庫
    如果之前沒有初始化過 seata 數據庫,先執行 seata-golang/scripts/server/db/mysql.sql 腳本
  • 修改 dsn 數據庫配置,修改下列文件:
seata-golang/tc/app/profiles/dev/config.yml
seata-golang/samples/at/product_svc/conf/client.yml
seata-golang/samples/at/product_svc/conf/client.yml
  • 將下列文件中的 configPath 修改為 client.yml 配置文件的路徑
seata-golang/samples/at/product_svc/main.go
seata-golang/samples/at/order_svc/main.go
seata-golang/samples/at/aggregation_svc/main.go
  • 依次運行 tc、order_svc、product_svc、aggragation_svc,訪問下列地址開始測試:
http://localhost:8003/createSoCommit
http://localhost:8003/createSoRollback

TC 啟動參考參与 Seata 社區到 go 與 Seata 的邂逅

seata-golang 後續安排

  接下來不打算再增加新的 feature。Java 版 Seata 畢竟發展了一年多時間,並且有很多社區成員一起維護,Go 版本目前主要是我在開發,時間不到2個月,現有的代碼,僅是完成了框架,還需要大量優化,改bug,後續的工作重心在於使 seata-golang 穩定運行,生產可用,希望對分佈式事務感興趣且對 Go 感興趣的同學一起加入進來,一起做些事情。進入微信群,請加我微信:scottlewis,備註進群。

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

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

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

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

Kubernetes日誌的6個最佳實踐

本文轉自Rancher Labs

Kubernetes可以幫助管理部署在Pod中的上百個容器的生命周期。它是高度分佈式的並且各個部分是動態的。一個已經實現的Kubernetes環境通常涉及帶有集群和節點的幾個系統,這些系統託管着幾百個容器,而這些容器不斷地基於工作負載啟動、毀滅。

當在Kubernetes中處理大量的容器化應用和工作負載時,主動進行監控和調試錯誤十分重要。在容器、節點或集群級別,這些錯誤都能在容器中看到。Kubernetes的日誌機制是一個十分重要的組件,可以用來管理和監控服務以及基礎設施。在Kubernetes中,日誌可以讓你跟蹤錯誤甚至可以調整託管應用程序的容器的性能。

配置stdout(標準輸出)和stderr(標準錯誤)數據流

圖片來源:kubernetes.io

第一步是理解日誌是如何生成的。通過Kubernetes,日誌會被發送到兩個數據流——stdout和stderr。這些數據流將寫入JSON文件,並且此過程由Kubernetes內部處理。你可以配置將哪個日誌發送到哪個數據流中。而一個最佳實踐的建議是將所有應用程序日誌都發送到stdout並且所有錯誤日誌都發送到stderr。

決定是否使用Sidecar模型

Kubernetes建議使用sidecar容器來收集日誌。在這一方法中,每個應用程序容器將有一個鄰近的“streaming容器”,該容器將會將所有日誌流傳輸到stdout和stderr。Sidecar模型可以幫助避免在節點級別公開日誌,並且它可以讓你控制容器級別的日誌。

然而,這一模型的問題是它能夠適用於小容量的日誌記錄,如果面對大規模的日誌記錄,可能會造成大量資源被佔用。因此,你需要為每個正在運行的應用程序容器單獨運行一個日誌容器。在Kubernetes文檔中,將sidecar模型形容為“幾乎沒有很大的開銷”。需要由你決定是否嘗試這一模型並在選擇它之前查看它所消耗的資源類型。

替代方法是使用日誌代理,該代理在節點級別收集日誌。這樣可以減少開銷,並確保安全地處理日誌。Fluentd已成為大規模聚合Kubernetes日誌的最佳選擇。它充當Kubernetes與你要使用Kubernetes日誌的任意數量的端點之間的橋樑。你也可以選擇像Rancher這樣的Kubernetes管理平台,在應用商店已經集成了Fluentd,無需從頭開始安裝配置。

確定Fluentd可以更好地匯總和路由日誌數據后,下一步就是確定如何存儲和分析日誌數據。

選擇日誌分析工具:EFK或專用日誌記錄

傳統上,對於以本地服務器為中心的系統,應用程序日誌存儲在系統中的日誌文件中。這些文件可以在定義的位置看到,也可以移動到中央服務器。但是對於Kubernetes,所有日誌都發送到磁盤上/var/log的JSON文件中。這種類型的日誌聚合併不安全,因為節點中的Pod可以是臨時的也可以是短暫的。刪除Pod時,日誌文件將丟失。如果你需要嘗試對部分日誌數據丟失進行故障排除時,這可能很難。

Kubernetes官方推薦使用兩個選項:將所有日誌發送到Elasticsearch,或使用你選擇的第三方日誌記錄工具。同樣,這裏存在一個潛在的選擇。採用Elasticsearch路線意味着你需要購買一個完整的堆棧,即EFK堆棧,包括Elasticsearch、Fluentd和Kibana。每個工具都有其自己的作用。如上所述,Fluentd可以聚合和路由日誌。Elasticsearch是分析原始日誌數據並提供可讀輸出的強大平台。Kibana是一種開源數據可視化工具,可以從你的日誌數據創建漂亮的定製dashboard。這是一個完全開源的堆棧,是使用Kubernetes進行日誌記錄的強大解決方案。

儘管如此,有些事情仍然需要牢記。Elasticsearch除了由名為Elastic的組織構建和維護,還有龐大的開源社區開發人員為其做貢獻。儘管經過大量的實踐檢驗,它可以快速、強大地處理大規模數據查詢,但在大規模操作時可能會出現一些問題。如果採用的是自我管理(Self-managed)的Elasticsearch,那麼需要有人了解如何構建大規模平台。

替代方案是使用基於雲的日誌分析工具來存儲和分析Kubernetes日誌。諸如Sumo Logic和Splunk等工具都是很好的例子。其中一些工具利用Fluentd來將日誌路由到他們平台,而另一些可能有它們自己的自定義日誌代理,該代理位於Kubernetes中的節點級別。這些工具的設置十分簡單,並且使用這些工具可以花費最少的時間從零搭建一個可以查看日誌的dashboard。

使用RBAC控制對日誌的訪問

在Kubernetes中身份驗證機制使用的是基於角色訪問控制(RBAC)以驗證一個用戶的訪問和系統權限。根據用戶是否具有特權(authorization.k8s.io/decision )並向用戶授予原因(authorization.k8s.io/reason ),對在操作期間生成的審核日誌進行註釋。默認情況下,審核日誌未激活。建議激活它以跟蹤身份驗證問題,並可以使用kubectl進行設置。

保持日誌格式一致

Kubernetes日誌由Kubernetes架構中不同的部分生成。這些聚合的日誌應該格式一致,以便諸如Fluentd或FluentBit的日誌聚合工具更易於處理它們。例如,當配置stdout和stderr或使用Fluentd分配標籤和元數據時,需要牢記這一點。這種結構化日誌提供給Elasticsearch之後,可以減少日誌分析期間的延遲。

在日誌收集守護進程上設置資源限制

由於生成了大量日誌,因此很難在集群級別上管理日誌。DaemonSet在Kubernetes中的使用方式與Linux類似。它在後台運行以執行特定任務。Fluentd和filebeat是Kubernetes支持的用於日誌收集的兩個守護程序。我們必須為每個守護程序設置資源限制,以便根據可用的系統資源來優化日誌文件的收集。

結 論

Kubernetes包含多個層和組件,因此對其進行良好地監控和跟蹤能夠讓我們在面對故障時從容不迫。Kubernetes鼓勵使用無縫集成的外部“Kubernetes原生”工具進行日誌記錄,從而使管理員更輕鬆地獲取日誌。文章中提到的實踐對於擁有一個健壯的日誌記錄體繫結構很重要,該體繫結構在任何情況下都可以正常工作。它們以優化的方式消耗計算資源,並保持Kubernetes環境的安全性和高性能。

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

【其他文章推薦】

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

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

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

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

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

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

※回頭車貨運收費標準

Action的三種實現方式,struts.xml配置的詳細解釋及其簡單執行過程(二)

勿以惡小而為之,勿以善小而不為————————–劉備

勸諸君,多行善事積福報,莫作惡

上一章簡單介紹了Struts2的’兩個蝴蝶飛,你好’ (一),如果沒有看過,請觀看上一章

一 Action的三種實現方式

上一章開發的HelloAction和HelloAction2,並沒有繼承任何類或者實現任何接口,但是必須有一個execute() 方法,方法返回值是String類型。

這樣的代碼不容易理解,更並不能使人看得出這個類是干什麼的,甚至不能區分這個控制器類與普通的Java類有什麼區別,通常開發中不這樣做。

我們開發者在開發Struts2框架的時候,希望自己寫的這個Action類能夠具有易理解性,且已經支持某些功能,如參數接收,文件上傳等。

一.一 第一種實現方式(普通Java類,裏面只包含execute()方法)

package com.yjl.web.action;
import org.apache.log4j.Logger;
/**
* @author 兩個蝴蝶飛
* @version 創建時間:2018年8月23日 上午9:41:32
* @description 第一種實現方式,普通java類,
* 有一個execute()方法,也可以多寫幾個方法,用action中的標籤method來控制,可以正常訪問。
*/
public class Hello1Action {
	private static Logger logger=Logger.getLogger(Hello1Action.class);
	public String execute() {
		logger.info("兩個蝴蝶飛,web層你好");
		return "success";
	}
}

不具有開發時要求的規範性,且不支持某些struts2自身提供的功能。

方法名稱只有一個 execute()

一.二 第二種實現方式(實現Action接口)

package com.yjl.web.action;
import com.opensymphony.xwork2.Action;
/**
* @author 兩個蝴蝶飛
* @version 創建時間:2018年8月23日 上午10:54:03
* @description 第二種實現方式,實現Action接口,重寫裏面的execute()方法
* 有一個execute()方法和五個String類型的常量
*/
public class Hello2Action implements Action{
	@Override
	public String execute() throws Exception {
		return Action.SUCCESS;
		//return Action.ERROR;
		//return Action.LOGIN;
		//return Action.NONE;
		//return Action.INPUT;
	}
}

注意,Action接口是xwork2包下的接口。

實現了Action接口,使開發者能夠看出來這是一個Action,具有了一定程度上的開發規範,

但是實現了Action接口,所以必須要重寫execute()方法。

一般自己寫Action,構思好之後上來就直接add(), edit(), delete(). select() 這些業務方法,

每次都要重寫execute()方法,不太方便。 而且這種方式不具有struts2中某些功能,如驗證框架和國際化。

Action中接口中有五個常用的結果字符串(好多方法都返回success,error,login,input,none,故將其封裝了一下) .

這些字符串雖然是大寫,然而真實的值是全部小寫.

package com.opensymphony.xwork2;

public abstract interface Action
{
  public static final String SUCCESS = "success";
  public static final String NONE = "none";
  public static final String ERROR = "error";
  public static final String INPUT = "input";
  public static final String LOGIN = "login";
  
  public abstract String execute()
    throws Exception;
}

一.三 繼承ActionSupport類(官方推薦)

	package com.yjl.web.action;
	import com.opensymphony.xwork2.ActionSupport;
	/**
	* @author 兩個蝴蝶飛
	* @version 創建時間:2018年8月23日 上午11:04:20
	* @description 第三種方式,繼承ActionSupport類。
	* ActionSupport類實現了Action接口,也有Action中的五個常量.
	*/
	public class Hello3Action extends ActionSupport{
		public String list() {
			return "list";
		}
	}

繼承了ActionSupport類,不需要重新寫execute()方法,直接寫業務方法即可。

ActionSupport類,已經實現了 Action接口。 其具備Action中的五個常量,並且該類還實現了其他接口,

源代碼:

	public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable{
    ...
	public String execute() throws Exception
  	{
		//默認返回的是 success 字符串 
  		 return "success";
 	}
 	...
}

如驗證框架(Validateable,ValidationAware),國際化(LocaleProvider)。

以後開發中,使用 繼承 ActionSupport 類的形式。

二 配置文件 struts.xml中節點的詳細解釋

在src下有一個struts.xml的配置文件,它配置了開發者自己編寫實現的Action,是struts2框架的核心,不能改變文件名稱。(注意,是struts.xml,並不是struts2.xml,並沒有那個2)。

在struts.xml中,最上面是一個約束, 是一個根節點。

二.一 修改常量節點

在struts-core.jar核心包下,有一個包org.apache.struts2包下,有一個default.properties屬性文件,裏面記錄了很多常用的常量,

其中常見的有:

struts.i18n.encoding=UTF-8 
struts.multipart.maxSize=2097152
struts.action.extension=action,,
struts.enable.DynamicMethodInvocation = false
struts.devMode = false
struts.ui.theme=xhtml
struts.ognl.allowStaticMethodAccess=false

建議修改后的值為:

###國際化操作,編碼格式為UTF-8
struts.i18n.encoding=UTF-8
###上傳文件時最大的上傳大小,默認為2M. 根據項目情況具體填寫值,建議後面加兩個00
struts.multipart.maxSize=209715200
###struts的訪問後綴名, struts1框架默認的是 .do 
struts.action.extension=action,,
###struts是否可以訪問靜態方法
struts.enable.DynamicMethodInvocation =true
###struts是否是開發者模式
struts.devMode =true
###struts中ui標籤的主題,建議為simple
struts.ui.theme=simple
###ognl中是否可以訪問靜態方法,為true
struts.ognl.allowStaticMethodAccess=true

可以在struts.xml中進行相應的修改,如

 <!--修改國際化編碼 -->
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<!--修改是否為開發者模式 -->
<constant name="struts.devMode" value="true"></constant>

按照name,value值的形式進行填寫。

也可以在src下新建一個struts.properties,然後將這些值放置進去,struts也會自動struts.propeties中的常量值的。

也可以在web.xml中,在 中,以 局部參數的形式傳遞進去。

建議使用第一種方式,在struts.xml中用 ,畢竟這個文件常常打開,出錯了也容易發現。

二.二 分模塊開發

在實際的項目中,有很多的模塊,如果所有的配置都放在一個struts.xml,那麼一旦這個struts.xml被其他人誤操作導致了錯誤,那麼其他人的項目將無法運行的,當配置內容過多時,struts.xml的內容太長,不便於維護,所以最好是分模塊開發,一個模塊用一個配置文件,然後再利用 進行導入, 類似 於jsp中的 靜態包含一樣。

所以建議每一個模塊都寫一個模塊.xml,然後在struts.xml中引入即可。如有三個模塊 User模塊和Class,Course,那麼可以將User的配置放置在user.xml中,Class配置放置在class.xml中,course模塊放置在course.xml,在struts.xml中只需要

	<include file="user.xml"></include>
	<include file="class.xml"></include>
	<include file="course.xml"></include>

靜態包含即可。 注意,file的文件路徑引用是否輸入正確。

正確的位置引用,點擊ctrl+模塊.xml時,可以跳轉到相應的.xml文件中。如果沒有跳轉和反應,那說明位置引用錯誤,需要重新檢查一下。

二.三 包節點

在struts.xml配置文件中,最重要的節點就是package節點。 package,分包。 可以將action進行分包處理。

這樣每一個action或者每一組action用package進行隔開,便於維護,類似於java中package的概念。

二.三.一 <package> 節點的使用

<package name="hello" extends="struts-default" namespace="/">
        <!--具體的Action-->
</package>

package中name節點是package的名字,是獨一無二的,不能夠重複。 最好與模塊名相同或者起一個有意義的名稱。

extends節點表示繼承,即package之間可以相互的繼承,來避免重複化功能的編寫。 默認為struts-default。

struts-default中struts已經定義了很多功能,開發者自己寫的包只需要extends 這個包名struts-default,

就擁有了struts已經定義好的功能。 如攔截器功能,文件上傳功能。

用戶也可以自己繼承自己所寫的包 。如父包名為

那麼子包只需要 , 這樣child包不但擁有struts-default的功能,也擁有parent包中的特殊功能,這也是Java的多重繼承的體現。 所以package的name 要符合標識符的規範,具有可讀性。

namespace節點表示命名空間,以/開頭,默認是”/” 。是為了在訪問路徑和訪問請求url方面體現package的分包作用. package中的name是在配置文件中體現分包,namespace是在url中體現分包。 建議開發中,namespace的路徑名與name保持一致。 package中的namespace的值與子節點action中name的值,共同構成了完整的訪問請求路徑。

二.三.二 <package></package> 子節點<action></action>節點的使用

在Hello3Action中定義兩個方法,一個是list()查詢,一個是add()添加的方法。

package com.yjl.web.action;
import org.apache.log4j.Logger;
import com.opensymphony.xwork2.ActionSupport;
/**
* @author 兩個蝴蝶飛
* @version 創建時間:2018年8月23日 上午11:04:20
* @description 測試action標籤中method的方法訪問
*/
public class Hello3Action extends ActionSupport{
	private static final long serialVersionUID = 8737138848863458260L;
	Logger logger=Logger.getLogger(Hello3Action.class);
	public String list() {
		logger.info("執行list方法");
		return "list";
	}
	public String add() {
		logger.info("執行add方法");
		return "add";
	}
}

標籤,有三個基本的屬性,

	<action name="list" class="com.yjl.web.action.Hello3Action"
        method="list">

</action>

其中name為action的名字,表示區別一個package包下的不同的action。 其中這個name的值,不應該隨便取,應該是要訪問的方法名。

在瀏覽器客戶端請求的url為 /項目名/package的namespace名稱/action的name名稱.action;

class為要訪問的那個Action的全限定名稱,是class,用.(點)進行分隔。

其中,class 可以省略, 省略默認為 ActionSupport 類, 全限定名稱為: com.opensymphony.xwork2.ActionSupport
method為要訪問的那個方法名稱,類 extends ActionSupport 后,有很多很多的方法,如list(), add(), delete()等,那麼怎麼知道具體要訪問哪個方法呢? 用method這個屬性. method=”要方法的方法名” ,是方法名。

action還有一個節點是converter,表示所用的是哪一個類型轉換器。(後面會有相應的解釋)

很清楚, action 中的 class指定了訪問的是哪一個action, method 指定了訪問的是哪一個具體的方法, 利用了反射技術實現。

在本實例了有兩個方法,所以要進行寫兩個Action, 一個Action類中會有多個方法,難道要一個個配置多個Action嗎?

Struts2提供了一些簡單的方式

二.三.三 配置Action的三種形式

二.三.三.一 通過配置method的屬性完成

簡單舉例如下:

	<action name="list" class="com.yjl.web.action.Hello3Action"
		method="list">
			
	</action>
  <action name="add" class="com.yjl.web.action.Hello3Action"
		method="add">
            
    </action>

缺點: 有幾個方法,就要配置有幾個action,當方法過多時,不易維護。

二.三.三.二 通過配置 通配符完成。

簡單舉例如下:

	<action name="Hello3_*" class="com.yjl.web.action.Hello3Action"
		method="{1}">
			
		</action>

name的值為: 類簡寫名(去掉Action后)_* method中的值取第一個{1},從1開始,不是從0開始。

這樣訪問Hello3Action中的list方法,訪問路徑就是 Hello3_list

訪問Hello3Action中的add方法,訪問路徑就是Hello3_add

簡化了action的相關配置。

也有的人配置的更狠, 會配置成_, 即:

	<action name="*_*" class="com.yjl.web.action.{1}Action"
		method="{2}">
			
		</action>

User類中的list就是User_list, User類中的add就是User_add,

Class類中的list就是Class_list,Class類中的add就是Class_add

這樣雖說簡化了開發,但卻不利用 result 節點的維護 ,不建議這樣配置。

好多類的好多方法返回值,都寫在這一個action 下面,會亂。

二.三.三.三 動態方法訪問

不是用 * 通配符,而是用! 號。 即:

想訪問UserAction中list方法() 前端寫url為 userAction!list.action
想訪問UserAction中add方法() 前端寫url為 userAction!add.action
想訪問ClassAction中list方法() 前端寫url為 classAction!list.action
想訪問ClassAction中add方法() 前端寫url為 classAction!add.action

這樣訪問也特別的方便。

這樣的話, action中只需要配置name和class即可。 method已經由外部指定了,不需要寫method的值了。

需要先添加變量 struts.enable.DynamicMethodInvocation, 使其變成 true,開啟。

	<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>

如果是UserAction的話,配置應該是:

<action name="userAction" class="com.yjl.web.action.UserAction" >
			
</action>

ClassAction的話,配置應該是

<action name="classAction" class="com.yjl.web.action.ClassAction" >
			
</action>

二.三.四 action子節點result的配置

result表示結果,是對方法的返回值進行相應的分析。有兩個屬性,name和type

	<result name="success" type="dispatcher">/index.jsp</result>

其中name的值要與方法的返回值保持一致。

如 list方法返回值是return SUCCESS,那麼這個list方法的返回值對應的result的值就是 ,

如果返回是”hello”, 那麼這個name的返回值就是

如果在action中配置通配符, name=Hello3_*形式,method=”{1}”, 那麼為了簡化result的配置,可以將result配置成 name={1},

相應的.jsp,可以變成 /{1}.jsp。

但這樣必須保證Action中方法的名稱與返回值的名稱相同,並且與跳轉到的jsp的名稱也要相同, 這樣不太好。

result中type五種常見的形式, dispatcher(轉發到jsp),redirect(重定向到jsp), chain(轉發到另外一個方法),redirectAction(重定向到另外一個方法),stream(上傳和下載流)

其中dispathcer和redirect是跳轉到jsp,如果想要傳遞數據,用dispather,

如果不想傳遞數據,用redirect (dispathcer是轉發,redirect是重定向)

chain,redirectAction是跳轉到action的操作,一般用於這同一個類中兩個方法之間的跳轉,

如add()添加成功之後,需要跳轉到list()方法進行显示結果,這時就可以配置成:

	<result name="add" type="redirectAction">Hello3_list</result>

地址url也會相應的改變,如果是chain的話,地址欄是不會改變的。 chain是轉發到action, redirectAction是重定向到action.

也可以在不同包之間的action進行的跳轉 。

如 add 方法 想到跳轉到 /class 命名空間下的 Hello2Action 的 list 方法。

<result name="add" type="redirectAction">
	<!-- 要跳轉到哪一個命名空間,即哪一個包 -->
	<param name="namespace">/class</param>
	<!-- 要跳轉到哪一個Action 不加後綴 -->
	<param name="actionName">Hello2Action</param>
	<!-- 跳轉到哪一個方法 -->
	<param name="method">list</param>
	<!-- 可能要傳遞的參數. 用ognl表達式,根據情況添加 -->
	<param name="id">${id}</param>
</result>

通過 param 標籤來配置帶參還是不帶參。

二.四 全局結果頁面與局部結果頁面。

這個全局是相對於package來說的,是package中的全局,並不是所有的struts.xml中的全局,所以全局結果的節點位置應該放在package節點裏面,與action節點平行。 用 節點。

常用的全局結果頁面有兩種:

error錯誤頁面,頁面出錯了都显示這個頁面,

login 登錄頁面, 如果沒有登錄,輸入任何url都會跳轉到login頁面(認證時用)

noprivilege 沒有權限頁面,如果用戶沒有權限訪問了某一個頁面,會給出相應的提示(授權時用)

<global-results>
			<result name="error">/error/error.jsp</result>
			<result name="login">/login.jsp</result>
            <result name="noprivilege">/noprivilege.jsp</result>
</global-results>

當全局結果頁面與局部結果頁面發生衝突時,以局部結果頁面為準。

全局配置時:

<global-results>
			<result name="success">/successGlobal.jsp</result>
</global-results>

在該包下的某個action 的方法result 也返回了 success

	<result name='success'>success.jsp</result>

那麼,當邏輯視圖為 success時,最終將返回 success.jsp

二.五 配置跳轉頁面

在開發中,常常有這麼一種情況,

請求login.jsp 時,為 /login, 那麼就跳轉到 login.jsp 頁面,

語法為 register.jsp 時,為 /register, 那麼就跳轉到 register 頁面。

這個時候,配置 為:

	<action name="*">
			<result>/WEB-INF/content/{1}.jsp</result>
	</action>

將頁面放置在 content 文件夾下面,避免用戶直接訪問 jsp頁面。

注意,要將此 action 放置在最後, 當所有上面的action都不匹配時,才匹配這一個action.

三 Struts2的執行流程

當用戶在客戶端發送一個請求后,如常用的標準的http://localhost:8080/Struts_Hello/user/User_add.action時,

會經過前端控制器(StrutsPrepareAndExecuteFilter) 過濾器,執行一連串的過濾器鏈,然後根據user 找到了對應的package的namespape,進入到具體的package包下。 利用通配符的方式進行訪問,User_add會進行匹配相應的action,根據class和method找到是哪一個類的哪一個方法,在實例化類Action之前,會先執行攔截器。通過反射實例化類,運行方法, 方法運行成功之後,有一個返回值,這個返回值會與剛才action下的 中的name進行相應的匹配,匹配到哪一個,就執行哪一個result。 如果是diapatcher或者redirect,就显示到相應的.jsp頁面(帶有數據), 如果是chain或者redirectAction,那麼就去執行那一個方法,之後進行返回具體的視圖。

執行過程圖如下:

謝謝您的觀看!!!

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

【其他文章推薦】

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

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

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

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

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

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

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