這5款帥爆的車,多花6、7萬你都覺得不虧?

由於奧迪A5 Coupe的車身線條都偏硬朗,所以它很難體現出Coupe那種優雅,更像一款雙門的大型“小鋼炮”。奧迪A5有一款叫哥特蘭綠的專屬車漆,象徵著“復古騎士”,其實還是挺有味道的。從奧迪A4L的名字我們就可以看出,奧迪A4實現國產時並沒有保留標軸版,所以奧迪A5 Coupe的軸距要比國產奧迪A4L的短。

有許多走高端路線的汽車品牌,為了建立豐富的汽車產品線,基於同一個車型平台往往能衍生出轎跑版、三廂版或旅行版等車型,通過這些車型的差異取向,去滿足不同消費者的個性需求。我們通過對這些車型的特性分析,發現他們的最大差異在於外觀、實用性和售價。

通過這樣的大致分析,我們就可以理解到為什麼傳統的三廂車是銷量最大,因為它的特性很均衡,而且受眾廣,在實現國產的情況下,價格也有很大優勢。不過我們今天的話題是那些很炫酷但又不是太實用,而且賣得很貴的轎跑車型,也就是我們常說的Coupe。

如果問Coupe車型最值錢的地方在於哪裡?我認為是車身側面,一般情況下,Coupe車型與同平台的三廂車型往往在底盤架構和動力總成方面是一致的,最大的區別在於Coupe車型是雙門的,由於是雙門設計,後排空間受到了很大限制,而且後排只能設定兩個座位,乘坐空間也非常拘束,但是也因為由四門變成了雙門,車身側面的美感上升了不止一個層次,而且都是無框車門,這種姿態上的進化,就是Coupe車型的價值所在,這也就是我們所說的“顏值即正義”。

那麼這些Cuope車型到底要比三廂車貴多少呢?又帥了多少呢?我們通過幾款熱門的車型分析一波。

奔馳C級/C級Coupe

首先第一款Coupe車型是奔馳的C級,由於進口版本的奔馳C級Coupe並沒有1.6T動力的版本,最低配置為C 200,指導價38.08萬,相對於同動力同配置(配置接近)的北京奔馳C 200運動版,指導價為31.28萬,兩車差價6.8萬,這6.8萬多了什麼?

外觀方面,C級Coupe的前臉配有星輝大標中網,側面與三廂版一樣是採用雙腰線的設計,但是由於少了兩個門,而且車身高度也更低,所以側面看起來的效果非常優雅;而尾部的設計也有所不同,更小的后風擋,扁平式的尾燈樣式,更簡潔的尾箱蓋設計,都使得C級Coupe的尾部具有更寬大的視覺效果。

尺寸方面,C級Coupe的軸距和C級三廂標軸版的保持一致,這也象徵著它們源自同一平台。但這不意味着它們有相同的空間表現,如果是170cm以上的人,就不要考慮坐進後排了,實在太難受。

內飾樣式也基本保持一致,不過根據車主反映,C級Coupe的內飾會更具質感,畢竟是進口車型,一些用料和做工還是比較優越。

進口的C級Coupe除了沒有1.6T的動力外,2.0T的高低功率版與國產C級保持一致,只是在調校方面有小小差異,但基本感覺不出來。

寶馬3系/4系 Coupe

其實現在的4系Coupe就是過去的3系轎跑版,只是現在獨立出來了,現款寶馬430i M運動套裝版指導價為52.59萬,而國產的華晨寶馬330i M運動曜夜版指導價為45.20萬,兩車差價7.39萬。看上去還好,實際上現在華晨寶馬330i的優惠幅度非常大。

首先4系Coupe由於“雙腎”和“天使眼大燈”的設計跟3系有一點點差異,加上下進氣格柵也比3系更扁平,所以整個前臉都是更扁平的;側面的確也比3系更拉風,但是實際上3系的側面也是非常協調和優美的;尾部除了尾燈的設計有一點點不同,其他的差距並不大。值得一提的是4系有一款專屬的“海岸藍”車漆。

尺寸方面,寶馬4系coupe的軸距與3系標軸版的保持一致,但車身高度也是更低,所以造型當然更拉風。

內飾不要說出自同平台的車了,對於寶馬來說,3系和7系的內飾風格就一個樣。上圖方向盤的樣式不同主要是因為基本版和運動版的差別。

由於寶馬4系Coupe為進口車型,所以也沒有配備1.5T的動力,不過卻多了一個3.0T的動力,但又跟M4的3.0T不一樣,功率比M4的要更低。

奧迪A4L/奧迪A5 Coupe

現款奧迪A5 Coupe 40 TFSI時尚型指導價39.80萬(看似很便宜,實際聽說要加價),而對應的現款國產奧迪A4L 30周年年型 40 TFSI 時尚型指導價為34.57萬(現優惠幅度還不錯,應該有4萬左右),兩車差價5.23萬(所以實際差價應該上10萬,具體以4S店為準)。

相對於奧迪A4L,奧迪A5 Coupe的前臉也有所不同,大燈樣式更簡潔凌厲,六邊形的進氣格柵更扁平,整個前臉也是更扁平的風格;而側面的腰線呈“大波浪”的走勢;尾燈的設計則更運動。由於奧迪A5 Coupe的車身線條都偏硬朗,所以它很難體現出Coupe那種優雅,更像一款雙門的大型“小鋼炮”…?奧迪A5有一款叫哥特蘭綠的專屬車漆,象徵著“復古騎士”,其實還是挺有味道的。

從奧迪A4L的名字我們就可以看出,奧迪A4實現國產時並沒有保留標軸版,所以奧迪A5 Coupe的軸距要比國產奧迪A4L的短。

內飾風格兩個幾乎保持一致,基本也就材質或配置的小小差異。不得不說奧迪內飾的科技感或高級感真非常強。

動力方面,奧迪A5 Coupe除了有沒配備1.4T的動力,2.0T的高低功率版也與國產的奧迪A4L保持一致;如果你要更強的動力,那就要上奧迪S5,甚至奧迪RS5了。

英菲尼迪Q50L/Q60 Coupe

最新款的英菲尼迪Q60 2.0T豪華版指導價為38.98萬,而相同動力,配置接近的最新款英菲尼迪Q50L 2.0T豪華版的指導價為36.98萬(現有5萬左右的優惠幅度),兩車差價2萬元,就指導價來看,差距的確非常小。

要說英菲尼迪Q60 Coupe與英菲尼迪Q50L在外觀上的差距,無論是整體還是細節都有所體現,更大尺寸的中網、更精緻的大燈和尾燈造型、更具動感的C柱設計,整體外觀更寬、更扁。對於英菲尼迪的Q60 Coupe,可以說是以上車型中最動感或最性感的一款了,車身那些流暢且優美的曲線可以說是把Coupe那種美感展現得淋漓盡致。

由於英菲尼迪Q50實現國產時也沒有保留標軸版,所以Q60 Coupe的軸距是和進口版,沒加長的Q50保持一致。

內飾風格兩車也是一個樣,但材質方面應該也有一點點不一樣,或者說座椅的設計不同,Q60的座椅會更偏向運動風格。對於這兩款偏向運動的車型來說,這套內飾並沒有很激進,而是通過大面積的皮質營造比較豪華的氛圍。

動力方面,現款Q60隻有一個動力可選,也就是和Q50L一樣2.0T。但Q60在海外有3.0T的版本,如果你對動力有比較高的追求,就只能選擇平行進口了,但那樣的價格當然也貴得離譜吧。

雷克薩斯IS/RC

其實雷克薩斯RC與以上所有的Coupe都不同,它是出自跑車平台的純種跑車。但是,由於雷克薩斯RC的調節和設定都非常偏向於豪華和舒適,就連排氣聲浪也是模擬出來的,而且它也是跟雷克薩斯IS共享同一套動力總成,所以經常會被誤以為是雷克薩斯IS的Coupe車型。

那麼作為一款跑車,獨立的平台,價格當然會很貴,最受歡迎的200t F SpORT版本指導價為52.80萬,而現款雷克薩斯IS 300 F SpORT版的指導價為36.90萬,由於兩款都是進口車型,所以基本都沒什麼優惠,兩車差價15.9萬。畢竟RC是跑車嘛…可以理解。

由於出自不同的平台,所以軸距也是不同的。而整個外觀造型,比起IS,雷克薩斯RC更長,更寬,更矮,那當然也更帥咯。

同為F SpORT版本,那源自LFA的“机械式液晶”是必不可少的,兩車內飾風格基本保持一致,但細心的朋友就會發現,其實還是有所不同的,就在中央空調出風口下方的中控面板,IS是陷進去的,而RC是揚出來的。還有就是擋桿後面,RC配有一個小型“手寫板”。

動力總成是共享的,講道理,RC比IS少了兩個門,那就應該更輕,也跑得更快。但事實並非如此,同是F SpORT版本,RC的整備質量要重一點點,RC的官方百公里加速為7.5秒,而IS的官方百公里加速為7秒。

總結

最後,通過上述車型對比,如果不考慮終端優惠,其實那些進口的Coupe車型也沒有我們想象中那麼貴,也只不過比同級三廂車型貴個5、6、7萬。至於實用性,你也別指望它們的後排有什麼驚喜了,總之,1米7以上的乘客“免進”後排。其實對於中國市場而言,說後排不重要的人只是少數,但說顏值不重要的人更是少數,那麼對於顏值、後排、價格,你會怎麼選?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※超省錢租車方案

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

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

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

看到大廠的面試題,你慌了嗎?,【朝花夕拾】Android多線程之(二)ThreadLocal篇,android中getWidth()和getMeasuredWidth()之間的區別

       最近參加了TX音樂Android工程師崗位的面試,這裏憑記憶記錄了面試中的一些考點,希望能幫到正在面試的你(答案還在整理中)!

1、Java調用函數傳入實際參數時,是值傳遞還是引用傳遞?

2、單例模式的DCL方式,為什麼需要第二次判空?

    單例模式的DCL是一種比較好的單例實現方式,面試中被問及的頻率非常高,考察的方式也多種多樣。根據本題的提問,這裏簡單整理了一下,這裏面的每一個點最好都能夠做到爛熟於心:

 1 public class Test {
 2     private volatile static Test instance;
 3 
 4     private Test() {
 5 
 6     }
 7 
 8     public static Test getInstance() {
 9         if (instance == null) {
10             synchronized (Test.class) {
11                 if (instance == null) {
12                     instance = new Test();
13                 }
14             }
15         }
16         return instance;
17     }
18 }

 這裡有5個要點需要注意:

    (1)第一個注意點:使用私有的構造函數,確保正常情況下該類不能被外部初始化(非正常情況比如通過反射初始化,一般使用反射之後單例模式也就失去效果了)。

    (2)第二個注意點:getInstance方法中第一個判空條件,邏輯上是可以去除的,去除之後並不影響單例的正確性,但是去除之後效率低。因為去掉之後,不管instance是否已經初始化,都會進行synchronized操作,而synchronized是一個重操作消耗性能。加上之後,如果已經初始化直接返回結果,不會進行synchronized操作。

    (3)第三個注意點:加上synchronized是為了防止多個線程同時調用getInstance方法時,各初始化instance一遍的併發問題。

    (4)第四個注意點:getInstance方法中的第二個判空條件是不可以去除,如果去除了,並且剛好有兩個線程a和b都通過了第一個判空條件。此時假設a先獲得鎖,進入synchronized的代碼塊,初始化instance,a釋放鎖。接着b獲得鎖,進入synchronized的代碼塊,也直接初始化instance,instance被初始化多遍不符合單例模式的要求~。加上第二個判空條件之後,b獲得鎖進入synchronized的代碼塊,此時instance不為空,不執行初始化操作。

    (5)第五個注意點:instance的聲明有一個voliate關鍵字,如果不用該關鍵字,有可能會出現異常。因為instance = new Test();並不是一個原子操作,會被編譯成三條指令,如下所示。
          1)給Test的實例分配內存

          2)初始化Test的構造器

          3)將instance對象指向分配的內存空間(注意,此時instance就不為空)

        然後咧,java會指令重排序,JVM根據處理器的特性,充分利用多級緩存,多核等進行適當的指令重排序,使程序在保證業務運行的同時,充分利用CPU的執行特點,最大的發揮機器的性能!簡單來說就是jvm執行上面三條指令的時候,不一定是1-2-3這樣執行,有可能是1-3-2這樣執行。如果jvm是按照1-3-2來執行的話,當1-3執行完2還沒執行的時候,如果另外一個線程調用getInstance(),因為3執行了此時instance不為空,直接返回instance。問題是2還沒執行,此時instance相當於什麼都沒有,肯定是有問題的。然後咧,voliate有一個特性就是禁止指令重排序,上面的三條指令是按照1-2-3執行的,這樣就沒有問題了。

       參考:https://blog.csdn.net/hnd978142833/article/details/81633730

3、volatile有什麼作用?AtomiticInteger有什麼作用,底層實現原理是什麼?與synchronized關鍵字有什麼區別?cas有什麼弊端?

       關於多線程相關的知識點,volatile、AtomiticInteger、synchronized、cas問題都是高頻考點,與之相關的知識點如:重量級鎖/輕量級鎖、樂觀鎖/悲觀鎖、JMM(Java Memmory Mode Java內存模型)、用戶空間/內核空間、多線程三要素(原子性、可見性、順序性)、自旋、ABA問題等,都是需要掌握的要點。

       推薦閱讀:【死磕Synchronized底層實現】

                         【面試官沒想到,volatile能吹上半個小時】

                         【《吊打面試官》系列-樂觀鎖、悲觀鎖】

                         【「每日知識點」什麼是 CAS 機制】

4、Android Log中的tag,用類名.class.getSimpleName()來獲取,會有什麼弊端?

5、反射有什麼作用?有什麼弊端?

6、廣播底層實現機制?為什麼會比AIDL方式慢?與EventBus相比有什麼區別?

7、Handler如何保證每個線程只有一個looper?ThreadLocal有什麼作用?

       這道題其實主要考察ThreadLocal,不了解ThreadLocal的可以閱讀博文:【朝花夕拾】Android多線程之(二)ThreadLocal篇,以及【再有人問你什麼是ThreadLocal,就把這篇文章甩給他!】

8、100個0~100之間的整數,實現排序

9、RxJava介紹

10、Glide介紹

11、measuredWidth和width的區別

      結論:getMeasuredWidth()獲取的是view原始的大小,也就是這個view在XML文件中配置或者是代碼中設置的大小。getWidth()獲取的是這個view最終显示的大小,這個大小有可能等於原始的大小也有可能不等於原始大小。

      推薦閱讀:【android中getWidth()和getMeasuredWidth()之間的區別】

12、SparseArray介紹,為什麼能提高性能

13、MVP與MVVM的區別,MVVM的實現方式

14、分享時,Android N開始對url做了什麼限制?

15、HashSet介紹

16、軟引用和弱引用的區別,什麼時候會GC?System.gc()的時候系統會立即回收系統垃圾嗎?

17、Exception和Error有什麼區別?Error能被捕捉嗎?OOM Error能被捕捉嗎?

18、Sharepreference commit()和apply()的區別。Sharepreference進程安全嗎?線程安全嗎?

19、500×500的png圖片所佔的內存大小。同一張圖片在xxdpi-drawable和drawable中誰佔用的內存更大,大多少?

20、RecyclerView與ListView的區別。

大體上這記得么多,面試官會根據回答的內容進一步深入提問,讀者可以在該知識點上進一步拓展。

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

【其他文章推薦】

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

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

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

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

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

因為我最近忙、所以我寫了它

一、事出有因

       1、上周工作原因項目的事情每天都很忙,周五下班和樂師兄下班的時候已經晚上11點了,然後和師兄吃了一個燒烤吃到了12點了(結果啥也沒吃,錢也花了挺多的。ps:程序員建議養生)扯遠了 ,主要是一周比較忙周六沒有進行我們學校的健康報備信息填寫。導致輔導員給我打了6個電話(現在我還是在實習中,所以還歸學校管)自己剛好在看網絡請求這一塊的東西,說干就干!!!

二、知其所以然

       1、我們學校的健康報備主要是將自己每天的信息填寫到學校的公眾號上面。打開頁面是這樣的。這個時候我們就要想一下我們是要做什麼了。首先我們健康報備的流程是=>打開學校公眾號=>輸入自己的學號點擊查詢=>然後輸入自己的正式情況=>點擊提交。

             

     三、反向分析

            1、做為程序員的我們首先要清楚我們要什麼,現在我們已經清楚了要做什麼了和步驟。現在就是用我們的程序模擬用戶進行正常的報備工作。首先我將報備鏈接從學校公眾號複製出來,然後使用瀏覽器訪問查看我們在進行報備的時候我們向瀏覽器發起了什麼和做了什麼。

            2、在左邊的是我們的頁面,右邊的是網頁請求的文件和信息,我們就一步一步的進行分析。這裏我們可以看到我們在訪問頁面的時候會生成一些信息__EVENTVALIDATION   、 __VIEWSTATEGENERATOR 我以前在長沙寫的也是ASPX頁面使用控件程序的時候也會生成一些這個,需要通過這些東西來獲取我們頁面填寫的信息所以這裏我們需要保留,因為我們等下需要輸入學號然後點擊查詢,不過不傳這些參數獲取不到我輸入的學號,這個是我嘗試過的哈哈。

             3、下面看到的是我輸入了自己的學號點擊查詢獲取到的信息,我們可以看到這裏使用的是formData進行傳遞到後台去的,也可以明顯的看到我填寫的信息了。然後進入到了填寫頁面。然後我們在查看頁面上面生成的東西。

              4、我們輸入完整的信息之後,點擊報備按鈕又會發生什麼呢?可以看到我們提交的formData信息,請求也成功了(今天我已經報備了,所以是這個提示)。現在整個流程我們已經清楚了,以及請求的參數。那就讓我們開始整活吧。

 四、開始動手

        1、廢話不多說直接創建一個.net core 的項目整活。我先寫了一個簡單的html頁面進行填寫學號信息,然後在寫一個定時任務每天晚上12點之後自動執行,健康報備信息。

public async static Task AsyncQuartz()
        {
            await Task.Run(async () =>
             {
                 //創建一個鍵值集合
                 NameValueCollection nameValue = new NameValueCollection {
                    //定時任務的序列類型是二進制的
                    { "quartz.serializer.type", "binary" }
                 };
                 //創建定時任務調度器工廠
                 StdSchedulerFactory factory = new StdSchedulerFactory(nameValue);
                 //獲取工廠中的調度器
                 IScheduler scheduler = await factory.GetScheduler();

                 //開啟調度器
                 await scheduler.Start();

                 //然後就是創建我們的任務
                 //給任務一個身份
                 //在進行建立
                 IJobDetail userServiceJob = JobBuilder.Create<HealthForJob>()
                                              .WithIdentity("UserServiceJob", "UserServiceJobGroup")
                                              .Build();

                 //任務有了創建觸發器
                 ITrigger userServiceTrigger = TriggerBuilder.Create()
                  .WithIdentity("userServiceTrigger", "userServiceTriggerGroup")
                  .StartNow()

                  //給定執行時間,然後在重複執行
                  .WithSimpleSchedule(x => x.WithIntervalInHours(6).RepeatForever())
                  .Build();

                 //將任務和觸發器進行綁定放入觸發器中

                 //單任務調用
                 await scheduler.ScheduleJob(userServiceJob, userServiceTrigger);
             });
        }

            2、首先我們需要模擬用戶向報備網頁發起請求這裏我使用的是HttpClient 對象發起請求,怕被攔截我還填了很多請求頭哈哈。但我們發起get請求的時候獲取的是一段長的html字符串。

            3、然後我們要使用一個神器進行html分析了。HtmlAgilityPack 它可以解析我們獲取的html字符串代碼

          4、我們創建一個HtmlDocument htmlDoc1 = new HtmlDocument(); 對象然後然後將我們獲取的html 對象放到 htmlDoc1.LoadHtml(strHtml);就可以解析成了正常的html了,也可以直接在頁面上面複製xpath結構,然後直接放進來就好了

                            htmlDoc1.LoadHtml(strHtml);
                            //這裏就是通過html結構尋找我們想要的節點信息
                            var liNodes1 = htmlDoc1.DocumentNode.SelectNodes("//div[@class='aspNetHidden']/input");

            5、這裏我們獲取到了html節點之後就可以進行正常取數據啦。

                6、這裏就開始我們的請求三大步了,直接模擬一個form表單請求將我們的數據傳遞就好了

 

using (HttpContent httpContent = new FormUrlEncodedContent(keyValuePairs))
                        {
                            httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
                            strHtml = httpClient.PostAsync("URL", httpContent).Result.Content.ReadAsStringAsync().Result;
                            if (!string.IsNullOrWhiteSpace(strHtml))
                            {
                                htmlDoc1.LoadHtml(strHtml);
                                var liNodes1 = htmlDoc1.DocumentNode.SelectNodes("//div[@class='aspNetHidden']/input");
                                keyValuePairs.Clear();
                                foreach (var item in liNodes1)
                                {
                                    var id = item.Attributes["id"].Value;
                                    var value = item.Attributes["value"].Value;
                                    if (!string.IsNullOrWhiteSpace(id) && !string.IsNullOrWhiteSpace(value))
                                    {
                                        keyValuePairs.Add(id, value);
                                    }
                                }
                            }
                        }

 

五、項目部署

        1、項目部署使用的是Docker +JenKins 實現自動化部署,現在我在公司也想慢慢推廣因為我們公司服務器權限管的比較嚴格,每次發布測試環境都需要找師兄發布,導致師兄很多時間都在幫我們發布項目。所以這個技術我覺得是很有必要在我們部門推廣。這個項目主要使用的了.net core 3.1 作為框架 Dapper作為數據訪問層,Quartz 定時任務 ,HtmlAgilityPack 進行Html結構分析,Docker 部署項目 ,JenKins 實現項目自動化部署。由於篇幅問題這些技術會在後面的文章分享出來。我自己也多研究一下避免誤人子弟。哈哈

六、個人說明

        1、以上就是我寫的全部流程,我們需要重複試錯,因為你要了解寫這個程序的同行的思路哈哈,我還看過一些網站是通過惰性加載信息,還有一些比較重要的信息會通過其他的方式傳遞,就是防止我們爬取,比如京東的商品價格使用Js請求的方式傳遞Jsonp請求,這個這個就需要我們多動手動倒騰了。重點說明一下這個只是自己學習使用的,對於學校健康報備我雙手支持。源碼就不分享了大家動起手來吧。

 

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

協議生成器工具

前言

何為協議生成器?其實就是前後端同學在對協議的時候使用的工具,手動添加對應的內容,最後一鍵發布自己需要的任何與協議有關的內容。
有人會說,我直接寫proto文件用它的命令行也可以生成很多文件的。不過proto本身的能力,我工具都可以使用,因為本身工具就可以調用proto。下面開始介紹一下這款附帶源碼的工具
良心價格,買來不一定要用,但是你可以拿來學習這種思想;用什麼語言開並不重要,重要的還是思想;編程編的就是思想,就跟寫文章一樣。

介紹

  1. 文件功能
  2. 定義服務

    可能我門一款遊戲用到好幾個服務,比如登陸服務,大廳獲得道具服務,戰鬥服務。對於棋牌遊戲或者聯網對戰遊戲尤其如此。而這些服務器有的是長連接,有的是短鏈接,有的是proto格式,有的是json格式。在這個工具里都是可以設置的。

  3. 定義協議號

    我們用socket做遊戲的一般定義格式的時候都是協議號+數據長度+數據段。這個很正常,當然http也是可以這樣定義的。比如http://xxx.xxx.com:80/classname/functionname?xxx=cc&xx=xx
    ip+端口,這個跟socket是一樣的。端口之後和問號之前的就可以定義為協議號了,也就是資源路徑。這樣就可以長短鏈接使用同樣的處理方式。

  4. 定義模塊

    我個人喜歡將不同的功能分為不同的模塊。然後在模塊中定義消息。

  5. 定義消息格式

    比如這個商店模塊,在進入商店時需要給服務器發送獲取商品列表的消息。而服務器需要兩個字段。並設置了類型。而工具是支持註釋的,CNName就是了。有請求格式,自然也有返回格式,所以有GetProductInfoResult,並定義了返回的消息格式。

  6. 使用

    xxxHandler代表了一個請求處理。一個處理會有請求消息,響應消息。所以將剛才定義的兩個消息格式,設置到request和response中就可以了。

導出

xml目錄為項目配置文件,export為導出內容目錄

導出的文檔

導出proto的java類

使用lua腳本解析xml文件

結語

工具介紹就這些,希望對有需求的人提供一定的幫助。關鍵還是思想,結合我微店裡的網絡框架一起學習會更快速。
歡迎關注我的公眾號,獲取更多精彩內容。

歡迎掃碼關注公眾號《微笑遊戲》,瀏覽更多內容。

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

【其他文章推薦】

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

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

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

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

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

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

對抗代碼遺忘的思考——提問回顧與個人總結

一、提問回顧

提問博客點這裏

關於第一章中的“軟件的非連續性”

經過這一學期的實踐,我對軟件的非連續性有了比較具體的認識。

在我們的項目中,後端涉及比較複雜的狀態機,而可能一些小的輸入變化就會觸髮狀態機的改變,進而影響系統的運行狀態。測試後端狀態機是整個項目最困難、最複雜的地方,在這部分,軟件的非連續性就體現得淋漓盡致。

而應對這種困難的方式也有很多,一方面,可以做充分的測試,盡量覆蓋狀態機的每一條狀態轉移路徑,另一方面,在設計時也要做好充分的考慮,盡量讓系統的狀態數較少,轉移數較少,從而使得系統的穩定性提高,易於維護和管理。

關於第二章中提到的“單元測試”

在學期初提出的問題是

是否有必要追求100%覆蓋率的單元測試

經過這一個學期的實踐,我覺得我找到了答案,測試是必需的,但100%覆蓋率的單元測試既不必要,不也現實。

在這個學期的項目中,我們的產品從前端到後端涉及到了瀏覽器、服務器、Docker、文件服務器、磁盤文件系統。其中,很多功能都是需要多個組件協同完成的,而單獨處於一個組件內部的單元測試常常無法兼顧整體,例如,在服務器系統內就很難監控到Docker的運行狀態,相應的單元測試也就很難開展。因為不存在一個組件可以訪問和控制到整個系統的每個組件,如果真的存在這樣的組件的話,那說明系統的設計也是不好的,沒有很好地實現系統層次之間的隔離,整個軟件的耦合度比較高。

但是,這是不是意味着我們可以放棄對單元測試的要求而為偷懶找借口了呢?不是的。

首先,單元測試依然起着十分重要的作用,拿建築樓房為例子,單元測試的作用就是保證每個磚塊、每根鋼筋的質量,雖然它很難保證整個樓房的藍圖設計是正確無誤的,但是作為第一層保障,它可以有效地保證我們的最低層組件工作正常。

以我們的項目為例,在後端服務器實現中,會用到很多的工具類,這些類之間的耦合度很低,各自完成相關的一系列功能,為上層提供服務。單元測試在這裏就可以發揮很大的作用,對每個工具類的每個方法進行全面的測試,可以為將來進一步的開發排除很多潛在的隱患。

而除此之外,我還認識到了測試不僅僅是單元測試這麼簡單,測試是一門學問,相應的也有諸多經典的測試方法,例如,在我們的項目開發後期,常常採用錄製腳本的方式進行測試,通過瀏覽器錄製一系列操作形成腳本,這個腳本可以重放,從而在軟件開發過程中可以隨時回歸測試,保證之前腳本中包含的功能運行正常。

所以,總結來說,測試十分重要,但100%的單元測試往往不切實際,但在單元測試無法覆蓋的地方,必須要有其他的測試手段進行彌補,要保證軟件的每個環節都有相應的測試作為保障,才能在接下來的開發中保持軟件的高質量。

關於第四章中提到的“結對編程”

在學期初提出的問題是

結對編程的開發方式開起來很美好,但是在實際團隊開發中真的有廣泛使用嗎

經過本學期的結對編程實踐,我依然對當初提出的問題持保留意見,也尚不能完全認同結對編程中的所有優點。

在書籍中介紹到結對編程有如下幾個優點

  • 可以起到教學作用,技術高的程序員可以幫助技術較弱的程序員進步
  • 可以提高代碼質量,因為代碼的每個部分的質量都取決於一對程序員中在該方面技術較高的一個
  • 可以提高團隊凝聚力,促進團隊交流,利於團隊管理
  • 可以有效應對團隊人員變動

針對這幾點,我也想談談我在實踐過接對編程后的理解和困惑。

  • 可以起到教學作用,技術高的程序員可以幫助技術較弱的程序員進步

關於這個優點我完全認同,在接對編程實踐中,我從搭檔身上學到了不少東西,不論是編程技巧還是設計藝術,同時,我有時也能夠為他提供一些幫助和想法,應該是完全起到了相互促進的作用。

但是,在這個優點背後有一個問題值得思考,也是我所困惑的。這樣的時間成本是否較高,一方學到東西的代價是另一方需要停下開發的腳步,而且,並非每個人都有成為老師的潛質,有的人技術高超但是表達能力不強,讓他們教授別人技術或許不如讓他人查閱相關資料來的效率高。同時,編程和思維都是有節奏和狀態的,打斷編程者的連續輸出其實對於編程人員來說是一件效率很低的事情,這樣看來,這個教學作用的成本是否較高。

  • 可以提高代碼質量,因為代碼的每個部分的質量都取決於一對程序員中在該方面技術較高的一個

這個優點我也完全認同,但是,在我實踐過程中的體會就是,達到這個最優往往會經歷一番周轉。

當雙方在某個設計點上意見不一致時,需要停下進行分析,這本身沒有問題,尤其是在雙方技術水平相差較大時,一方會主導話題,從而使得問題的討論和解決較快。而當雙方技術水平相當時,問題就可能出現,可能雙方各有不錯的設計,但這兩個設計相去甚遠,說服任意一方接受理解另一方的設計都是比較困難的事情。其本質就是默契問題,是否雙方有很高的默契度,編程和設計習慣上風格一致,這些都影響着結對編程的效果和實際性。倘若雙方無法保持高度默契,那麼有時時間就會被浪費在類似上面提到的場景上。

  • 可以提高團隊凝聚力,促進團隊交流,利於團隊管理

這一點我完全認同,也認為十分實際,當下,很多公司也有技術茶話會這樣的活動,目的也是為了可以一邊交流技術、提高團隊水平,一邊也可以提高團隊的凝聚力、促進團隊交流。

  • 可以有效應對團隊人員變動

確實有這方面的意義,但是我個人感覺這依然沒有解決本質問題,這樣的解決辦法下,風險依然是在人員本身上,只不過將一個人變成了兩個人而已。

而我認為更好的解決辦法可以是完善相關的內部文檔,每個人負責各自工作範圍內的技術文檔維護,這樣可以有效地規避掉人員變動的風險。

這一點在這學期的強制轉會中深有體會,據我了解,有的團隊就將項目開荒初期的學習和技術文檔維護了下來,從而使得轉會新來的成員可以快速上手項目,團隊的開發進度不會受到很大的影響。

關於第十六章中提到的“要成為領域的專家,才能創新”

在書中,作者的觀點是這樣的

這個想法看起來沒什麼錯,我們不就是為了成為某個領域的專家,才來上學,拿學位,希望拿到學位之後成為專家,然後再開始這個領域的創新?但是統計數據表明,70%的創新者說,他們最成功的創新,是在他們的拿手領域之外發現的。

之後作者舉出了HTTP的誕生阿里巴巴的誕生等例子,佐證上面的觀點。

經過這學期的實踐,我對這個觀點有了一定的理解,也有了一些自己的看法。

在這學期,我們是自選項目,也算是做了一些創新性的設計實現,但是這背後是經過了一定的調研和學習才得來的。雖然不能說經過調研我們就成為了領域的專家,但是至少對領域有了一定的了解和認知,知道哪些是實現了的,哪些是空白的,哪些東西因為沒人想到所以沒人做,哪些東西因為難度太大所以沒人做。

當然,作者的意思不是說對某個領域聞所未聞就企圖在其中有所創新,而是說創新的領域不一定是自己最拿手的領域。這一點,經過這學期的實踐,我有了全新的理解。

創新和實現不同,創新更關注的是要站在一個應用者和設計者的角度去思考,而不是實現者或者架構師的角度,它更多關注的是需要什麼而不是如何實現。當然,這兩者都十分重要,單純有想法但無法實現也無濟於事。但是,這背後正是作者想要表達的意思,不一定每個人都有實現某個東西的能力,但是每個人一定都有想到、想出某個東西的能力。

那我們的項目為例,我們發現在初學編程時,環境的配置很麻煩,IDE的安裝很麻煩,所以我們想解決這個問題,於是我們提出了自己的WEB版IDE,對這方面的需求提供了一定的支持。這個創意源自於我們的真實需求,同樣,那些偉大的創意,也往往來自於真實的需求。這正是作者想要表達和闡述的。

關於第十七章中提到的“磨合階段”

經過這學期的實踐,我發現沒有磨合階段的團隊和無法磨合的團隊都很少,以我們的團隊為例,大家在最開始雖然意見不統一,但是經過一段不長的時間的調整和交流,很快大家在認識上就可以達成一致。

我認為,除了一些極端人員難以融入團隊,可能會成為團隊的害群之馬以外,大部分時候,團隊都是可以磨合和愉快合作的。

而在學期開始時,我提出了如下問題

如何判斷一個團隊是處於“磨合階段”還是說這個團隊的人員配置本身真的存在問題呢

針對這一點,結合我的實踐體會,我認為,如果一個團隊能夠明確地完成分工,並且每個人都能夠清楚自己的職責和任務,那麼這個團隊就可以繼續合作下去。即使最開始存在團隊成員的進度不能很好地達標的情況,但也依然可以認為團隊的人員構成本身沒有問題,是可以合作的。

因為如果每個成員都清楚自己的任務和職責,那麼這至少說明了大家在工作和認識上達成了一致,在這個一致達成的基礎上開展後續的合作都是有可能的。而倘若成員之間連分工和職責分配都無法明確,則要麼是團隊管理出了問題,PM沒有很好地協調成員,要麼就是團隊成員無法達成一致,整個團隊內對任務和目標沒有一個清晰的認識和把握。

所以,我的理解是,團隊成員之間能否對團隊任務和目標有一個統一的認識和把握是可以作為評判團隊人員配置是否合理的一個重要標準。

二、新的問題

實踐出真知,經過一個學期的實踐后,再回顧最初提出的問題,確實顯得有些稚嫩和缺乏實踐了。

不過在實踐過程中,我也產生了一些新的問題,下面提出來和大家共同探討。

如何對抗歷史代碼遺忘問題

這個項目總共歷時2個月,從最初的搭建,到後來項目功能越來越多,魯棒性越來越強,這其中都是需要進行代碼的修改和添加的。

然而,在項目後期常常會出現一個情況,就是幾周前的代碼在幾周后再次閱讀時不能很快地回憶出其中的實現細節。

這裏並不是想表達代碼的可讀性較差,即使是在充分利用面向對象編程和函數式編程的優勢的情況下,回顧以往的代碼依然要耗費一定的時間去閱讀。

特別是在系統的狀態較多較複雜的情況下,這種問題尤為明顯,需要花費比較多的時間理清楚系統的狀態遷移。

我認為,完備的設計文檔和代碼註釋會有幫助,同時,設計多個小型專用系統來替代單一的多功能大型系統也會有所幫助。

但是我並無法滿足於上述兩種可能的解決方案,同時,因為問題暴露較晚,所以我也沒有機會去實踐檢驗上述辦法是否真的有效。

所以在這裏提出這個問題,希望能夠得到幫助。

軟件功能和軟件安全性的矛盾

網絡安全是一個很大的領域,而WEB應用依賴於網絡,自然WEB安全也是一個很大的話題。

在項目初期,我們花費了不少時間在安全機制的設計上,甚至對於安全機制的考量一度影響到了我們正常功能與核心功能的開發進度。

我們每個人都承認,在軟件領域,軟件的安全性無論對於用戶還是開發者都是十分重要的,它關乎雙方的利益。但是,在能力有限,或是缺乏相應的專業技術人員的情況下,過多的安全設計考慮常常會影響到功能的開發。

所以,我很困惑應該將安全機制設計放在軟件開發的哪個階段。

倘若在最初軟件設計時就將大部分安全機制考慮到並設計在最初架構中,那這樣肯定會影響到軟件的開發進度,特別是在缺乏專業技術人員的情況下。

而若不在最初設計時將安全機制考慮在內,而寄希望於在後期逐漸添加安全機制,那麼很可能出現一種情況,就是為了添加安全機制,軟件架構需要一些變動,這有時甚至會破壞單元測試的可用性,因為更高的安全性背後往往是更低的便利性,可能會有一些原本可以正常工作的單元測試不能在新的安全機制下運行,這就又給回歸測試帶來的困難,進而迫使軟件開發進入了一種比較危險的狀態。

所以,我很想知道,在有限的條件下,應該如何平衡安全機制設計和功能開發。

三、實踐知識點回顧

需求階段

在需求階段,我學到的知識點是

需求調研不僅要保證提出的需求是真需求,同時也要保證我們的產品有優於同類產品的地方

我們的項目是WEB版的IDE,其實,這個領域的同類產品還是有不少的,但是我們在需求調研時提出了我們獨特的地方,即面向新手

我們提出的需求是,許多新手初學編程時會被諸如環境配置、IDE配置等一系列配置工作阻礙,而我們的目標就是為他們消除阻礙,能夠提供一個開箱即用的編程環境。

那麼,我們提出的需求是真需求嗎?是的。

據調查,很多大一新生在編程學習的前半個學期都會對開發環境有着或多或少的困惑和不解。然而理解這背後的一系列內容又本身超出了他們現有的能力範圍,那麼,我們產品的使用人群和使用場景也就應運而生了。

而我們的產品是否有優於同類產品的地方呢?是的。

根據調研,市面上大多數的WEB版IDE的功能都十分強大,基本涵蓋了非WEB版IDE的絕大部分功能。但同非WEB版的IDE類似,這些WEB版的IDE依然使用難度較高,需要一定的經驗,也需要一定的配置,並不能做的開箱即用,而這就是我們產品的優勢。

設計階段

在設計階段,我學到的知識點是

有效地分隔任務為若干個子任務會有利於設計的進展

在我們項目最初的設計階段,我們就將項目進行了分隔,粗略分為了前端、編輯器、後端這三個部分,而這三個部分又各自被分隔為若干個更小的部分,然後針對每個部分的功能需求去單獨設計。這樣,一方面有利於強化對於項目的整體把握,另一方面也有利於控制軟件的複雜度,可以使得每個小部分都得到較優的設計和實現。

實現階段

在實現階段,我學到的知識點是

團隊開發中的每日例會十分重要,有利於每個成員把握整體的開發進度

在alpha和beta階段都有14天的scrum階段,其中每天都要舉行例會,在實現階段的每日例會是十分重要的。

一方面,通過每日例會,每個成員都可以比較清晰地把握團隊整體的開發進展,進而便於規劃自己未來幾天的任務。

另一方面,也可以起到監督和督促的作用,在每日例會上,大家都會彙報自己的工作進展,這在無形中就起到了督促作用。

此外,每日例會也能夠起到活躍團隊氣氛、促進團隊團結的效果,每日例會不僅是彙報工作的地方,也是團隊成員交流的機會。

測試

在測試階段,我學到的知識點是

要常常回歸測試,不要等到最後統一測試,那樣往往費力不討好

在alpha階段,我們的測試基本上是在發布前統一進行的,在開發過程中的測試較少,所以最後發布前的測試工作十分緊張。

統一測試的壞處在於,一方面,統一測試的工作量很大,面對一個初有體積的項目,要進行覆蓋度較高的測試是十分耗時耗力的工作。另一方面,在最後統一測試的修復成本較高,在軟件開發階段發現並修正錯誤往往是比較容易的,但是當軟件完成了整合,再進行測試並修正錯誤,那樣的修復成本往往較高,因為在軟件整合完成之後發現的BUG有可能是整合導致的,也有可能是某個組件自身帶來的,這樣不僅問題定位困難,而且修復時常常會涉及到多個組件,牽一發而動全身。

發布

在發布階段,我學到的知識點是

推廣十分重要,優秀的推廣能夠助力讓產品最終擁有大量的用戶

在alpha階段的發布環節,我們團隊並沒有十分重視產品的推廣,因而導致在alpha階段最終用戶數量不多,相應的,收到的用戶反饋也就較少,為beta階段的展開帶來了一定的困難。

而在beta階段,我們及早進行了發布和推廣,有力地吸引了一批有效用戶,他們為我們的項目提出了寶貴的意見和建議,從長遠來看,這將十分有助於我們產品的進一步發展和更新。

維護

在維護階段,我學到的知識點是

要做好系統數據收集工作,在維護階段要密切關注系統數據記錄,及時發現系統可能存在的問題

在alpha階段,我們的後端系統並沒有設計太多的日誌系統,用戶的操作基本都沒有被有效記錄下來,導致維護時出現了問題很難定位。

在beta階段,我們針對後端系統的設計強化了系統日誌方面的實現,記錄了所有數據庫查詢操作、API訪問操作等諸如此類操作的記錄,便於在維護時定位錯誤和排查隱患。

四、理解與心得

無論是個人項目、結對項目還是團隊項目,都需要有一個思路清晰的領導者(管理者)來把握整體的前進方向。

在個人項目中,自己是那個管理者,在結對項目中,兩人都是管理者,而在團隊項目中,PM是主導的管理者,每個人也都參与其中。

為什麼說這個管理者十分重要,因為在多人完成一項任務時,思路統一是很重要的一件事情。每個人都有自己的主意,那樣是無法擰成一股繩來合作的,需要有人來管理和協調,讓大家的想法達成一致,才能使得團隊高效地合作。

同時,管理團隊和管理軟件開發周期也是一門學問。

管理團隊涉及到協調大家不同的意見,盡量不偏不坦,保證每個人的個性的同時又要保證團隊的統一。要能夠充分發揮每個人的特點,盡量滿足每個人的愛好和想法,這本身就是一項十分有挑戰的事情。

而管理軟件開發周期更甚,軟件開發涉及到多個環節,每個環節都有每個環節的任務和特點,在每個階段都指定明確的目標對於按期完成軟件開發而言有十分重要的意義。

同時,軟件開發不僅是技術的挑戰,也是設計的挑戰。

高超的技術可以幫助程序員實現功能,但是並不能幫助程序員設計出優秀的產品。軟件開發往往細節之處見真功夫,這種功夫不一定是實現難度有多高,往往是設計思想上的巧妙。優秀的設計可以讓產品更加易用,更加具有粘性,讓用戶更加依賴於產品。

這一點我在我們的項目中深有體會。我們的IDE主打易用,所以在很多地方的設計上都是精雕細琢,如功能的布局、UI的設計、項目的入口等等,都力求讓用戶能夠快速上手,長期使用。

此外,我也有一些想進行反思的地方。

首先是和大家的交流方式上,我覺得我一直存在一定的問題,同時,這也是團隊合作中十分重要的地方。團隊合作,大家不僅僅只是簡單的在一起做個東西,人際層面的往來對團隊的建設也十分重要,良好的交流方式有利於提高團隊的凝聚力,營造良好的團隊氛圍。在這一點上,我覺得我做的還不夠,有時會將個人情緒遷怒到他人,也是感謝大家對我的包容吧,能夠讓團隊的合作一直很愉快。

還有就是缺乏思考,尤其是設計上的思考。好的軟件開發人員會設計優秀的接口和服務,讓使用者一看就能覺出這是大家之作,方便易用的同時功能全面。這一點上我覺得我做的還不夠,很多時候都是功能有了就可以了,而不再進一步考慮如何優化接口,優化API設計,讓調用者更加方便地使用接口與服務,這一點在未來的軟件開發設計上也是需要提高的。

總結起來說,這一學期的軟工實踐體驗是很充實的。從單人項目到結對項目再到最終的團隊項目,實踐了不同模式下的開發過程,也最終取得了一個小有規模的產品,無論是過程還是結果都值得欣慰。同時,通過一系列的實踐,我也深刻體會到了團隊大型軟件開發的難度和痛點,也為將來的進一步學習和發展奠定了基礎、明確了方向,從這些角度上講,都是十分有益的。希望這個學期的實踐可以成為未來軟件開發生涯的一個好的開端。

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

【其他文章推薦】

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

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

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

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

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

SpringBoot整合Hibernate Validator實現參數驗證功能

  在前後端分離的開發模式中,後端對前端傳入的參數的校驗成了必不可少的一個環節。但是在多參數的情況下,在controller層加上參數驗證,會顯得特別臃腫,並且會有許多的重複代碼。這裏可以引用Hibernate Validator來解決這個問題,直接在實體類進行參數校驗,驗證失敗直接返回錯誤信息給前端,減少controller層的代碼量。

一、pom引入Hibernate Validator

<!-- 驗證器 -->
<dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.1.5.Final</version>
</dependency>

 二、通過註解在實體類進行參數校驗

@Data
public class UserModel {

    @NotNull(message = "用戶名稱不能為空!")
    private String userName;

    @NotNull(message = "age不能為null!")
    @Range(min = 1, max = 888, message = "範圍為1至888")
    private Integer age;

    /**
     * 日期格式化轉換
     */
    @NotNull(message = "日期不能為null!")
    private Date date;
}

這裏用到的參數校驗的註解有@NotNull和@Range,message是到時候我們返回給前端的信息,註解的具體意思如下:

@Null  被註釋的元素必須為null
@NotNull  被註釋的元素不能為null
@AssertTrue  被註釋的元素必須為true
@AssertFalse  被註釋的元素必須為false
@Min(value)  被註釋的元素必須是一個数字,其值必須大於等於指定的最小值
@Max(value)  被註釋的元素必須是一個数字,其值必須小於等於指定的最大值
@DecimalMin(value)  被註釋的元素必須是一個数字,其值必須大於等於指定的最小值
@DecimalMax(value)  被註釋的元素必須是一個数字,其值必須小於等於指定的最大值
@Size(max,min)  被註釋的元素的大小必須在指定的範圍內。
@Digits(integer,fraction)  被註釋的元素必須是一個数字,其值必須在可接受的範圍內
@Past  被註釋的元素必須是一個過去的日期
@Future  被註釋的元素必須是一個將來的日期
@Pattern(value) 被註釋的元素必須符合指定的正則表達式。
@Email 被註釋的元素必須是电子郵件地址
@Length 被註釋的字符串的大小必須在指定的範圍內
@NotEmpty  被註釋的字符串必須非空
@Range  被註釋的元素必須在合適的範圍內

 三、controller層的方法加上@Valid註解

@PostMapping("/testPost")
public Object testPost(@RequestBody @Valid UserModel userModel, BindingResult result){
if(result.hasErrors()){
for(ObjectError error:result.getAllErrors()){
return error.getDefaultMessage();
}
}
return userModel;
}

controller層這裏只需要在實體類的前面加上@Valid註解,這個註解可以實現數據的驗證。這裏BindingResult是存儲了校驗時的錯誤信息,驗證有誤時將錯誤信息返回給前端。這裏不使用BindingResult的時候,控制台會報MethodArgumentNotValidException,這裏可以通過自定義異常類來捕捉它,然後去掉BindingResult,以及難看的if判斷。

四、自定義異常類捕捉MethodArgumentNotValidException

@RestControllerAdvice
public class GlobalExceptionAdvice {

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public JsonData validException(MethodArgumentNotValidException e) {
        //驗證post請求的參數合法性
        MethodArgumentNotValidException notValidException = e;
        String msg = notValidException.getBindingResult().getFieldError().getDefaultMessage();
        return JsonData.buildError(msg);
    }
}

使用PostMan的測試結果如下:

具體的代碼可以在我的gitee上面查看,springboot_validator

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

【其他文章推薦】

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

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

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

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

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

gulp壓縮html,css,js文件流程、監聽任務、使用gulp創建服務器、同時運行多個任務、反向代理

一、初始化

首先先做一個項目初始化,用來記錄你項目中用到的工具

再你項目文件下打開一個控制台,輸入命令 yarn init -y 進行初始化

 

輸入命令yarn add gulp -g  — 全局安裝gulp,這裏我提前已經安裝過了就不演示了,然後再輸入命令yarn add gulp -S 局部安裝,都安裝完成過後輸入命令 gulp -v,如果出現兩個版本號,就代表都安裝成功了

 

接着在你的項目文件夾下新建一個文件名為 gulpFile.js js文件,名字必須叫這個,官方規定的,用來寫gulp命令

 

好了,可以開始安裝壓縮工具進行壓縮了

 

 

 二、html壓縮

 

 安裝html壓縮工具,輸入命令 

yarn add gulp-htmlmin -D

安裝壓縮html的工具,安裝到開發環境,生產環境用不到

安裝完成過後打開初始化時生成的文件 package.json,開發環境有沒有你剛安裝的 gulp-htmlmin

 

 

 

 

 

 

 打開開始建的 gulpFile.js 文件,開始寫命令

const gulp = require('gulp') //引入gulp
const htmlmin = require('gulp-htmlmin') //引入html壓縮模塊
const path = { //方便管理路徑
    html: {
        src: 'src/**/*.html',
        dest: 'dist'
    }
}
gulp.task('html', () => { //創建任務,並命名任務名
    /*一個*表示所有文件,兩個*表示所有目錄*/
    return gulp.src(path.html.src) //打開讀取文件
        .pipe(htmlmin({
            removeComments: true, //清除HTML註釋
            collapseWhitespace: true, //壓縮HTML
            collapseBooleanAttributes: true, //省略布爾屬性的值 <input checked="true"/> ==> <input checked />
            removeEmptyAttributes: true, //刪除所有空格作屬性值 <input id="" /> ==> <input />
            removeScriptTypeAttributes: false, //刪除<script>的type="text/javascript"
            removeStyleLinkTypeAttributes: true, //刪除<style>和<link>的type="text/css"
            minifyJS: true, //壓縮頁面JS
            minifyCSS: true //壓縮頁面CSS
        })) //管道流操作,壓縮文件
        .pipe(gulp.dest(path.html.dest)) //指定壓縮文件放置的目錄
})

然後輸入命令

gulp html

執行壓縮

 

 

 像這樣就壓縮成功了

上面是 gulp3 寫法,gulp4 寫法:

const gulp = require('gulp') //引入gulp
const htmlmin = require('gulp-htmlmin') //引入html壓縮模塊
const path = { //方便管理路徑
    html: {
        src: 'src/**/*.html',
        dest: 'dist'
    }
}
const html = () => { //創建任務,並命名任務名
    /*一個*表示所有文件,兩個*表示所有目錄*/
    return gulp.src(path.html.src) //打開讀取文件
        .pipe(htmlmin({
            removeComments: true, //清除HTML註釋
            collapseWhitespace: true, //壓縮HTML
            collapseBooleanAttributes: true, //省略布爾屬性的值 <input checked="true"/> ==> <input checked />
            removeEmptyAttributes: true, //刪除所有空格作屬性值 <input id="" /> ==> <input />
            removeScriptTypeAttributes: false, //刪除<script>的type="text/javascript"
            removeStyleLinkTypeAttributes: true, //刪除<style>和<link>的type="text/css"
            minifyJS: true, //壓縮頁面JS
            minifyCSS: true //壓縮頁面CSS
        })) //管道流操作,壓縮文件
        .pipe(gulp.dest(path.html.dest)) //指定壓縮文件放置的目錄
}

module.exports = { //一定要以對象形式導出
    html
}

三、css壓縮

安裝css壓縮模塊,輸入命令

yarn add gulp-clean-css -D

 

 

 然後也在gulpFile.js文件里寫壓縮css的命令

const gulp = require('gulp') //引入gulp
const htmlmin = require('gulp-htmlmin') //引入html壓縮模塊
const cleanCss = require('gulp-clean-css') //引入css壓縮模塊
const path = { //方便管理路徑
    /*一個*表示所有文件,兩個*表示所有目錄*/
    html: {
        src: 'src/**/*.html',
        dest: 'dist'
    },
    css: {
        src: 'src/**/*.css',
        dest: 'dist'
    }
}

gulp.task('css', () => {
    return gulp.src(path.css.src)
        .pipe(cleanCss())
        .pipe(gulp.dest(path.css.dest))
})

輸入命令 gulp css 命令執行

 

 

 另外css還有一個很好用的模塊,它可以自動給需要兼容的css屬性加前綴,輸入命令安裝它

yarn add gulp-autoprefixer -D

安裝好了,引入模塊,調用即可

四、js壓縮

安裝js es6語法轉es5語法模塊,壓縮js模塊,輸入命令

yarn add -D gulp-babel @babel/core @babel/preset-env //es6語法轉es5
yarn add -D gulp-uglify //壓縮js

 

 

 同樣的打開 gulpFile.js 文件寫壓縮js的命令

const gulp = require('gulp') //引入gulp
const htmlmin = require('gulp-htmlmin') //引入html壓縮模塊
const cleanCss = require('gulp-clean-css') //引入css壓縮模塊
const autoprefixer = require('gulp-autoprefixer') //引入加前綴模塊
const babel = require('gulp-babel'), //引入es6轉es5模塊
    uglify = require('gulp-uglify') //引入js壓縮模塊
const path = { //方便管理路徑
    /*一個*表示所有文件,兩個*表示所有目錄*/
    html: {
        src: 'src/**/*.html',
        dest: 'dist'
    },
    css: {
        src: 'src/**/*.css',
        dest: 'dist'
    },
    js: {
        src: 'src/**/*.js',
        dest: 'dist'
    }
}
gulp.task('js', () => {
    gulp.src(path.js.src)
        .pipe(babel({
            presets: ['@babel/env'] //es6轉es5
        }))
        .pipe(uglify()) //執行壓縮
        .pipe(gulp.dest(path.js.dest))
})

輸入命令 gulp js 運行

五、監聽任務

監聽任務需要使用gulp4的寫法

const gulp = require('gulp') //引入gulp
const htmlmin = require('gulp-htmlmin') //引入html壓縮模塊
const cleanCss = require('gulp-clean-css') //引入css壓縮模塊
const autoprefixer = require('gulp-autoprefixer') //引入加前綴模塊
const babel = require('gulp-babel'), //引入es6轉es5模塊
    uglify = require('gulp-uglify') //引入js壓縮模塊
const path = { //方便管理路徑
    /*一個*表示所有文件,兩個*表示所有目錄*/
    html: {
        src: 'src/**/*.html',
        dest: 'dist'
    },
    css: {
        src: 'src/**/*.css',
        dest: 'dist'
    },
    js: {
        src: 'src/**/*.js',
        dest: 'dist'
    }
}



const css = () => {
    return gulp.src(path.css.src)
        .pipe(autoprefixer())
        .pipe(cleanCss())
        .pipe(gulp.dest(path.css.dest))
}
const js = () => {
    return gulp.src(path.js.src)
        .pipe(babel({
            presets: ['@babel/env'] //es6轉es5
        }))
        .pipe(uglify()) //執行壓縮
        .pipe(gulp.dest(path.js.dest))
}

const html = () => { //創建任務,並命名任務名
    return gulp.src(path.html.src) //打開讀取文件
        .pipe(htmlmin({
            removeComments: true, //清除HTML註釋
            collapseWhitespace: true, //壓縮HTML
            collapseBooleanAttributes: true, //省略布爾屬性的值 <input checked="true"/> ==> <input checked />
            removeEmptyAttributes: true, //刪除所有空格作屬性值 <input id="" /> ==> <input />
            removeScriptTypeAttributes: false, //刪除<script>的type="text/javascript"
            removeStyleLinkTypeAttributes: true, //刪除<style>和<link>的type="text/css"
            minifyJS: true, //壓縮頁面JS
            minifyCSS: true //壓縮頁面CSS
        })) //管道流操作,壓縮文件
        .pipe(gulp.dest(path.html.dest)) //指定壓縮文件放置的目錄
}
const watch = () => { //監聽文件,文件改變執行對應的任務
    gulp.watch(path.html.src, html)
    gulp.watch(path.css.src, css)
    gulp.watch(path.js.src, js)
}

module.exports = {
    html,
    js,
    css,
    watch
}

輸入命令 gulp watch 即可實現監聽

六、gulp創建服務器

輸入命令

yarn add gulp-connect -D

引入模塊

const connect = require('gulp-connect')

創建服務器

const server = () => {
    connect.server({ //創建服務器
        root: 'dist',//根目錄
        port: '2000',//端口號
        livereload:true//服務器熱更新
    })
}

導出模塊

module.exports = {
    html,
    js,
    css,
    watch,
    server
}

輸入命令 gulp server 就可以運行了

如果想直接打開首頁,可以輸入命令安裝open模塊

yarn add open -S

然後再任何位置寫入你想打開的網址

open('http://127.0.0.1:2000')

還有一個模塊也可以創建服務器

輸入命令安裝

yarn add gulp-webServer -D

 

 引入模塊

const    webserver = require('gulp-webserver')

創建服務器

const createServer = () => {
    return gulp.src('./dist')
        .pipe(webserver({ //創建服務器
            port:'3000', //端口號
            open:'/html', //默認打開路徑
            livereload:true //熱更新
        }))
}

七、同時運行多個任務

// 默認任務:default 我們可以把所有任務都放進default
// series 同步執行,先執行刪除dist任務,再執行其他任務
// parallel 異步執行(并行),不會互相影響的任務可以并行
module.exports.default = gulp.series(gulp.parallel(html,js,css,watch,server))

運行只需要寫 gulp 命令

如果想頁面實時更新的話,再想實時更新的任務後面加上

.pipe(connect.reload())

然後重啟服務器就ok了

八、反向代理

輸入命令

yarn add http-proxy-middleware -D

 

 引入模塊

const proxy = require('http-proxy-middleware')

創建反向代理

connect 創建的服務器要用函數創建代理

const server = () => {
    connect.server({ //創建服務器
        root: 'dist', //根目錄
        port: '2000', //端口號
        livereload: true, //服務器熱更新
        middleware: () => {
            return [
                proxy.createProxyMiddleware('/api', { //創建反向代理,請求已 /api 開頭就使用target的服務器
                    target: 'http://localhost',//需要代理的服務器
                    changeOrigin: true
                })
            ]
        }

    })
}

 webserver創建的服務器要用數組創建代理

const createServer = () => {
    return gulp.src('./dist')
        .pipe(webserver({ //創建服務器
            port: '3000', //端口號
            open: '/html', //默認打開路徑
            livereload: true, //熱更新
            middleware: [
                proxy.createProxyMiddleware('/api', { //創建反向代理,請求已 /api 開頭就使用target的服務器
                    target: 'http://localhost',
                    changeOrigin: true
                })
            ]
        }))
}

 

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

【其他文章推薦】

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

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

※超省錢租車方案

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

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

專家駐點「能源檢查站」 一年服務10萬人 省電30億度

環境資訊中心記者 陳文姿報導

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

【其他文章推薦】

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

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

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

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

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

東協化學品法規因應策略與近況更新

轉載自2018年11月12日國際化學品政策宣導網

自台灣新南向政策上路以來,對於東協的投資持續增加,根據經濟部國貿局近5年(至2016年)的資料顯示,我國對新加坡的投資占比最高(47%),其次為越南(32%)。

根據2017年的財政部統計資料,東協為台灣化學品及塑膠與橡膠相關製品世界出口第二大市場,而化學品管理為國際各產業貿易中須關注的重要的法規,今年10月22日經濟部工業局主辦之「東協化學品管理因應策略宣導會」,特別邀請到新加坡化學工業產業協會(Singapore Chemical Industry Council Limited,SCIC)兩位資深業界講師,針對新加坡及東協國家化學品管理法規的進展及化學品全球調和制度(GHS)之管理機制進行說明。

新加坡以生命週期觀念建立化學管理框架

講師分享新加坡化學管理框架,主要由各主管機關分別對管轄範圍內危險化學品進行管理,包含化學品生命週期的不同階段,針對產品初期發展、製造、運輸、儲存、販賣、使用、以及最後廢棄的生命週期進行管理。

例如進口時,儲存和運輸皆須進行申報及許可申請,且連結海關的進口資料作必要的管控和追蹤。而針對危害性化學品,新加坡民防部隊即要求在進口、儲存、運輸以及建造用途時申請執照。而新加坡國家環境局(National Environment Agency)也要求購買危害性化學品時須申請許可,並進行正確的標示。

另外為符合水俣公约的要求,新加坡在2020年起也將禁止特定含水銀產品的製造、輸入及出口,例如電池、化妝品、節能燈泡和某些醫​​療設備等。

新加坡GHS制度落實與業界合作 在GHS制度落實方面,講師除了說明新加坡對於GHS標示的要求,也提到當廠場現場中完整的GHS標示在實務上不可行時,應將標示資訊簡化,降低過多複雜的資訊展示,但此規定並不適用需要運送到其他廠場時的標示。

另外在出口方面,進口後再重新出口、以及儲存將出口的國內製造之危害性化學品時,都依相關規定進行標示,並符合出口目的國家之法規要求。其中更令人驚豔的是講師分享之業界與新加坡政府於法規制訂時之技術合作,彼此透過密集的諮詢與業界經驗分享,取得法規與經濟發展之平衡之作法,亦是台灣可積極參考之作法。

其他東協國家管理規範持續發展

講師也針對其他東協國家化學品管理規範最新進度進行介紹,摘要如下:泰國正在建立第一份既有化學物質清單,預計會於2020年公布; 越南於2017年11月已正式實施化學法法令,透過清單進行工業及前驅化學品的管理規範,目前也正在建立化學物質清單; 柬埔寨、寮國、緬甸目前仍著重於GHS的執行; 菲律賓則持續檢視預製造及預進口的新化學物質通報規範,以及其他管制清單; 馬來西亞與印尼目前持續評估及調整其化學品管理框架。

東協國家是我國進來貿易往來的重要區域,經濟部工業局提醒我國廠商應隨時掌握東協各國化學品管理法規的近況,採取因應法規需要的措施與行動,並及早準備未來法規發展所需的合規相關資料,確保出口貿易活動能符合當地的相關規範。  

參考資料

※ 轉載自

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

日本福島核事故:日本證實一名工人死於輻射

摘錄自2018年9月6日BBC中文網報導

日本首次公開證實,2011年福島核電站洩漏事故當中的一名工人,在事後因為核輻射而死亡。

該名50多歲的男子在2016年被診斷患有肺癌,他最終也是死於這種疾病。

日本政府此前曾經承認,福島核輻射導致四名工人患病,但這是日本第一次承認有人因此而死亡。

在聽取放射科專家及其他專業人士的意見之後,厚生勞動省認為該名工人的家屬應當獲得賠償。

雖然福島核災當時並沒有人直接死於核事故,但負責福島核設施運作的東京電力株式會社仍然面對多起賠償申訴。

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

【其他文章推薦】

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

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

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

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

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

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