標籤: 租車

  • STM32串口打印的那些知識

    STM32串口打印的那些知識

    常規打印方法

    在STM32的應用中,我們常常對printf進行重定向的方式來把打印信息printf到我們的串口助手。在MDK環境中,我們常常使用MicroLIB+fputc的方式實現串口打印功能,即:

    要實現fputc函數的原因是:printf函數依賴於fputc函數,重新實現fputc內部從串口發送數據即可間接地實現printf打印輸出數據到串口。

    不知道大家有沒有看過正點原子裸機串口相關的例程,他們的串口例程里不使用MicroLIB,而是使用標準庫+fputc的方式。相關代碼如:

    #if 1
    #pragma import(__use_no_semihosting)
    //標準庫需要的支持函數
    struct __FILE
    {
        int handle;
    };
    
    FILE __stdout;
    /**
     * @brief	定義_sys_exit()以避免使用半主機模式
     * @param	void
     * @return  void
     */
    void _sys_exit(int x)
    {
        x = x;
    }
    
    int fputc(int ch, FILE *f)
    {
        while((USART1->ISR & 0X40) == 0); //循環發送,直到發送完畢
    
        USART1->TDR = (u8) ch;
        return ch;
    }
    #endif
    

    關於這兩種方法的一些說明可以查看Mculover666兄的重定向printf函數到串口輸出的多種方法這篇文章。這篇文章中不僅包含上面的兩種方法,而且也包含着在GCC中使用標準庫重定向printf的方法。

    自己實現一個打印函數

    以上的幾種方法基本上是改造C庫的printf函數來實現串口打印的功能。其實我們也可以自己實現一個串口打印的功能。

    printf本身就是一個變參函數,其原型為:

    int printf (const char *__format, ...);
    

    所以,我們要重新封裝的一個串口打印函數自然也應該是一個變參函數。具體實現如下:

    1、基於STM32的HAL庫

    #define TX_BUF_LEN  256     /* 發送緩衝區容量,根據需要進行調整 */
    uint8_t TxBuf[TX_BUF_LEN];  /* 發送緩衝區                       */
    void MyPrintf(const char *__format, ...)
    {
      va_list ap;
      va_start(ap, __format);
      
      /* 清空發送緩衝區 */
      memset(TxBuf, 0x0, TX_BUF_LEN);
      
      /* 填充發送緩衝區 */
      vsnprintf((char*)TxBuf, TX_BUF_LEN, (const char *)__format, ap);
      va_end(ap);
      int len = strlen((const char*)TxBuf);
      
      /* 往串口發送數據 */
      HAL_UART_Transmit(&huart1, (uint8_t*)&TxBuf, len, 0xFFFF);
    }
    

    因為我們使用printf函數基本不使用其返回值,所以這裏直接用void類型了。自定義變參函數需要用到va_start、va_end等宏,需要包含頭文件stdarg.h。關於變參函數的一些學習可以查看網上的一些博文,如:

    https://www.cnblogs.com/wulei0630/p/9444062.html

    這裏我們使用的是STM32的HAL庫,其給我們提供HAL_UART_Transmit接口可以直接把整個發送緩衝區的內容給一次性發出去。

    2、基於STM32標準庫

    若是基於STM32的標準庫,就需要一字節一字節的循環發送出去,具體代碼如:

    #define TX_BUF_LEN  256     /* 發送緩衝區容量,根據需要進行調整 */
    uint8_t TxBuf[TX_BUF_LEN];  /* 發送緩衝區                       */
    void MyPrintf(const char *__format, ...)
    {
      va_list ap;
      va_start(ap, __format);
        
      /* 清空發送緩衝區 */
      memset(TxBuf, 0x0, TX_BUF_LEN);
        
      /* 填充發送緩衝區 */
      vsnprintf((char*)TxBuf, TX_BUF_LEN, (const char *)__format, ap);
      va_end(ap);
      int len = strlen((const char*)TxBuf);
      
      /* 往串口發送數據 */
      for (int i = 0; i < len; i++)
      {
    	while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);    
    	USART_SendData(USART1, TxBuf[i]);
      }
    }
    

    測試結果:

    我們也可以使用我們的MyPrintf函數按照上一篇文章:======的方式封裝一個宏打印函數:

    以上就是我們自定義方式實現的一種串口打印函數。

    但是,我想說:對於串口打印的使用,我們沒必要自己創建一個打印函數。看到這,是不是有人想要打我了。。。。看了半天,你卻跟我說沒必要用。。。

    哈哈,別急,我們不應用在串口打印調試方面,那可以用在其它方面呀。

    (1)應用一:

    比如最近我在實際應用中:我們的MCU跑的是我們老大自己寫的一個小的操作系統+我們公司自己開發的上位機。我們MCU端與上位機使用的是串口通訊,MCU往上位機發送的數據有兩種類型,一種是HEX格式數據,一種是字符串數據。

    但是我們下位機的這兩種數據,在通過串口發送之前都得統一把數據封包交給那個系統通信任務,然後再由通信任務發出去。在這裏,就不能用printf了。老大也針對他的這個系統實現了一個deb_printf函數用於打印調試。

    但是,那個函數既複雜又很雞肋,稍微複雜一點的數據就打印不出來了。因此我利用上面的思路給它新封裝了一個打印調試函數,很好用,完美地兼容了老大的那個系統。具體代碼就不分享了,大體代碼、思路如上。

    (2)應用二:

    我們在使用串口與ESP8266模塊通訊時,可利用類似這樣的方式封裝一個發送數據的函數,這個函數的使用可以像printf一樣簡單。可以以很簡單的方式把數據透傳至服務端,比如我以前的畢設中就有這麼應用:

    以上就是本次的分享,如有錯誤,歡迎指出!謝謝

    我的個人博客:https://www.lizhengnian.cn/

    我的微信公眾號:嵌入式大雜燴

    我的CSDN博客:https://blog.csdn.net/zhengnianli

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

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

    ※推薦台中搬家公司優質服務,可到府估價

  • mybatis 逆向工程使用姿勢不對,把表清空了,心裏慌的一比,於是寫了個插件。

    mybatis 逆向工程使用姿勢不對,把表清空了,心裏慌的一比,於是寫了個插件。

    使用mybatis逆向工程的時候,delete方法的使用姿勢不對,導致表被清空了,在生產上一刷新后發現表裡沒數據了,一股涼意從腳板心直衝天靈蓋。

    於是開發了一個攔截器,並寫下這篇文章記錄並分享。

    這鍋只能自己背了

    你用過 mybatis 逆向工程(mybatis-generator-maven-plugin)生成相關文件嗎?

    就像這樣式兒的:

    可以看到逆向工程幫我們生成了實體類、Mapper 接口和 Mapper.xml。

    用起來真的很方便,我用了好幾年了,但是前段時間翻車了。

    具體是怎麼回事呢,我給大家擺一下。

    先說一下需求吧。就是在做一次借據數據遷移的過程中,要先通過 A 服務的接口拿到所有的借據和對應的還款計劃數據,然後再對這些借據進行核查,如果不滿足某些添加,就需要從表中刪除借據和對應的還款計劃。

    借據和對應的還款計劃存放在兩張表中,用借據號來關聯。

    而上線之後,我在一片歡聲笑語中把還款計劃表清空了,而這個必現的問題,在測試階段同學還沒有測試出來。

    事情發生后我趕緊找到了 DBA 協助修複數據:

    是怎麼回事呢,為了模擬這個場景,我在本地創建了兩張表,訂單表(orderInfo)和訂單擴展表(orderInfoExt),他們之間用訂單號進行關聯:

    僅僅是做演示,所以兩張表是非常簡單的,

    我們假設現在表裡面的這條訂單號為 2020060666666 的數據經過判斷是錯誤數據,我當時寫的代碼體現在單元測試裏面是這樣的:

    看出問題了嗎?

    第 42 行用的 example 對象還是 OrderInfo 的 example。而真正的 OrderInfoExt 對象的 exampleExt 對象沒有進行任何賦值的操作。

    為什麼會出現這樣的烏龍呢?

    都怪 idea 太智能了!(強行找個借口)

    我只需要打一個 ex 然後回個車…. example 就出現在代碼裏面了。

    而這種沒有參數的 example 傳進去,在 mapper.xml 裏面是這樣處理的:

    執行一下,看看效果:

    看到 delete from order_info_ext 語句。你說你慌不慌?

    當然在線上的服務器肯定是看不到執行的 SQL 的,但是當報警短信一條一條接着來的時候,當連上數據庫一看錶,發現數據沒了的時候。

    你說你慌不慌?

    反正我一刷新后發現表裡沒數據了,一股涼意從腳板心直衝天靈蓋。這種時候都還是要小小的心慌一下,先大喊一聲“卧槽!數據怎麼沒了?”

    然後趕緊報備,準備找 DBA 撈數據吧。

    還好,本次誤刪不影響正常業務。

    數據恢復過程就不說了,聊一下這事發生后我的一點思考吧。

    哦,對了,還得說一下測試同學為什麼沒有發現這個問題。這個問題確實是一個必現的問題,測試案例上也寫了這個測試點。

    但是測試同學查看數據的時候用的是 select 語句,查詢條件給的是確實需要被刪除的數據 。

    然後分別在兩個表裡面執行后發現:數據確實是沒了。

    是的,是數據確實是沒了。整個表都乾淨了。

    看着測試妹子驚慌失措的樣子,我還能怎麼說呢?

    這鍋,不甩了,我自己背下來吧。

    重新審視逆向工程

    我們先看看逆向工程幫我們生成的接口:

    我相信用過 mybatis 逆向工程的朋友們,一看到這幾個接口就知道了:喲,這都是老朋友了。

    當我再去重新審視這些接口的時候我會發現其實還有會有一些問題的。

    比如 delete 這樣的高危語句我們還是需要盡量的手寫 xml。

    比如 updateByExample 同樣存在由於誤操作沒有 where 條件,導致全表更新的情況。

    比如 select 語句是查出了整個對象,但是有時間我們可能只需要對象裏面的某個值而已。

    比如 select 語句針對大表、關鍵表操作的時候,不能從代碼的角度限定 SQL 必須帶上索引字段查詢。

    上面的這些問題我們怎麼處理呢?

    我的建議是不要使用 mybatis 的逆向工程,全都手寫。

    開個玩笑。我們肯定不能因噎廢食,何況逆向工程確實是幫我們做了很多工作,極大的方便我們這樣的 CRUD Boy 進行 CRUD。

    所以,我想 mybatis 的逆向工程肯定是有什麼配置來控制生成哪些接口的,別問為什麼,問就是直覺。

    因為要是讓我去開發這樣的一個插件,我肯定也會提供對應的開關配置。

    我現在的想法是不讓它給我生成 delete 相關的接口,這個接口用起來我心裏害怕。

    所以怎麼配置呢?

    我們去它的 DTD 文件裏面找一下嘛:

    這個文件不長,一共也才 213 行,你能發現這一塊東西:

    你用腳指頭想也能知道,這就是我們要找的開關配置。從 DTD 文件的描述中來看,這個幾個參數是配置在 table 標籤裏面的。

    我們去試一下:

    果然是這樣的。然後我們進行相關配置如下:

    再生成一下:

    果然,delete 相關的接口沒了。

    然後我們程序中真的需要 delete 操作的時候,再自己去手寫 xml 文件。

    那你自己寫的 xml 文件也忘記寫 where 條件了這麼辦?

    這個月工資別領了。自己好好反思反思。

    當然,就算你真的忘記寫了,下面這個攔截器還能給你兜個底,幫你一把。

    mybatis 攔截器使用

    其實這個方案是我想到的第一個方案。導致上面問題的原因很簡單嘛,就是執行了delete 語句卻沒有 where 條件。

    那麼我們可以攔截到這個 SQL 語句,然後對其進行兩個判斷:

    是否是 delete 語句。 如果是,是否包含 where 條件。

    那麼問題來了,我們怎麼去攔截到這個 SQL 呢?

    答案就是我們可以開發一個 mybatis 插件呀,就像分頁插件那樣。

    插件,聽起來很高端的樣子,其實他就是個攔截器。實現起來非常簡單。

    先去官網上看一下:

    中文:https://mybatis.org/mybatis-3/zh/configuration.html#plugins

    英文:https://mybatis.org/mybatis-3/configuration.html

    在官網上,對於插件這一模塊的描述是這樣的:

    通過 MyBatis 提供的強大機制,使用插件是非常簡單的,只需實現 Interceptor 接口,並指定想要攔截的方法簽名即可。

    正如官網說的這樣,插件開發、使用起來是非常簡單的。只需要三步:

    1.實現 Interceptor 接口。

    2.指定想要攔截的方法簽名。

    3.配置這個插件。

    mybatis 插件開發

    基於上面這三步,大家先看一下我們這插件怎麼寫,以及這個插件的效果。

    先說明一下本文涉及到的源碼 mybatis 版本是 3.4.0。

    本文用攔截器的目的是判斷 delete 語句中是否有 where 條件。所以,開發出來的插件長這樣:

    再來一個複製粘貼直接運行版本:

    @Slf4j
    @Intercepts({
            @Signature(type = Executor.class, method = "update",
                    args = {MappedStatement.class, Object.class}),
    })
    public class CheckSQLInterceptor implements Interceptor {
    
        private static String SQL_WHERE = "where";
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            //獲取方法的第0個參數,也就是MappedStatement。@Signature註解中的args中的順序
            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
            //獲取sql命令操作類型
            SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
            final Object[] queryArgs = invocation.getArgs();
            final Object parameter = queryArgs[1];
            BoundSql boundSql = mappedStatement.getBoundSql(parameter);
            String sql = boundSql.getSql();
            if (SqlCommandType.DELETE.equals(sqlCommandType)) {
                //格式化sql
                sql = sql.replace("\n", "");
                if (!sql.toLowerCase().contains(SQL_WHERE)) {
                    sql = sql.replace(" ", "");
                    log.info("刪除語句中沒有where條件,sql為:{}", sql);
                    throw new Exception("刪除語句中沒有where條件");
                }
            }
            return invocation.proceed();
        }
    
        @Override
        public Object plugin(Object o) {
            return Plugin.wrap(o, this);
        }
    
        @Override
        public void setProperties(Properties properties) {
        }
    }
    

    再把插件註冊上(註冊插件還有其他的方法,後面會講到,這裏只是展示Bean注入的方式):

    我們先看看配上插件后的執行效果:

    可以看到日誌中輸出了:

    刪除語句中沒有where條件,sql為:delete from order_info_ext

    並拋出了異常。

    這樣,我們的擴展表的數據就保住了。在測試階段,測試同學就一定能扯出來問題,瞟一眼日誌就明白了。

    就算測試同學忘記測試了,在生產上也不會執行成功,拋出異常后還會有報警短信通知到相應的開發負責人,及時登上服務器去處理。

    功能實現了,確實是非常的簡單。

    我們再說回代碼,你說說看:當你拿到上面這段代碼后,最迷惑的地方是哪裡?

    其中的邏輯是很簡單的了。 沒有什麼特別的地方,我想大多數人拿到這段代碼迷惑的地方在於這個地方吧:

    這個 @Intercepts 裏面的 @Signature 裏面為什麼要這樣配置?

    我們先看看 @Intercepts 註解:

    裏面是個數組,可以配置多個 Signature。所以,其實這樣配置也是可以的:

    關鍵的地方在於 @Signature 怎麼配置:

    這個問題,我們放到下一節去討論。

    mybatis插件的原理

    上面一小節我們知道了對於開發插件而言,難點在於 @Signature 怎麼配置。

    其實這也不能叫難點,只能說你不知道能配置什麼,比較茫然而已。這一小節就來回答這個問題。

    要知道怎麼配置就必須要了解mybatis 這四大對象:Executor、ParameterHandler 、ResultSetHandler 、StatementHandler 。

    官網上說:

    MyBatis 允許你在映射語句執行過程中的某一點進行攔截調用。默認情況下,MyBatis 允許使用插件來攔截的方法調用包括:

    Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

    ParameterHandler (getParameterObject, setParameters)

    ResultSetHandler (handleResultSets, handleOutputParameters)

    StatementHandler (prepare, parameterize, batch, update, query)

    那官網上說的這四大對象分別是拿來幹啥用的呢?

    Executor:Mybatis 的執行器,用於進行增刪改查的操作。

    ParameterHandler :參數處理器,用於處理 SQL 語句中的參數對象。

    ResultSetHandler:結果處理器,用於處理 SQL 語句的返回結果。

    StatementHandler :數據庫的處理對象,用於執行SQL語句

    知道攔截的四大對象了,我們就可以先揭秘一下上面的這個註解配置的是啥了:

    type 字段存放的是 class 對象,其取值範圍就是上面說的四大對象。

    method 字段存放的是 class 對象的具體方法。

    args 存放的是具體方法的參數。

    看到這幾個參數你想到了什麼?有沒有條件反射式的想到反射?如果沒有的話你再咂摸咂摸,看看能不能品出一點反射的味道。

    本文用攔截器的目的是判斷 delete 語句中是否有 where 條件,因此經過上面的分析,Executor 對象就能滿足我們的需求。

    所以在本文示例中 @Signature 的 type 字段就是 Executor.class。

    那 method 字段我們放哪個方法呢?放 delete 嗎?

    這就得看看 Executor 對象的方法有哪些:

    可以看到其中並沒有 delete 方法,和 SQL 執行相關的,看起來只有 query和 update。

    但是,我們可以大膽猜測一下呀:delete 也是一種 update。

    接着去求證一下就行:

    可以看到 delete 方法確實是調用了 update 方法。

    所以在本文案例中 @Signature 的 method 字段放的是 update 方法。

    已經知道具體的方法了,那 args 放的就是方法的入參,所以這段配置就是這樣來的:

    真的,我覺得這屬於手摸手教學系列了。經過這個簡單的案例,我希望大家能做到一通百通。

    接下來帶大家看看我們常用的分頁插件 pageHelper 是怎麼做的吧。

    其實你用腳指頭也能想到,分頁插件肯定是攔截的查詢方法,我們只是需要去驗證一下就可以。

    引入 pageHelper 后可以看到 Interceptor 的多了兩個實現:

    我們看一下 PageInterceptor 方法吧:

    對吧,攔截了兩個 query 方法,一個參數是 4 個,一個參數是 6 個:

    同時,在 intercept 的實現裏面有一部分是這樣寫的:

    4 個參數和 6 個參數是做了單獨處理的,至於為什麼要這樣處理,至於為什麼要攔截兩個 query 方法,說起來又是一個很長的故事了。

    詳細的可以看看這個鏈接: https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Interceptor.md

    好了,還是那句話:如果要寫出好的 mybatis 插件,必須知道 @Signature 怎麼去配置。配置后能攔截哪些東西,你心裏應該是有點數的。

    mybatis插件的原理

    前面我們知道攔截器怎麼寫了,接下來簡單的分析一波原理。

    前幾天我看到一個觀點是說看開源框架的源碼建議從 mybatis 看起。我是很贊成這個觀點的,確實是優雅,而容易看懂。能品出很多設計模式的使用。

    一句話總結 mybatis插件的原理就是:動態代理加上責任鏈。

    先看一下 Plugin 類的動態代理:

    標號為 ① 的地方一看就知道,InvocationHandler,JDK 動態代理,沒啥說的。

    標號為 ② 的地方是 wrap 方法,生成 Plugin 代理對象。

    標號為 ③ 的地方是 invoker 方法,圈起來的目的是想說是在這裏判斷當前方法是否是需要被攔截的方法。如果是則用代理對象走攔截器邏輯,如果不是則用目標對象,走正常邏輯。

    給大家看一下這個地方的 debug 效果:

    一個平平無奇的 if 判斷,是攔截器的關鍵。為什麼這個地方多說了幾句呢?

    因為其實這就是細節的地方。當面試的時候面試官問你:mybatis 是怎麼判斷是否需要攔截這個方法的時候你能答上來。說明你是真的看過源碼。

    責任鏈是怎麼體現的呢?

    就是這個地方: org.apache.ibatis.plugin.InterceptorChain

    你看又學到一招,mybatis 裏面的設計模式還有責任鏈。

    我們看一下 pluginAll 方法的調用方:

    這個地方就體現出之前官網說的了:

    插件是作用於這四大對象的:Executor、ParameterHandler 、ResultSetHandler 、StatementHandler 。

    上面框起來的這四個框,就是插件調用的地方。

    那麼插件在什麼時候被加載,或者說什麼是被註冊上的呢?

    還是回到攔截鏈這個類上去:

    pluginAll 方法我們已經知道有哪些地方調用了。這個方法裏面其實還有兩個考點。

    第一就是 interceptor 這個 List 集合的定義,用了 final 修飾。所以要注意 final 修飾基本類型和引用類型的區別,被 final 修飾的引用類型變量內部的內容是可以發生變化的。

    第二就是 getInterceptors 返回的是一個不可修改的 List 。所以,要對集合 interceptors 進行修改,只能通過 addInterceptor 方法進行元素添加,保證了這個集合是可控的。

    所以,我們只需要知道哪裡調用了 addInterceptor 方法,哪裡就是插件被註冊的地方。

    一個是 SqlSessionFactoryBean ,一個是 XMLConfigBuilder。

    使用 XML 配置是這樣的:

    熟悉 mybatis 的朋友們肯定知道,無非就是對於標籤的解析而已。

    解析到 plugins 標籤,則進入 pluginElement 方法中,在這個方法裏面調用 addInterceptor:

    本文沒有使用 XML 的形式配置,所以我們主要看一下 SqlSessionFactoryBean。

    怎麼看呢?

    不要盲目的走入源碼,加個斷點看調用鏈,跟着調用鏈去走就很清晰了。

    在這個地方加一個斷點:

    然後 debug 起來,你就可以看到整個調用鏈了:

    然後我們根據上面的調用鏈,我們就可以找到源頭了:

    在 MybatisAutoConfiguration 的構造方法裏面初始化了 interceptors。

    而 interceptorsProvider.getIfAvailable() 方法也解釋了為什麼我們只需要在程序裏面這樣注入我們的攔截器就可以被找到了:

    對 getIfAvailable 方法不熟悉的朋友可以去補一下這塊的知識,我這裏只是給大家看一下這個方法上的註釋:

    當然,你這樣去注入的話有可能會不生效,你就會大罵一聲:寫的什麼垃圾玩意,配置上了也不對呀。

    別著急呀,我還沒說完呢。你看看是不是有自定義的 SqlSessionFactory 在項目里。

    看一下注入 SqlSessionFactory 的源碼上面的那個註解了嗎?

    @ConditionalOnMissingBean ,看名字也知道了,當你的項目裏面沒有自定義的 SqlSessionFactory 的時候,才會由源碼給你注入,這個時候才會正在的註冊上插件:

    如果你有自定義的 SqlSessionFactory,那麼請手動調用 factory.setPlugins 方法。

    所以,總結一下插件的三種配置方法:

    1.xml方式配置。

    2.如果沒有自定義 SqlSessionFactory 直接 @Bean 注入攔截器即可。

    3.如果有自定義 SqlSessionFactory 需要在自定義的地方手動調用 factory.setPlugins 方法。

    其實我嘗試過第四種方法,在application.properties 裏面配置:

    這種配置方式才是符合 SpringBoot 思想的配置。才是真正的絲滑,潤物無聲的絲滑。

    可惜,我配置上后,點擊到對應的源碼地方一看:

    它調用的是 getInterceptors 方法,我就知道肯定是有問題了:

    果然,運行起來會報這樣的錯誤: Failed to bind properties under 'mybatis.configuration.interceptors' to java.util.List<org.apache.ibatis.plugin.Interceptor>

    找了一圈原因,最後發現了這個 issue:

    github.com/mybatis/spring-boot-starter/issues/180

    這個“奇異博士”頭像的用戶提出了和我一樣的問題:

    然後下面的回答是這樣的:

    別問,問就是不支持。請使用 @Bean 的方式。

    最後說一句(求關注)

    點個“贊”吧,周更很累的,不要白嫖我,需要一點正反饋。

    才疏學淺,難免會有紕漏,如果你發現了錯誤的地方,還請你指出來,我對其加以修改。

    感謝您的閱讀,我堅持原創,十分歡迎並感謝您的關注。

    我是 why,一個被代碼耽誤的文學創作者,不是大佬,但是喜歡分享,是一個又暖又有料的四川好男人。

    歡迎關注我的微信公眾號:why技術。在這裏我會分享一些java技術相關的知識,用匠心敲代碼,對每一行代碼負責。偶爾也會荒腔走板的聊一聊生活,寫一寫書評、影評。感謝你的關注,願你我共同進步。

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

    【其他文章推薦】

    ※超省錢租車方案

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

    ※回頭車貨運收費標準

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

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

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

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

  • 詳解SpringBoot(2.3)應用製作Docker鏡像(官方方案)

    詳解SpringBoot(2.3)應用製作Docker鏡像(官方方案)

    關於《SpringBoot-2.3容器化技術》系列

    《SpringBoot-2.3容器化技術》系列,旨在和大家一起學習實踐2.3版本帶來的最新容器化技術,讓咱們的Java應用更加適應容器化環境,在雲計算時代依舊緊跟主流,保持競爭力;

    全系列文章分為主題和輔助兩部分,主題部分如下:

    1. 《體驗SpringBoot(2.3)應用製作Docker鏡像(官方方案)》;
    2. 《詳解SpringBoot(2.3)應用製作Docker鏡像(官方方案)》;
    3. 《掌握SpringBoot-2.3的容器探針:基礎篇》;
    4. 《掌握SpringBoot-2.3的容器探針:深入篇》;
    5. 《掌握SpringBoot-2.3的容器探針:實戰篇》;

    輔助部分是一些參考資料和備忘總結,如下:

    1. 《SpringBoot-2.3鏡像方案為什麼要做多個layer》;
    2. 《設置非root賬號不用sudo直接執行docker命令》;
    3. 《開發階段,將SpringBoot應用快速部署到K8S》;

    本篇簡介

    在前文,咱們快速體驗了官方推薦的docker鏡像製作方案,但也產生了幾個疑問:

    1. SpringBoot-2.3版本推薦的鏡像構建方案和舊版本比有什麼不同?
    2. pom.xml中spring-boot-maven-plugin插件新增的參數,到底做了什麼?
    3. Dockerfile中,java -Djarmode=layertools -jar application.jar extract這個操作啥意思?

    本篇的目標就是解答上述問題,在尋找答案的過程中不斷補全知識點,提升自己;

    關鍵知識點:鏡像layer

    前文多次提到的鏡像layer到底是什麼,為什麼會有多層layer?有必要先把這個知識點夯實了,請參考文章《SpringBoot-2.3鏡像方案為什麼要做多個layer》

    老版本SpringBoot的官方方案

    SpringBoot-2.2.0.RELEASE版本為例,官方文檔(
    https://docs.spring.io/spring-boot/docs/2.2.0.RELEASE/reference/pdf/spring-boot-reference.pdf)給出的做法如下:

    1. 將SpringBoot工程編譯構建,在target目錄得到jar;
    2. 在target目錄新建dependency文件夾;
    3. 將jar解壓到dependency文件夾;
    4. 編寫Dockerfile文件,內容如下:
    FROM openjdk:8-jdk-alpine
    VOLUME /tmp
    ARG DEPENDENCY=target/dependency
    COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib
    COPY ${DEPENDENCY}/META-INF /app/META-INF
    COPY ${DEPENDENCY}/BOOT-INF/classes /app
    ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.MyApplication"]
    
    1. 可見,官方推薦的做法是將整個jar文件解壓,在Dockerfile中多次用COPY命令分別複製,這樣做的好處顯而易見:多個layer,如果鏡像的新版本中只修改了應用代碼,那麼下載鏡像時只會下載/app這個layer,其他部分直接使用本地緩存,這是docker鏡像的常規優化手段;
    2. 上述方案有個小問題:麻煩!!!
    3. 於是2.3.0.RELEASE版本做了些優化,讓事情變得簡單些;

    2.3.0.RELEASE版本方案和舊版的區別

    2.3.0.RELEASE版本構建Docker的步驟如下:

    1. pom.xml中的spring-boot-maven-plugin插件增加一個配置項;
      2.編譯構建生成jar;
    2. 編寫Dockerfile,裏面用到了多階段構建(multi-stage builds),用工具從jar中提取拆分后,再多次執行COPY命令將拆分后的內容放入鏡像,達到多個layer的目的;

    因此,2.3.0.RELEASE版本和舊版本相比有如下變化:

    1. pom.xml中多了個參數;
    2. 構建好jar后,無需自己解壓jar;
    3. Dockefile內容不一樣,舊版是手動解壓jar,再在Dockerfile分別複製,2.3.0.RELEASE是通過java命令從jar中提取出各部分內容

    搞清楚了新舊版本的區別,咱們繼續研究下一個問題吧;

    pom.xml中spring-boot-maven-plugin插件新增的參數

    1. pring-boot-maven-plugin插件新增參數如下圖所示:

    2. 上述參數有啥用?我這邊編譯構建了兩次jar,第一次有上述參數,第二次沒有,將兩次生成的jar解壓后對比,發現用了上述參數后,生成的jar會多出下圖紅框中的兩個文件:

    1. 看看layers.idx文件的內容,如下圖:
    1. 上圖中的內容分別是什麼意思呢?官方已給出了詳細解釋,如下圖紅框:
    1. 綜上所述,layers.idx文件是個清單,裏面記錄了所有要被複制到鏡像中的信息,接下來看看如何使用layers.idx文件,這就涉及到jar包中新增的另一個文件:spring-boot-jarmode-layertools-2.3.0.RELEASE.jar

    spring-boot-jarmode-layertools工具

    1. 前面已經介紹過jar中除了layers.idx,還多了個文件:spring-boot-jarmode-layertools-2.3.0.RELEASE.jar ,來看看這個文件的用處;
    2. 進入工程的target目錄,這裏面是編譯后的jar文件(我這裏文件名為dockerlayerdemo-0.0.1-SNAPSHOT.jar),注意此時的spring-boot-maven-plugin插件是帶上了下圖紅框中的參數的:
    1. 執行以下命令:
    java -Djarmode=layertools -jar dockerlayerdemo-0.0.1-SNAPSHOT.jar list
    
    1. 得到結果如下圖所示,是layers.idx文件的內容:
    1. 來看看官方對這個layertools的解釋,list參數的作用上面我們已經體驗過了,重點是紅框中的extract參數,它的作用是從jar中提取構建鏡像所需的內容:
    1. 看到這裏,您是否想到了《體驗SpringBoot(2.3)應用製作Docker鏡像(官方方案)》中Dockerfile的內容,請看下圖的紅框和紅字,是否有種恍然大悟的感覺:jar構建生成清單layers.idx,Dockerfile中根據清單從jar提取文件放入鏡像:

    至此,三個問題都已經找到了答案,小結一下:

    SpringBoot-2.3.0.RELEASE推薦的鏡像構建方案和舊版本相比有什麼不同

    1. pom.xml中的spring-boot-maven-plugin插件增加一個配置項;
    2. 構建好jar后,舊版本要自己解壓jar,新版不需要;
    3. 新版本的jar中,多了個文件清單layers.idx和鏡像文件處理工具spring-boot-jarmode-layertools-2.3.0.RELEASE.jar
    4. 舊版的Dockefile內容:因為前面解壓好了,所有在Dockerfile里直接複製前面解壓的內容,這裏就有個風險:前一步解壓和當前複製的文件位置要保證一致;
    5. 新版的Dockerfile內容:使用工具spring-boot-jarmode-layertools-2.3.0.RELEASE.jar,根據的layers.idx內容從jar中提取文件,複製到鏡像中;
    6. 新版的Dockerfile中,由於使用了分階段構建,因此從jar提取文件的操作不會保存到鏡像的layer中;

    pom.xml中spring-boot-maven-plugin插件新增的參數,到底做了什麼

    spring-boot-maven-plugin插件新增的參數,使得編譯構建得到jar中多了兩個文件,如下圖所示:

    Dockerfile中,java -Djarmode=layertools -jar application.jar extract這個操作啥意思

    1. java -Djarmode=layertools -jar application.jar extract的作用是從jar中提取文件,這些文件是docker鏡像的一部分;
    2. 上述操作的參數是extract,另外還有兩個參數,官方解釋它們的作用如下:

    至此,問題已全部澄清,相信您對SpringBoot-2.3.0.RELEASE官方的鏡像構建方案也足夠了解了,最後是我根據自己的認識畫的流程圖,幫助您快速理解整個構建流程:

    歡迎訪問我的GitHub

    • 地址:https://github.com/zq2599/blog_demos
    • 內容:原創文章分類匯總,及配套源碼,涉及Java、Docker、K8S、DevOPS等

    歡迎關注我的公眾號:程序員欣宸

    https://github.com/zq2599/blog_demos

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

    台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

    ※推薦台中搬家公司優質服務,可到府估價

  • 又大又硬!每個男人都想擁有的硬派SUV

    又大又硬!每個男人都想擁有的硬派SUV

    G-class擁有的超強非鋪裝行駛能力,折服了不少喜歡越野但又想買買菜的買家。前中后三把電控差速鎖,在野外擁有了全時四驅,你唯一需要擔心的就是自己的車技了。從軍車轉型至民用車,G-class一共發展了三代車型,而換代車型也即將在明年亮相。

    全車方方正正,車燈也是極其簡單的圓形,價格不是一般消費者能承擔得起的,擁有三把差速鎖,超強的越野能力,整車所帶來硬派的風格,卻是它最大的魅力。

    沒錯,要說的就是奔馳G-class。字母G本義是德語Gelndewagen的縮寫,也就是越野車的意思。從1979年誕生到現在,G-class還是一副方盒子的模樣。模樣沒變,其非承載式車身和梯形大梁的設定也沒變。

    G-class擁有的超強非鋪裝行駛能力,折服了不少喜歡越野但又想買買菜的買家。前中后三把電控差速鎖,在野外擁有了全時四驅,你唯一需要擔心的就是自己的車技了。

    從軍車轉型至民用車,G-class一共發展了三代車型,而換代車型也即將在明年亮相。沒錯,還是那個模樣,但整車車重減輕了200kg,動力系統除了六缸機外,還會提供4.0L V8雙渦輪增壓發動機。

    G-class硬派的風格着實讓不少車迷痴迷,要是能買上一輛,基本就是人生贏家的存在了。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

    ※回頭車貨運收費標準

  • 手把手帶你入門numpy,從此數據處理不再慌【四】

    手把手帶你入門numpy,從此數據處理不再慌【四】

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

    今天是numpy專題的第四篇文章,numpy中的數組重塑與三元表達式。

    首先我們來看數組重塑,所謂的重塑本質上就是改變數組的shape。在保證數組當中所有元素不變的前提下,變更數組形狀的操作。比如常用的操作主要有兩個,一個是轉置,另外一個是reshape。

    轉置與reshape

    轉置操作很簡單,它對應線性代數當中的轉置矩陣這個概念,也就是說它的功能就是將一個矩陣進行轉置

    轉置矩陣的定義是將一個矩陣的橫行寫為轉置矩陣的縱列,把縱列寫成轉置矩陣的橫行。這個定義的是二維的矩陣,本質上來說,轉置操作其實是將一個矩陣沿着矩陣的大對角線進行翻轉。翻轉之後,顯然這個矩陣的各個維度都會發生變化。

    其中二維的矩陣最直觀,一個4 x 3的矩陣,轉置之後得到的是3 x 4的矩陣。如果維度更多呢?如果是3 x 2 x 4的矩陣轉置之後會得到什麼?

    很簡單,得到的會是4 x 2 x 3的矩陣。我們都知道,如果我們把一個矩陣各個維度的大小寫在一起,會得到一個元組(tuple),這個元組稱為矩陣的shape,我實在是不知道該怎麼翻譯這個單詞,但是我覺得叫做形狀不太妥當,所以就保留了英文原文。轉置之後,矩陣的shape會整個翻轉。比如(3, 2, 4)會變成(4, 2, 3)。

    我們可以來看一個例子,會更加的直觀。首先我們先看最簡單的二維矩陣:

    這是隨機出來的一個3 x 4的二維矩陣,在numpy當中,有兩種方式獲取一個矩陣或者是數組的轉置。第一種方式是通過在數組的變量名之後加上.T操作符,第二種方式是調用numpy中的transpose函數,這兩種方式是一樣的。我個人比較傾向於前者,寫起來比較簡單。

    我們可以看到轉置之後新的矩陣的第一列其實是原矩陣的第一行,第一行是原矩陣的第一列。可以看成是原矩陣按照從左上角到右下角的一條無形的線翻轉之後的結果。

    理解了轉置之後,我們再來看reshape操作。其實我們從這個單詞上也能大概猜到它的意思,reshape也就是再次shape的意思,本意是根據我們想要的shape重新組裝矩陣當中的元素

    我們來看一個例子吧,首先,我們通過arange方法來獲取一個一維的數組:

    因為是1維的,所以我們去看它的shape也只有一維。假設我們不喜歡這樣的一維數組,而想把它變成3 x 4或者是6 x 2的格式,這時候使用reshape就會很方便。

    本質上來說reshape操作其實就是按照順序從矩陣當中獲取元素,然後按照我們制定的shape填充出一個新的矩陣的操作。這個應該不難理解, 它也是非常常用的重塑操作,通過reshape和轉置,我們可以很方便地操作矩陣的大小,根據我們的需要作出改變。

    三元表達式

    在許多編程語言當中我們經常會用到三元表達式,三元表達式其實本質就是if-else語句,只是我們用特殊的方法將它簡寫。

    比如說在C++當中,我們可以把if condition A else B簡寫成:condition ? A : B。Python同樣支持三元表達式,不過對C++的三元表達式做了一些改動,在Python當中三元表達式寫成:A if condition else B。相對來說更加直觀一些,我們經常會在數組初始化的時候用到三元表達式。

    比如,我們可能會這樣生成一個數組:

    arr = [1 if condition else 0 for _ in range(10)]
    

    我們通過條件來判斷了每一位是1還是0來生成了一個數組,簡化了代碼。在numpy當中同樣繼承了這個用法,我們一樣可以使用三元表達式,不過numpy將它封裝進了where函數當中,我們是通過調用一個方法來實現三元表達式的功能。我們來看下具體的用法,假設我們有兩個數組:

    我們還有一個bool型的數組c,我們希望根據c數組選擇從a數組或者是b數組當中獲取數據。我們可以使用where寫成這樣:

    在這個例子當中,c數組中的1和0分別表示True和False。當我們調用np.where的時候,numpy會自動根據c數組當中的值去選擇從a數組還是b數組當中獲取數據。相當於我們執行了這麼一段代碼:

    [x if c else y for c, x, y in zip(c, a, b)]
    

    雖然兩者的運行結果是一樣的,但是顯然使用循環的方法計算耗時更長,而使用numpy的向量做法運算速度更快。除此之外,numpy的where方法還支持高維的數組,但是循環的方法不行。並且where還有一些更高級的用法,比如說我們傳入的第二個和第三個參數,可以不是數組而是一個標量。比如我們可以指定當c中的元素是True的時候填入1,否則填入-1:

    甚至我們還可以將標量和向量結合起來使用:

    並且這裏的數組c也可以替換成邏輯運算:

    總結

    今天的文章主要介紹了Numpy當中的reshape、轉置以及where的用法,這些也是numpy的基礎用法,尤其是轉置、reshape,幾乎是處理數據必用的方法。所以想要從事Python機器學習或者是人工智能的小夥伴,numpy的這些用法是一定要會的。

    本文當中介紹的只是numpy的一些固定套路,但其實numpy很多的用法是可以組合的,一些看似平淡無奇的用法組合在一起之後會有神奇的效果。這一點光看書或者是資料是很難窮盡的,所以如果你已經學會了這些api的基本使用,接下來最應該做的是去讀一些大牛的源碼,看看大牛們是如何運用這些工具的,相信一定還會有新的收貨。

    文章就到這裏,如果喜歡本文,可以的話,請點個關注

    本文使用 mdnice 排版

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

    台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

    ※推薦台中搬家公司優質服務,可到府估價

  • 12萬就能買德國旅行車 試駕大眾蔚領

    12萬就能買德國旅行車 試駕大眾蔚領

    這時你可以選擇切到S擋,這時你就可以激活一下蔚領的潛在運動基因,讓它活潑一些,也讓自己小小放肆一回。而蔚領的懸挂行程得到了增加,正常行駛沒有什麼問題,遇上爛路的話你只能包容一下了。作為一輛跨界屬性的車型,沒有一個體面的後備廂,是沒有說服力的。

    六年時間,無論是對於人還是事,都是一段不短的時間了。如果說一輛車花了六年時間來研發,那它推出市場后的反響,直接就能定義它是否成功了。這對於一汽大眾蔚領來說,它面對的處境是很相似的。

    近期一汽大眾的大新聞莫過於和奧迪間的瓜葛,但回到產品上來說,新上市的蔚領也是吸引了不少眼球。蔚領的定位其實有點模糊,長着旅行車的身版,標配沒卵用的行李架,又有摻了點跨界風。而它的外觀最大的亮點,我覺得應該是在於它的尾燈造型了。但是相對於現在套娃風來說,還算有點誠意了。

    EA211 1.4T發動機+DQ2007速乾式雙離合變速箱,這套動力單元的搭載給人的感覺就和豆漿油條一樣,基於pQ34平台,一切的配方都是那麼熟悉。

    所以蔚領一上手,你還是會不由自主的覺得,這是一輛大眾。D擋模式下,你要車子很快的走起來,那就得來多點油,雖然扭矩有小幅提升,但低扭輸出還是差不多。這時你可以選擇切到S擋,這時你就可以激活一下蔚領的潛在運動基因,讓它活潑一些,也讓自己小小放肆一回。

    蔚領的內飾個人而言還是可以接受的,雖然都是一片硬塑料,拋開質感而言,說得過去。

    蔚領提供了1.4T和1.6L兩款發動機型號可選,目前的售價區間為12.59-16.29萬元。能接受兩廂車造型,憧憬一家大小在周末出外休閑的朋友,現在就多了一個選擇了。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

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

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

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

    ※回頭車貨運收費標準

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

  • 12萬左右到底是買SUV還是轎車比較好?

    12萬左右到底是買SUV還是轎車比較好?

    誠然,1。6L發動機在扭矩輸出方面弱於1。2T,但是居家過日子,還是1。6L會更讓人省心。1。6L+CVT的這套動力組合,雖然給不了你太多激情,但是輸出平順線性,易於操控,質量可靠,就像春雨一樣,潤物細無聲。得益於較高的車身,即便精英版配有天窗,頭部空間依然很充裕。

    前言

    12萬左右買SUV還是轎車,估計這是許多人糾結的問題。但實際上問題其實很簡單,為何這麼說?下面聽我娓娓道來。

    首先這個價位,能挑選的主流合資小型SUV是幾乎沒有的。剩下一些非主流的貨,例如創酷與2008,這兩車是比小型SUV還要小一點點的車,因此我也不作推薦。

    在12萬內想買到SUV就唯有投身自主品牌的懷抱,但是買轎車卻有許多花樣選擇。所以我就推薦幾款自主品牌的SUV與合資家轎來給各位參考一下。

    廣汽乘用車-傳祺GS4

    2017款 200T G-DCT兩驅舒適版

    指導價:11.58萬

    編者點評:

    GS4的雙離合變速箱算是自主品牌當中匹配較為完善的一個,無論是高速巡航,還是低速跟車都表現得相當出色,不會展露出明顯的頓挫。同時,由於雙離合變速箱的傳動效率較高,其百公里綜合油耗在7.8L左右,在同級別中難遇敵手。

    底盤也是GS4一個最大的亮點,當車子碾過不平的路面時,懸架總能很好地吸收震動,給人滿滿的厚實感。更難能可貴的是,遇到大坑窪時,GS4依舊可以不露餡,不會讓乘客有種懸架極限已到的感覺。

    廣汽豐田-雷凌

    2016款 1.6G CVT精英版

    指導價:12.48萬

    編者點評:

    自從雷凌出了1.2T發動機以後,1.6L的日子恐怕即將到頭,所以現在終端也會有1萬塊以上的優惠,絕對是抄底的好時機。停產不代表1.6L這款發動機不行,相反地,這款發動機是日本原裝進口,各種配合精度都會優於國產。誠然,1.6L發動機在扭矩輸出方面弱於1.2T,但是居家過日子,還是1.6L會更讓人省心。

    1.6L+CVT的這套動力組合,雖然給不了你太多激情,但是輸出平順線性,易於操控,質量可靠,就像春雨一樣,潤物細無聲。得益於較高的車身,即便精英版配有天窗,頭部空間依然很充裕。同時,後排地台全平還配有中央頭枕,坐在中間的乘客也不會太難受,這點想得很周到。

    一汽-大眾-寶來

    2016款 1.6L 自動時尚型

    指導價:11.98萬

    編者點評:

    寶來剛出的時候,許多人都針對其拉皮車的身份責罵一番。但是,是否是舊平台其實並不十分重要,關鍵還是要看實際的產品力。從這方面來說,寶來的表現還是不錯的。1.6L+6擋手自一體的動力組合,動力還算輕快,變速箱的邏輯清晰,換擋平順,高速巡航時也有很好的油耗表現。

    懸挂濾震有韌性,行駛質感有所提升,座椅也變寬大,坐到裏面感覺更舒適。缺點也是有一點點,中控台並沒有重新設計,顯得有點老氣,整車的做工精細度不足,一些接縫處的間隙較大。

    編者總結:

    雖然SUV現在銷售火爆,但是同品牌下的SUV定價多數都高轎車那麼一些。12萬這個價錢左右想買車,如果不是對SUV有剛性需求的, 還是建議買合資家轎。現在的國產SUV儘管發展得紅紅火火,但是在可靠性上與合資車型依舊有差距,為了日後省心地過日子,合資家轎會是更好的選擇。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

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

    ※超省錢租車方案

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

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

    ※回頭車貨運收費標準

  • 讓昂科威、冠道震驚!這輛全新中型SUV有9個擋

    讓昂科威、冠道震驚!這輛全新中型SUV有9個擋

    98-32。98萬冠道就是採用了2。0T+9AT動力總成的熱點車型,這樣的動力總成同級少有。而冠道上的9AT與發動機配合默契,並且車速達到110km/h以上時,變速箱就能升到第9擋。所以探界者也要在動力匹配上多下功夫了。上汽通用別克-昂科威指導價:20。

    日前,雪佛蘭官方正式發布了一款全新的9速自動變速箱,而這款變速箱將先搭載在海外版的邁銳寶上。另外,國產版的雪佛蘭中型SUV探界者2.0T車型也會優先搭載這款變速箱!

    此變速箱的代號為Hydra-Matic 9T50,是適用於前驅橫置平台的變速箱,而它的特點在於各個擋位間齒比綿密,而第九擋的齒比達到了0.62,是一個亮眼的水平。

    雪佛蘭官方稱這款9AT變速箱會比現在各車型上使用的6AT變速箱在燃油經濟性方面提高3%!

    而且這款9AT變速箱採用單向離合器,讓它的體積相對緊湊,和老款6AT變速箱相差無幾。

    探界者將搭載這款9AT變速箱

    探界者的2.0T車型將搭載這款9AT變速箱,該2.0T渦輪增壓發動機的最大功率256馬力、峰值扭矩352牛米!

    搭配9AT變速箱有望提高車型的行駛平順性、降低續航發動機噪音、降低油耗等!

    另外,探界者作為雪佛蘭在國內生產的旗艦SUV車型,它搭載9AT變速箱,更有利於其樹立品牌形象。而這也會成為消費者選擇探界者的重要原因之一,所以實際表現值得期待。

    競爭對手

    廣汽本田-冠道

    指導價:26.98-32.98萬

    冠道就是採用了2.0T+9AT動力總成的熱點車型,這樣的動力總成同級少有。而冠道上的9AT與發動機配合默契,並且車速達到110km/h以上時,變速箱就能升到第9擋!所以探界者也要在動力匹配上多下功夫了。

    上汽通用別克-昂科威

    指導價:20.99-34.99萬

    銷量一直強勢的昂科威與探界者比較類似,而現款的昂科威2.0T車型採用的是6擋手自一體變速箱。未來改款的昂科威是否也會搭載9擋手自一體變速箱?

    編者語:

    隨着各個品牌對變速箱的研發投入更多,9AT變速箱不再是豪華品牌所獨有的。這對於我們消費者來說,選擇更多自然是好事。而探界者有望在2017年第一季度上市,它的表現如何?我們一起期待吧。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

    ※超省錢租車方案

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

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

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

    台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

  • 這些車空間比SUV好 舒適性不輸轎車 關鍵B格夠高

    這些車空間比SUV好 舒適性不輸轎車 關鍵B格夠高

    40萬大家知道寶馬是操控的王者,那麼3系旅行版可謂是在售旅行車當中兼顧駕駛樂趣和舒適性的佼佼者,雙腎型的進氣格柵非常的熟悉,還有犀利的天使眼大燈,雖說是注重操控的車子,但配置上還是挺豐富的,無鑰匙進入/啟動、感應電動後備箱、發動機啟停等配置非常豐富。

    準備買車的你是否也想過這個問題

    買個三廂車吧又太普遍了

    看上兩廂車又覺得太小

    嫌棄SUV的操控性很一般

    家庭首選的MpV又顯得太笨重

    這時候旅行車可能就是你的不二之選

    作為歐洲人最喜愛的車型之一

    旅行車兼備了轎車和MpV的實用性

    也同時擁有者SUV良好的通過性

    今天就為大家介紹一下旅行車

    沃爾沃(進口)-V60

    指導價:30.99-63.69萬

    旅行車這類在歐洲隨處可見的家用車多年來都無法討國人的喜愛,更多的是被當成少數人追求的個性和另類車,隨着吉利收購了沃爾沃之後,旗下的車型是越來越年輕化了,外觀也更容易受國人所接受,估計下一換代車型就會使用XC90最新的家族式前臉,雷神之錘也會裝備上去,而且現在的終端優惠巨大,性價比很高。

    內飾設計還是那套經典的数字鍵盤式中控,似乎有些脫離時代的腳步了,4635*1866*1484mm的車身尺寸,2776mm的軸距,加上方正的造型設計,內部空間還是很寬敞的,屬於那種能拉能跑的选手,喜歡跨界風格可選cross四驅版本,追求高性能可以選擇百公里加速4.8秒的polestar版本。

    寶馬(進口)-3系

    指導價:39.96-68.40萬

    大家知道寶馬是操控的王者,那麼3系旅行版可謂是在售旅行車當中兼顧駕駛樂趣和舒適性的佼佼者,雙腎型的進氣格柵非常的熟悉,還有犀利的天使眼大燈,雖說是注重操控的車子,但配置上還是挺豐富的,無鑰匙進入/啟動、感應電動後備箱、發動機啟停等配置非常豐富。

    車身尺寸和三廂版的一致為4628*1811*1476mm,軸距為2810mm,大尺寸的全景天窗為全系標配,相當厚道,乘坐空間則和短軸3系一致,最大亮點還是他的後備箱整體表現,後排座椅放倒后非常的平整,完全可以當床用了,又解鎖了很多高難度動作,而且儲物空間很人性化設計,很方便實用。

    奔馳(進口)-C級

    指導價:38.28-57.00萬

    大多數人都認為旅行車不就是以轎車為基礎,然後把後備箱加高到和車頂平齊么,奔馳C級旅行車表示不服,始終堅持這份情懷的它取得了不錯的成績,與前兩輛車不同的是,C200旅行版擁有漂亮的AMG運動套件,和18英寸的AMG式輪轂,看上去更吸引人的眼球。

    內飾是與三廂版奔馳C級沒有區別的,依然是豪華感十足,4729*1810*1457的車身尺寸,2840mm的軸距,乘坐空間是比較寬敞的,其後備箱的開后比較大,裝載物品非常方便,動力選擇上有小排量的1.6T(最大功率156馬力)車型選擇,相比於前兩款車型,家用性更強。

    總結:旅行車有着轎車般的舒適性和SUV空間上的靈活性,實用性更強,而這些豪華車終端優惠都很大,特別是沃爾沃V60性價比很高,20多萬就能擁有進口旅行車是相當划算的。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

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

    ※推薦台中搬家公司優質服務,可到府估價

  • 這款SUV國產以後只要十幾萬,奇駿虎軀一震

    這款SUV國產以後只要十幾萬,奇駿虎軀一震

    驅動方式上,是兩者最大的差別,奇駿是前驅,而歐藍德是適時四驅。歐藍德的這套四驅系統雖然算不上很強大,但是應付一些泥濘路面總比前驅車型要來得更強。內飾設計奇駿的中控台看上去很工整,各種按鈕的布置也符合人機工程學的設計,烤黑鋼琴漆面板讓整車多了幾分高級感。

    前言

    自從奇駿更新換代以後,憑藉著年輕的外觀與依舊出色的產品力,迅速地霸佔了合資緊湊型SUV銷量的前十名。但是,歐藍德國產以後將對奇駿的地位發起衝擊。

    進口的歐藍德起步售價在20萬元以上,明顯缺乏競爭力。國產以後,價格下探到15.98萬,與奇駿的售價區間高度吻合。實際對比,誰更勝一籌?下面我就以兩款售價相近的車型來做對比。

    廣汽三菱-歐藍德

    2016款 2.4L 四驅精英版 5座

    指導價:18.98萬

    東風日產-奇駿

    2014款 2.0L CVT舒適版 2WD

    指導價:19.68萬

    動力總成

    歐藍德是2.4L發動機配CVT變速箱(模擬6擋),最大輸出192馬力與235牛米。而奇駿則是2.0L發動機+CVT變速箱(模擬7擋),最大輸出150馬力與200牛米。從數據上就可以看出歐藍德的動力輸出要比奇駿的高上不少,兩者均採用CVT變速箱,所以在行駛起來都是追求平順。

    底盤結構

    歐藍德的底盤

    奇駿的底盤

    奇駿與歐藍德均採用前麥弗遜式獨立懸架,后多連桿獨立懸架的底盤構造。不過,奇駿在前後懸架上均加入了橫向穩定桿,這樣可以有效地對車身的側傾進行抑制。驅動方式上,是兩者最大的差別,奇駿是前驅,而歐藍德是適時四驅。歐藍德的這套四驅系統雖然算不上很強大,但是應付一些泥濘路面總比前驅車型要來得更強。

    內飾設計

    奇駿的中控台看上去很工整,各種按鈕的布置也符合人機工程學的設計,烤黑鋼琴漆面板讓整車多了幾分高級感。

    歐藍德的中控看上去更加圓滑,設計也更為簡約,按鈕不多,功能多集合於中控屏上。整體給人感覺不如奇駿高級。不過,方向盤上那兩塊換擋撥片卻顯得格外醒目。

    後排空間

    奇駿的後排

    歐藍德的後排

    奇駿的後排中央

    歐藍德的後排中央

    歐藍德的後排空間還比較大,就是坐墊偏短,身高174cm的體驗者坐到後排也能有兩拳有多的腿部空間。奇駿的腿部空間表現與歐藍德大致相同,只是坐墊長度會更長,對腿部的承托更加好。兩者的後排中央都有一定拱起,但是歐藍德的拱起更高。

    隔音表現

    在實際測試中,歐藍德無論在怠速、60km/h、80km/h和120km/h的情況下,隔音表現都要優於奇駿不少。

    配置對比

    配置方面的對比,歐藍德處於一個很明顯的領先狀態,具體的差距可以看下圖的對比。

    油耗與保養費用對比

    多位車主給出的奇駿百公里綜合油耗為8.9L,而歐藍德則為9.9L,這也符合預期水平。首先,歐藍德的排量要比奇駿大,其次它採用了四驅系統,所以高出奇駿1L的百公里綜合油耗也是完全可以接受的。

    奇駿6萬公里的總保養費用為5225元,不過這數據是按礦物油來算的,如果換成半合成機油,費用會相應增加。歐藍德6萬公里的總保養費用為8716元,高出奇駿不少,而且採用的也同為礦物質油。

    編者總結:

    歐藍德國產以後的性價比確實比以前要高了不少,而且各方面的表現依舊不錯。如果對油耗與內飾設計不太敏感的話,歐藍德會是一個更好的選擇,起碼它的四驅系統能帶你去見識更遠的風景。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※超省錢租車方案

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

    ※回頭車貨運收費標準

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

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

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

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