分類
發燒車訊

系統化學習多線程(一)

大綱

————————-學前必讀———————————-

學習不能快速成功,但一定可以快速入門
整體課程思路:
1.實踐為主,理論化偏少
2.課程筆記有完整的案例和代碼,(為了學習效率)再開始之前我會簡單粗暴的介紹知識點案例思路,
有基礎的同學聽了之後可以直接結合筆記寫代碼,
如果沒聽懂再向下看視頻,我會手把手編寫代碼和演示測試結果;
3.重要提示,學編程和學游泳一樣,多實踐學習效率才高,理解才透徹;
4.編碼功底差的建議每個案例代碼寫三遍,至於為什麼…<<賣油翁>>…老祖宗的智慧

————————————————————————-

 1.線程

1.1.什麼是線程

線程(英語:thread)是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程并行執行不同的任務。在Unix System V及SunOS中也被稱為輕量進程(lightweight processes),但輕量進程更多指內核線程(kernel thread),而把用戶線程(user thread)稱為線程。(來自百度百科)

一個進程可以有很多線程,每條線程并行執行不同的任務。

1.2.多線程hello word

需求:模擬在計算上一邊聽歌一邊打遊戲

三種實現方案如下:

TestDemo

 1 package com.wfd360.thread;
 2 
 3 import com.wfd360.thread.demo01.GameRunnable;
 4 import com.wfd360.thread.demo01.MusicRunnable;
 5 import com.wfd360.thread.demo02.GameThread;
 6 import com.wfd360.thread.demo02.MusicThread;
 7 import org.junit.Test;
 8 
 9 /**
10  * @author 姿勢帝-博客園
11  * @address https://www.cnblogs.com/newAndHui/
12  * @WeChat 851298348
13  * @create 05/03 5:27
14  * @description 需求分析:
15  * 1.模擬一邊打遊戲一邊聽音樂,在控制台打印輸出模擬
16  * 2.把兩個業務封裝成獨立的線程,實現接口Runnable或繼承Thread,通過看源碼你會發現Thread類實現了接口Runnable,使用本質上這兩種方法時一樣的。
17  * 3.Thread類提供兩個方法,線程主題方法run,啟動線程方法start
18  */
19 public class TestDemo {
20     /**
21      * 方式1:實現接口Runnable
22      */
23     @Test
24     public void testRunnable() throws InterruptedException {
25         System.out.println("-------test start-------");
26         // 實例對象
27         MusicRunnable music = new MusicRunnable();
28         GameRunnable game = new GameRunnable();
29         // 創建線程
30         Thread musicThread = new Thread(music);
31         Thread gameThread = new Thread(game);
32         // 啟動線程
33         musicThread.start();
34         gameThread.start();
35         System.out.println("--------等待其他線程執行--------------");
36         Thread.sleep(5 * 1000);
37         System.out.println("-------test end-------");
38     }
39 
40     /**
41      * 方式2:繼承Thread
42      */
43     @Test
44     public void testThread() throws InterruptedException {
45         System.out.println("-------test start-------");
46         // 創建線程
47         MusicThread musicThread = new MusicThread();
48         GameThread gameThread = new GameThread();
49         // 啟動線程
50         musicThread.start();
51         gameThread.start();
52         System.out.println("--------等待其他線程執行--------------");
53         Thread.sleep(5 * 1000);
54         System.out.println("-------test end-------");
55     }
56 
57     /**
58      * 方式3:簡寫,這種寫法一般我們在做模擬測試的使用,在正式代碼中建議不使用,可讀性較差
59      */
60     @Test
61     public void testThreadSimple() throws InterruptedException {
62         System.out.println("-------test start-------");
63         // 創建線程
64         Thread musicThread = new Thread(() -> {
65             for (int i = 0; i < 100; i++) {
66                 System.out.println("=======聽音樂中============" + i);
67             }
68         });
69         Thread gameThread = new Thread(() -> {
70             for (int i = 0; i < 100; i++) {
71                 System.out.println("=======打遊戲中============" + i);
72             }
73         });
74         // 啟動線程
75         musicThread.start();
76         gameThread.start();
77         System.out.println("--------等待其他線程執行--------------");
78         Thread.sleep(5 * 1000);
79         System.out.println("-------test end-------");
80     }
81 }


 實現接口Runnable

 1 package com.wfd360.thread.demo01;
 2 
 3 /**
 4  * @author 姿勢帝-博客園
 5  * @address https://www.cnblogs.com/newAndHui/
 6  * @WeChat 851298348
 7  * @create 05/03 5:31
 8  * @description
 9  */
10 public class GameRunnable implements Runnable {
11     @Override
12     public void run() {
13         for (int i = 0; i < 100; i++) {
14             System.out.println("=======打遊戲中============" + i);
15         }
16     }
17 }

GameRunnable

 1 package com.wfd360.thread.demo01;
 2 
 3 /**
 4  * @author 姿勢帝-博客園
 5  * @address https://www.cnblogs.com/newAndHui/
 6  * @WeChat 851298348
 7  * @create 05/03 5:29
 8  * @description
 9  */
10 public class MusicRunnable implements Runnable {
11     @Override
12     public void run() {
13         for (int i = 0; i < 100; i++) {
14             System.out.println("=======聽音樂中============"+i);
15         }
16     }
17 }

MusicRunnable

 繼承Thread

 1 package com.wfd360.thread.demo02;
 2 
 3 /**
 4  * @author 姿勢帝-博客園
 5  * @address https://www.cnblogs.com/newAndHui/
 6  * @WeChat 851298348
 7  * @create 05/03 6:00
 8  * @description
 9  */
10 public class GameThread extends Thread {
11     @Override
12     public void run() {
13         for (int i = 0; i < 100; i++) {
14             System.out.println("-------遊戲中----------"+i);
15         }
16     }
17 }

GameThread GameThread

 1 package com.wfd360.thread.demo02;
 2 
 3 /**
 4  * @author 姿勢帝-博客園
 5  * @address https://www.cnblogs.com/newAndHui/
 6  * @WeChat 851298348
 7  * @create 05/03 6:00
 8  * @description
 9  */
10 public class MusicThread extends Thread {
11     @Override
12     public void run() {
13         for (int i = 0; i < 100; i++) {
14             System.out.println("-------音樂中----------" + i);
15         }
16     }
17 }


 總結

啟動線程兩種方式:

    1.通過繼承Thread類

    2.實現Runnable接口

 使用哪種方式更好?

區別: 

一個類如果繼承了其他類,就無法在繼承Thread類,在Java中,一個類只能繼承一個類,而一個類如果實現了一個接口,還可以實現其他接口,接口是可以多實現的,所以說

Runable的擴展性更強,但是繼承的方式更簡單,個人建議一般情況下使用Thread;

實現接口Runnable或繼承Thread,通過看源碼你會發現Thread類實現了接口Runnable,使用本質上這兩種方法是一樣的

啟動線程流程:

    創建啟動線程的方式一:繼承Thread類

       1.將業務方法封裝成線程對象,自定義類t extends Thread類; 

       2.覆寫run方法: 覆寫第一步中的run方法;

       3.創建自定義對象t

       4.啟動線程 t.start();

   創建啟動線程方式二:實現Runnable接口

      1.將業務方法封裝成線程對象,自定義類t implements Runnable接口;

      2.實現第一步中的run方法

      3.創建自定義對象t

      4.啟動線程 new Thread(t).start();

1.3.對主線程與創建線程執行順序的理解

問題:
直接寫一個簡單的HelloWorld 程序,有沒有線程?
==>有一個主線程,在垃圾回收的時候,有gc 線程。

 1 package com.wfd360.thread;
 2 
 3 import org.junit.Test;
 4 
 5 /**
 6  * @author 姿勢帝-博客園
 7  * @address https://www.cnblogs.com/newAndHui/
 8  * @WeChat 851298348
 9  * @create 05/04 11:09
10  * @description <p>
11  * 問題:
12  * 直接寫一個簡單的HelloWorld 程序,有沒有線程?
13  * ==>有一個主線程,在垃圾回收的時候,有gc 線程。
14  * 結論:一旦線程啟動起來之後就是獨立的,和創建環境沒有關係;
15  * 啟動線程不能直接調用run方法,必須調用start方法;
16  * </p>
17  */
18 public class TestDemo02 {
19     /**
20      * 如果把創建線程放在循環語句的 下 面,會交替出現嗎
21      * ==>否,因為主線程執行完成后才會啟動hello線程
22      *
23      * @throws Exception
24      */
25     @Test
26     public void test1() throws Exception {
27         System.out.println("---test start-------");
28         // 執行主線程
29         for (int i = 0; i < 100; i++) {
30             System.out.println("-----test1--------" + i);
31         }
32         // 啟動hello線程
33         new HelloThread().start();
34         System.out.println("=======等待執行完成===========");
35         Thread.sleep(5 * 1000);
36         System.out.println("---test end-------");
37     }
38 
39     /**
40      * 如果把創建線程放在循環語句的 上 面,會交替出現嗎
41      * ==>可能會,可能不會,可能出現for循環完之後,線程還沒有啟動完;
42      *
43      * @throws Exception
44      */
45     @Test
46     public void test2() throws Exception {
47         System.out.println("---test start-------");
48         // 啟動hello線程
49         new HelloThread().start();
50         // 執行主線程
51         for (int i = 0; i < 100; i++) {
52             System.out.println("-----test1--------" + i);
53         }
54         System.out.println("=======等待執行完成===========");
55         Thread.sleep(5 * 1000);
56         System.out.println("---test end-------");
57     }
58 
59     /**
60      * 採用內部類的方式定義一個hello線程對象
61      */
62     class HelloThread extends Thread {
63         @Override
64         public void run() {
65             for (int i = 0; i < 100; i++) {
66                 System.out.println("-----HelloThread--------" + i);
67             }
68         }
69     }
70 }

TestDemo02

結論:一旦線程啟動起來之後就是獨立的,和創建環境沒有關係;
啟動線程不能直接調用run方法,必須調用start方法;

 1.4.對sleep方法的理解

package com.wfd360.thread;

/**
 * @author 姿勢帝-博客園
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 05/04 11:34
 * @description <p>
 * Thread類的方法:
 * static void sleep(long millis) 在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行);
 * </p>
 */
public class TestSleep {
    /**
     * 做一個簡易倒計時,10秒鐘,控制台每一秒輸出一個数字,如10,9,8,7.....0
     */
    public static void main(String[] args) throws Exception {
        System.out.println("---test start-------");
        for (int i = 10; i >= 0; i--) {
            Thread.sleep(1 * 1000);
            System.out.println(i);
        }
        System.out.println("---test end-------");
    }
}

1.5.線程名稱的設置與獲取

繼承方式

簡單需求:使用多線程模擬多窗口售票

 1 package com.wfd360.thread.demo03Ticket;
 2 
 3 /**
 4  * @author 姿勢帝-博客園
 5  * @address https://www.cnblogs.com/newAndHui/
 6  * @WeChat 851298348
 7  * @create 05/04 11:55
 8  * @description <p>
 9  * 模擬多線程售票
10  * </p>
11  */
12 public class TicketThread extends Thread {
13     // 假定票總是100張
14     private static Integer num = 100;
15 
16     @Override
17     public void run() {
18         // 只要有票就一直售票
19         while (num > 0) {
20             System.out.println("正在出售第" + num + "張票");
21             --num;
22         }
23         System.out.println("===售票結束===");
24     }
25 }

TicketThread

test

/**
     * 測試模擬三個窗口售票
     * @throws InterruptedException
     */
    @Test
    public void testTicketThread() throws InterruptedException {
        System.out.println("---test start-------");
        // 模擬多3個窗口售票
        TicketThread ticketThread1 = new TicketThread();
        TicketThread ticketThread2 = new TicketThread();
        TicketThread ticketThread3 = new TicketThread();
        // 啟動線程售票
        ticketThread1.start();
        ticketThread2.start();
        ticketThread3.start();
        System.out.println("======等待售票============");
        Thread.sleep(5 * 1000);
        System.out.println("---test end-------");
    }

結果:

1.在售票過程中不能區分售出的票是那個窗口售出的,解決通過線程名稱判斷

2.有重複售出的票(後面的線程同步解決)

解決第一個問題,設置獲取線程名稱,通過Thread對象裏面自帶的getName,setName方法

 具體代碼

設置線程名稱

 獲取線程名稱

 上面講了繼承的方式獲取線程名稱,那麼實現接口Runnable的方式怎麼獲取設置勒

繼承Thread的方式,可以通過getName的方式獲取當前線程的名稱?
那使用Runnable的方式,能通過getName獲取嘛?

getName方法是Thread類的,但是TicketThread現在並沒有繼承Thread類,而是實現了Runnable接口.

問題:如果實現Runnable接口,怎麼獲取線程名稱?

 思考:TicketThread類裏面的代碼要執行,它肯定存在於某個線程中, 就比如寫個helloword打印語句,是不是也處於一個主線程中,那這裏怎麼獲取線程名稱?
通過動態獲取,當程序正在執行的時候,獲取當前正在執行的線程名稱。怎麼獲取?
在Thread類裏面有個靜態的方法currentThread() 方法,返回當前正在執行的線程引用;

Thread.currentThread().getName

那怎麼設置線程名稱?

Thread類裏面有個name字段,相當於Thread類把它包裝了一下:

通過源碼可以發現,構造方法裏面還有可以傳一個名字:

具體實現代碼如下

 

 總結:

繼承方式設置\獲取線程名稱通過 Thread對象裏面的 setName,getName方法;

實現接口方式設置名稱通過 new Thread(‘線程實例對象’, “線程名稱”),獲取線程名稱通過:Thread.currentThread().getName

1.6.Thread的join方法

void join() 方法 :等待該線程終止
void join(long millis) 方法 :等待該線程終止的時間最長為millis毫秒

需求: 當主線程運行到20的時候(i =20)的時候,讓JoinThread線程加進來直到執行完成,在執行主線程.

 1 package com.wfd360.thread;
 2 
 3 import org.junit.Test;
 4 
 5 /**
 6  * @author 姿勢帝-博客園
 7  * @address https://www.cnblogs.com/newAndHui/
 8  * @WeChat 851298348
 9  * @create 05/04 6:31
10  * @description
11  */
12 public class Test05Join {
13     /**
14      * 需求:
15      * 當主線程for循環到i=20時,等JoinThread線程執行完成后,在執行for循環的線程
16      * @throws InterruptedException
17      */
18     @Test
19     public void testJoinThread() throws InterruptedException {
20         System.out.println("---test start-------");
21         // 開啟線程
22         JoinThread thread = new JoinThread();
23         thread.start();
24         // 循環打印線程
25         for (int i = 0; i < 100; i++) {
26             System.out.println("======testJoinThread=========="+i);
27             Thread.sleep(1);
28             if (i==20){
29                 // 等線程JoinThread執行完成
30                 thread.join();
31             }
32         }
33         System.out.println("=============等待線程執行完成===================");
34         Thread.sleep(10*1000);
35         System.out.println("---test end-------");
36     }
37     
38     class JoinThread extends Thread {
39         @Override
40         public void run() {
41             for (int i = 0; i < 100; i++) {
42                 System.out.println("=====JoinThread=======" + i);
43                 // 模擬處理很多業務耗時1毫秒
44                 try {
45                     Thread.sleep(1);
46                 } catch (InterruptedException e) {
47                     e.printStackTrace();
48                 }
49             }
50         }
51     }
52 }

Test05Join

1.7.線程優先級

直接上代碼

 1 package com.wfd360.thread;
 2 
 3 /**
 4  * @author 姿勢帝-博客園
 5  * @address https://www.cnblogs.com/newAndHui/
 6  * @WeChat 851298348
 7  * @create 05/05 8:17
 8  * @description <p>
 9  * 1.==>線程優先級的理解:
10  * 線程的優先級和生活中類似,高優先級線程的執行優先於低優先級線程;
11  * 並不是絕對的,可能優先級高的線程優先 比 優先級低的線程先執行,只能說,高優先級的線程優先執行的幾率更多;
12  * (比如兩個線程,一個優先級高,一個優先級低,如果一共運行一個小時,優先級高的線程執行遠遠大於優先級低的但是並不是說優先級高的先執行完,
13  * 在執行優先級低的)
14  * 2.==>重新設置線程優先級
15  * int getPriority() 返回線程的優先級。
16  * void setPriority(int newPriority) 更改線程的優先級。Java線程的優先級從1到10級別,值越大優先級越高.
17  * 3.==>線程的默認優先級受創建線程的環境影響,默認值5,自定義線程的默認優先級和創建它的環境的線程優先級一致
18  * </p>
19  */
20 public class Test06Priority {
21     /**
22      * 測試獲取線程優先級,設置線程優先級,驗證線程優先級受創建環境影響
23      * @param args
24      */
25     public static void main(String[] args) {
26         Thread threadMain = Thread.currentThread();
27         // 獲取默認優先級数字
28         System.out.println("main線程默認優先級:" +threadMain.getPriority());// 5
29         // 重新設置默認優先級数字
30         threadMain.setPriority(8);
31         // 再次重新獲取優先級数字
32         System.out.println("main線程修改后的優先級:" +threadMain.getPriority());// 8
33         // 創建一個線程查看優先級
34         Thread thread = new Thread();
35         System.out.println("thread線程的優先級:" +thread.getPriority());// 8 受創建環境影響
36     }
37 }

1.8.後台線程,即守護線程

直接看代碼

 1 package com.wfd360.thread;
 2 
 3 import com.wfd360.thread.demo04Daemon.DaemonThreaad;
 4 
 5 /**
 6  * @author 姿勢帝-博客園
 7  * @address https://www.cnblogs.com/newAndHui/
 8  * @WeChat 851298348
 9  * @create 05/05 9:12
10  * @description <p>
11  * 後台線程,即守護線程
12  * 後台線程:指為其他線程提供服務的線程,也稱為守護線程。JVM的垃圾回收線程就是一個後台線程。
13  * 需求:嘗試把線程標記為後台線程或者標記為(前台)線程;
14  * Thread類提供的方法:
15  * 方法1: void setDaemon(boolean on) 將該線程標記為守護線程或用戶線程,true為後台線程,false為用戶線程(前台線下)
16  * 怎樣測試該線程是否是守護線程?
17  * 方法2:isDaemon()  測試該線程是否為守護線程. true為後台線程,false為用戶線程(前台線下)
18  * <p>
19  * 結論1:活動的線程(已經在執行的線程t.start())不能設置後台線程,即主線程不能設置為後台線程。
20  * 結論2: 自定義線程的默認狀態和環境有關,後台線程中創建的線程默認是後台線程,前台線程中創建的線程為前台線程.
21  * 結論3: 前台線程執行完后,會直接關閉後台線程,即自定義的後台線程不一定能執行完成
22  * </p>
23  */
24 public class Test07Daemon {
25     /**
26      * 測試1
27      * 查看主線程的狀態,嘗試更改
28      * 結論:活動的線程不能設置為後台線程
29      *
30      * @param args
31      */
32     public static void main1(String[] args) {
33         Thread threadMain = Thread.currentThread();
34         System.out.println("是後台線程么:" + threadMain.isDaemon());// false
35         threadMain.setDaemon(true); // 報錯,活動的線程不能設置為後台線程
36         System.out.println("修改后是後台線程么:" + threadMain.isDaemon());
37     }
38 
39     /**
40      * 測試2
41      * 查看主線程中 創建線程的狀態,嘗試更改;
42      *
43      * @param args
44      */
45     public static void main2(String[] args) {
46         Thread thread = new Thread();
47         // false
48         System.out.println("是後台線程么:" + thread.isDaemon());
49         // 修改為後台線程
50         thread.setDaemon(true);
51         System.out.println("修改后是後台線程么:" + thread.isDaemon());
52     }
53 
54     /**
55      * 測試3
56      * 查看主線程中 創建線程的狀態,嘗試更改,讓線程處於活動狀態在修改->報錯;
57      *
58      * @param args
59      */
60     public static void main3(String[] args) {
61         DaemonThread thread = new DaemonThread();
62         // 讓線程處於活躍狀態
63         thread.start();
64         // false
65         System.out.println("是後台線程么:" + thread.isDaemon());
66         // 修改為後台線程,報錯,當前已經是活躍狀態(thread.start())不能修改為後台線程
67         thread.setDaemon(true);
68         System.out.println("修改后是後台線程么:" + thread.isDaemon());
69     }
70 
71     /**
72      * 測試4
73      * 前台線程執行完后,會直接關閉後台線程,即如果後台線程不一定能執行完成
74      * 可以通過修改等待執行時間來觀察DaemonThread線程的數組輸出變化
75      *
76      * @param args
77      */
78     public static void main(String[] args) throws InterruptedException {
79         DaemonThread thread = new DaemonThread();
80         // 修改為後台線程
81         thread.setDaemon(true);
82         // 讓線程處於活躍狀態
83         thread.start();
84         System.out.println("========等待後台線程執行============");
85         Thread.sleep(5 * 1000);
86     }
87 }
 1 package com.wfd360.thread.demo04Daemon;
 2 
 3 /**
 4  * @author 姿勢帝-博客園
 5  * @address https://www.cnblogs.com/newAndHui/
 6  * @WeChat 851298348
 7  * @create 05/05 9:27
 8  * @description
 9  */
10 public class DaemonThread extends Thread {
11     @Override
12     public void run() {
13         for (int i = 0; i < 10; i++) {
14             System.out.println("===="+i);
15             try {
16                 Thread.sleep(1000);
17             } catch (InterruptedException e) {
18                 e.printStackTrace();
19             }
20         }
21     }
22 }

DaemonThread

線程基礎相關的方法定義就先到這裏,下一篇我們將進入線程同步.

https://www.cnblogs.com/newAndHui/p/12831089.html

系統化的在線學習:點擊進入學習

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

【其他文章推薦】

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

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

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

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

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

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

分類
發燒車訊

WebService之Spring+CXF整合示例

一、Spring+CXF整合示例

WebService是一種跨編程語言、跨操作系統平台的遠程調用技術,它是指一個應用程序向外界暴露一個能通過Web調用的API接口,我們把調用這個WebService的應用程序稱作客戶端,把提供這個WebService的應用程序稱作服務端。

環境

win10+Spring5.1+cxf3.3.2

下載

  • 官網下載:https://archive.apache.org/dist/cxf/
  • 百度網盤:
    鏈接:https://pan.baidu.com/s/1nsUweTFG_6CcZKaVBCQ7uQ
    提取碼:4qp7

服務端

  • 新建web項目
  • 放入依賴
    apache-cxf-3.3.2\lib中的jar包全部copy至項目WEB-INF\lib目錄下(偷個懶,這些jar包中包含了Spring所需的jar包)
  • web.xml中添加webService的配置攔截
<!--webService  -->
<servlet>
    <servlet-name>CXFService</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>CXFService</servlet-name>
    <url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
  • webservice服務接口
    在項目src目錄下新建pms.inface.WebServiceInterface
package pms.inface;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

@WebService(targetNamespace = "http://spring.webservice.server", name = "WebServiceInterface")
public interface WebServiceInterface {

	@WebMethod
    @WebResult(name = "result", targetNamespace = "http://spring.webservice.server")
	public String sayBye(@WebParam(name = "word", targetNamespace = "http://spring.webservice.server") String word);

}

  • 接口實現類
    在項目src目錄下新建pms.impl.WebServiceImpl
package pms.impl;

import javax.jws.WebService;

import pms.inface.WebServiceInterface;

@WebService
public class WebServiceImpl implements WebServiceInterface{

	@Override
	public String sayBye(String word) {
		return word + "當和這個真實的世界迎面撞上時,你是否找到辦法和自己身上的慾望講和,又該如何理解這個鋪面而來的人生?";
	}

}

  • webservice配置文件
    WEB-INF目錄下新建webservice配置文件cxf-webService.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:jaxws="http://cxf.apache.org/jaxws"
	xmlns:cxf="http://cxf.apache.org/core"
	xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://cxf.apache.org/jaxws
       http://cxf.apache.org/schemas/jaxws.xsd
       http://cxf.apache.org/core
	   http://cxf.apache.org/schemas/core.xsd
	   http://cxf.apache.org/transports/http/configuration
	   http://cxf.apache.org/schemas/configuration/http-conf.xsd
	   ">
	   
	<import resource="classpath:META-INF/cxf/cxf.xml" />

	<!-- 使用jaxws:server標籤發布WebService服務 ,設置address為訪問地址, 和web.xml文件中配置的CXF配合為一個完整的路徑 -->
	<!-- serviceClass為實現類的接口 serviceBean引用配置好的WebService實現類 -->
	<jaxws:server address="/webServiceInterface"
		serviceClass="pms.inface.WebServiceInterface">
		<jaxws:serviceBean>
			<ref bean="WebServiceImpl" />
		</jaxws:serviceBean>
	</jaxws:server>
	
	<!-- 為所有的WS設置超時時間 ,此時為默認值 連接時間30s,等待回復時間為60s-->	
	<http-conf:conduit name="*.http-conduit">
		<http-conf:client ConnectionTimeout="60000" ReceiveTimeout="120000"/>
	</http-conf:conduit>

</beans>
  • spring配置文件
    WEB-INF目錄下新建spring配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="WebServiceImpl" class="pms.impl.WebServiceImpl"></bean>
	
	<import resource="cxf-webService.xml" />

</beans>

      在web.xml中配置applicationContext.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
		    /WEB-INF/applicationContext.xml
		</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  • 將項目放至tomcat中啟動
    啟動后訪問地址:localhost:PORT/項目名/webservice/webServiceInterface?wsdl,如下圖所示,webservice接口發布成功

二、SoapUI測試

SoapUI是一個開源測試工具,通過soap/http來檢查、調用、實現Web Service的功能/負載/符合性測試。

下載

  • 百度網盤
    鏈接:https://pan.baidu.com/s/1N2RTqhvrkuzx7YJvmDeY7Q
    提取碼:e1w3

測試

  • 打開SoapUI,新建一個SOAP項目,將剛才的發布地址copyInitial WSDL欄,點擊OK按鈕
  • 發起接口請求

三、客戶端

使用wsdl2java工具生成webservice客戶端代碼

  • 該工具在剛才下載的apache-cxf-3.3.2\bin目錄下
  • 配置環境變量
    設置CXF_HOME,並添加%CXF_HOME %/binpath環境變量。
  • CMD命令行輸入wsdl2java -help,有正常提示說明環境已經正確配置
  • wsdl2java.bat用法:
wsdl2java –p 包名 –d 存放目錄 -all wsdl地址

-p 指定wsdl的命名空間,也就是要生成代碼的包名

-d 指令要生成代碼所在目錄

-client 生成客戶端測試web service的代碼

-server 生成服務器啟動web service代碼

-impl 生成web service的實現代碼,我們在方式一用的就是這個

-ant 生成build.xml文件

-all 生成所有開始端點代碼
  • 生成客戶端代碼
wsdl2java -p pms.inface -d ./ -all http://localhost:8080/spring_webservice_server/webservice/webServiceInterface?wsdl

客戶端調用

  • 新建web項目
  • 放入依賴
    apache-cxf-3.3.2\lib中的jar包全部copy至項目WEB-INF\lib目錄下
  • wsdl2java生成的代碼放至src.pms.inface目錄下
調用方法一:
  • 新建webServiceClientMain測試
package pms;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import pms.inface.WebServiceInterface;

public class webServiceClientMain {
	public static void main(String[] args) {
		JaxWsProxyFactoryBean svr = new JaxWsProxyFactoryBean();
		svr.setServiceClass(WebServiceInterface.class);
		svr.setAddress("http://localhost:8080/spring_webservice_server/webservice/webServiceInterface?wsdl");
		WebServiceInterface webServiceInterface = (WebServiceInterface) svr.create();

		System.out.println(webServiceInterface.sayBye("honey,"));
	}
}
  • 運行webServiceClientMain
調用方法二:
  • 在src目錄下新建applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jaxws="http://cxf.apache.org/jaxws"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-3.0.xsd
		http://cxf.apache.org/jaxws
		http://cxf.apache.org/schemas/jaxws.xsd">

	<jaxws:client id="webServiceInterface"
		serviceClass="pms.inface.WebServiceInterface"
		address="http://localhost:8080/spring_webservice_server/webservice/webServiceInterface?wsdl" >
	</jaxws:client>	
</beans>
  • 新建webServiceClientTest測試
package pms;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pms.inface.WebServiceInterface;

public class webServiceClientTest {

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		WebServiceInterface webServiceInterface = context.getBean(WebServiceInterface.class);
		String result = webServiceInterface.sayBye("honey,");
		System.out.println(result);
	}
	
}
  • 運行webServiceClientTest

四、服務端攔截器

  • 需求場景:服務提供方安全驗證,也就是webservice自定義請求頭的實現,服務接口在身份認證過程中的密碼字段滿足SM3(哈希函數算法標準)的加密要求
  • SM3加密所需jar包:commons-lang3-3.9.jarbcprov-jdk15on-1.60.jar,這兩個jar包在剛才下載的apache-cxf-3.3.2\lib下就有
  • 請求頭格式
<security>
	<username></username>
	<password></password>
</auth>
  • src.pms.interceptor下新建WebServiceInInterceptor攔截器攔截請求,解析頭部
package pms.interceptor;

import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import pms.support.Sm3Utils;
import pms.support.StringUtils;

/**
 * WebService的輸入攔截器
 * @author coisini
 * @date May 2020, 13
 *
 */
public class WebServiceInInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
	
    private static final String USERNAME = "admin";
    private static final String PASSWORD = "P@ssw0rd";
    
    /**
     * 允許訪問的IP
     */
    private static final String ALLOWIP = "127.0.0.1;XXX.XXX.XXX.XXX";

	public WebServiceInInterceptor() {
		/*
		 * 攔截器鏈有多個階段,每個階段都有多個攔截器,攔截器在攔截器鏈的哪個階段起作用,可以在攔截器的構造函數中聲明
		 * RECEIVE 接收階段,傳輸層處理
		 * (PRE/USER/POST)_STREAM 流處理/轉換階段
		 * READ SOAPHeader讀取 
		 * (PRE/USER/POST)_PROTOCOL 協議處理階段,例如JAX-WS的Handler處理 
		 * UNMARSHAL SOAP請求解碼階段 
		 * (PRE/USER/POST)_LOGICAL SOAP請求解碼處理階段 
		 * PRE_INVOKE 調用業務處理之前進入該階段 
		 * INVOKE 調用業務階段 
		 * POST_INVOKE 提交業務處理結果,並觸發輸入連接器
		 */
		super(Phase.PRE_INVOKE);
	}

	/**
	  * 客戶端傳來的 soap 消息先進入攔截器這裏進行處理,客戶端的賬目與密碼消息放在 soap 的消息頭<security></security>中,
	  * 類似如下:
     * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
     * <soap:Header><security><username>admin</username><password>P@ssw0rd</password></security></soap:Header>
     * <soap:Body></soap:Body></soap:Envelope>
     * 現在只需要解析其中的 <head></head>標籤,如果解析驗證成功,則放行,否則這裏直接拋出異常,
     * 服務端不會再往後運行,客戶端也會跟着拋出異常,得不到正確結果
     *
     * @param message
     * @throws Fault
     */
	@Override
    public void handleMessage(SoapMessage message) throws Fault {
		System.out.println("PRE_INVOKE");
		
		HttpServletRequest request = (HttpServletRequest)message.get(AbstractHTTPDestination.HTTP_REQUEST);
	    String ipAddr=request.getRemoteAddr();
	    System.out.println("客戶端訪問IP----"+ipAddr);
	    
	    if(!ALLOWIP.contains(ipAddr)) {
			throw new Fault(new IllegalArgumentException("非法IP地址"), new QName("0009"));
		}
		
		/**
		 * org.apache.cxf.headers.Header
         * QName :xml 限定名稱,客戶端設置頭信息時,必須與服務器保持一致,否則這裏返回的 header 為null,則永遠通不過的
         */
		Header authHeader = null;
		//獲取驗證頭
		List<Header> headers = message.getHeaders();
		for(Header h:headers){
			if(h.getName().toString().contains("security")){
				authHeader=h;
				break;
			}
		}
		System.out.println("authHeader");
		System.out.println(authHeader);
		
		if(authHeader !=null) {
			Element auth = (Element) authHeader.getObject();
			NodeList childNodes = auth.getChildNodes();
			String username = null,password = null;
			for(int i = 0, len = childNodes.getLength(); i < len; i++){
					Node item = childNodes.item(i);
					if(item.getNodeName().contains("username")){
						username = item.getTextContent();
						System.out.println(username);
					}
					if(item.getNodeName().contains("password")){
						password = item.getTextContent();
						System.out.println(password);
					}
			}
			
			if(StringUtils.isBlank(username) || StringUtils.isBlank(password)) { 
		    	throw new Fault(new IllegalArgumentException("用戶名或密碼不能為空"), new QName("0001")); 
		    }
			
			if(!Sm3Utils.verify(USERNAME, username) || !Sm3Utils.verify(PASSWORD,password)) { 
		    	throw new Fault(new IllegalArgumentException("用戶名或密碼錯誤"), new QName("0008")); 
		    }
		  
		    if (Sm3Utils.verify(USERNAME, username) && Sm3Utils.verify(PASSWORD,password)) { 
		    	System.out.println("webService 服務端自定義攔截器驗證通過...."); 
		    	return;//放行
		    } 
		}else {
			throw new Fault(new IllegalArgumentException("請求頭security不合法"), new QName("0010"));
		}
	}

	// 出現錯誤輸出錯誤信息和棧信息
	public void handleFault(SoapMessage message) {
		Exception exeption = message.getContent(Exception.class);
		System.out.println(exeption.getMessage());
	}
	
}
  • src.pms.support下新建Sm3Utils加密類
package pms.support;

import java.io.UnsupportedEncodingException;
import java.security.Security;
import java.util.Arrays;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

/**
 * SM3加密
 * @author coisini
 * @date May 2020, 13
 */
public class Sm3Utils {
	 private static final String ENCODING = "UTF-8";
     static {
         Security.addProvider(new BouncyCastleProvider());
     }
	    
    /**
     * sm3算法加密
     * @explain
     * @param paramStr
     * 待加密字符串
     * @return 返回加密后,固定長度=32的16進制字符串
     */
    public static String encrypt(String paramStr){
        // 將返回的hash值轉換成16進制字符串
        String resultHexString = "";
        try {
            // 將字符串轉換成byte數組
            byte[] srcData = paramStr.getBytes(ENCODING);
            // 調用hash()
            byte[] resultHash = hash(srcData);
            // 將返回的hash值轉換成16進制字符串
            resultHexString = ByteUtils.toHexString(resultHash);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return resultHexString;
    }
    
    /**
     * 返回長度=32的byte數組
     * @explain 生成對應的hash值
     * @param srcData
     * @return
     */
    public static byte[] hash(byte[] srcData) {
        SM3Digest digest = new SM3Digest();
        digest.update(srcData, 0, srcData.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }
    
    /**
     * 通過密鑰進行加密
     * @explain 指定密鑰進行加密
     * @param key
     *            密鑰
     * @param srcData
     *            被加密的byte數組
     * @return
     */
    public static byte[] hmac(byte[] key, byte[] srcData) {
        KeyParameter keyParameter = new KeyParameter(key);
        SM3Digest digest = new SM3Digest();
        HMac mac = new HMac(digest);
        mac.init(keyParameter);
        mac.update(srcData, 0, srcData.length);
        byte[] result = new byte[mac.getMacSize()];
        mac.doFinal(result, 0);
        return result;
    }
    
    /**
     * 判斷源數據與加密數據是否一致
     * @explain 通過驗證原數組和生成的hash數組是否為同一數組,驗證2者是否為同一數據
     * @param srcStr
     *            原字符串
     * @param sm3HexString
     *            16進制字符串
     * @return 校驗結果
     */
    public static boolean verify(String srcStr, String sm3HexString) {
        boolean flag = false;
        try {
            byte[] srcData = srcStr.getBytes(ENCODING);
            byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);
            byte[] newHash = hash(srcData);
            if (Arrays.equals(newHash, sm3Hash))
                flag = true;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return flag;
    }
    
    public static void main(String[] args) {
        // 測試二:account
        String account = "admin";
        String passoword = "P@ssw0rd";
        String hex = Sm3Utils.encrypt(account);
        System.out.println(hex);//dc1fd00e3eeeb940ff46f457bf97d66ba7fcc36e0b20802383de142860e76ae6
        System.out.println(Sm3Utils.encrypt(passoword));//c2de40449a2019db9936381fa9810c22c8548a8635ed2b7fb3c7ec362e37429d
        //驗證加密后的16進制字符串與加密前的字符串是否相同
        boolean flag =  Sm3Utils.verify(account, hex);
        System.out.println(flag);// true
    }
}
  • StringUtils工具類
package pms.support;

/**
 * 字符串工具類
 * @author coisini
 * @date Nov 27, 2019
 */
public class StringUtils {

	/**
	 * 判空操作
	 * @param value
	 * @return
	 */
	public static boolean isBlank(String value) {
		return value == null || "".equals(value) || "null".equals(value) || "undefined".equals(value);
	}

}
  • cxf-webService.xml添加攔截器配置
<!-- 在此處引用攔截器 -->
<bean id="InInterceptor"
	class="pms.interceptor.WebServiceInInterceptor" >
</bean>

<cxf:bus>
	<cxf:inInterceptors>
		<ref bean="InInterceptor" />
	</cxf:inInterceptors>
</cxf:bus> 
  • SoapUI調用
  • java調用

    服務端攔截器到此結束,由上圖可以看出攔截器配置生效

五、客戶端攔截器

  • src.pms.support下新建AddHeaderInterceptor攔截器攔截請求,添加自定義認證頭部
package pms.support;

import java.util.List;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage>{ 
    
    private String userName; 
    private String password; 
       
    public AddHeaderInterceptor(String userName, String password) { 
        super(Phase.PREPARE_SEND); 
        this.userName = userName; 
        this.password = password;  
    } 
   
    @Override 
    public void handleMessage(SoapMessage msg) throws Fault { 
    	   System.out.println("攔截...");
        
           /**
            * 生成的XML文檔
            * <authHeader>
            *      <userName>admin</userName>
            *      <password>P@ssw0rd</password>
            * </authHeader>
            */ 
        
        	// SoapHeader部分待添加的節點
     		QName qName = new QName("security");
     		Document doc = DOMUtils.createDocument();

     		Element pwdEl = doc.createElement("password");
     		pwdEl.setTextContent(password);
     		Element userEl = doc.createElement("username");
     		userEl.setTextContent(userName);
     		Element root = doc.createElement("security");
     		root.appendChild(userEl);
     		root.appendChild(pwdEl);
     		// 創建SoapHeader內容
     		SoapHeader header = new SoapHeader(qName, root);
     		// 添加SoapHeader內容
     		List<Header> headers = msg.getHeaders();
     		headers.add(header); 
    } 
}
  • java調用,修改webServiceClientMain調用代碼如下
public class webServiceClientMain {
	public static void main(String[] args) {
		JaxWsProxyFactoryBean svr = new JaxWsProxyFactoryBean();
		svr.setServiceClass(WebServiceInterface.class);
		svr.setAddress("http://localhost:8081/spring_webservice_server/webservice/webServiceInterface?wsdl");
		WebServiceInterface webServiceInterface = (WebServiceInterface) svr.create();
		
		// jaxws API 轉到 cxf API 添加日誌攔截器
		org.apache.cxf.endpoint.Client client = org.apache.cxf.frontend.ClientProxy
				.getClient(webServiceInterface);
		org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
		//添加自定義的攔截器
		cxfEndpoint.getOutInterceptors().add(new AddHeaderInterceptor("dc1fd00e3eeeb940ff46f457bf97d66ba7fcc36e0b20802383de142860e76ae6", "c2de40449a2019db9936381fa9810c22c8548a8635ed2b7fb3c7ec362e37429d"));
		
		System.out.println(webServiceInterface.sayBye("honey,"));
	}
}

  • SoapUI調用

六、代碼示例

服務端:https://github.com/Maggieq8324/spring_webservice_server.git
客戶端:https://github.com/Maggieq8324/spring_webservice_client.git

.end

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

【其他文章推薦】

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

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

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

※回頭車貨運收費標準

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

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

分類
發燒車訊

疫情下的奇景!孟買市區湧入大量紅鶴 數量估創紀錄

摘錄自2020年5月2日自由時報綜合報導

根據《CNN》報導,每年9月至翌年5月都會觀測到紅鶴族群遷徙至孟買覓食,然而,今(2020)年在人類活動大幅下降的狀況下,遷徙至當地的紅鶴數量預估將超過13萬4000隻,創下歷史新高。

孟買自然歷史學會(BNHS)副主任科特(Rahul Khot)表示,在人類社交活動暫停後,當地不僅出現破紀錄數量的紅鶴,牠們選定的棲地也與往常相異,已有族群擴展至以往少見紅鶴蹤跡的濕地。

印度境內陸續傳出野生動物受益於武漢肺炎疫情的消息,不只德里湧入大量猴群,極瀕危的恆河江豚也在多年來首度被觀測到活體行為;顯示出人類活動暫停,讓我們的地球鄰居們產生明顯變化。

生物多樣性
生態保育
國際新聞
印度
孟買
紅鶴
江豚
動物與大環境變遷
武漢肺炎

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

【其他文章推薦】

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

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

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

※超省錢租車方案

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

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

※回頭車貨運收費標準

分類
發燒車訊

山地大猩猩的家園不平靜 剛果維龍加國家公園12名護管員遭殺害

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

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

【其他文章推薦】

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

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

※超省錢租車方案

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

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

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

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

分類
發燒車訊

法下週解除封鎖令 巴黎交通主幹道規劃給自行車

摘錄自2020年5月5日自由時報報導

法國為遏止武漢肺炎(新型冠狀病毒疾病,COVID-19)疫情擴散,自3月17日起實施全國封鎖,期間2度延長封鎖禁令至5月11日;面對下週即將解除的封鎖令,巴黎市長伊達戈(Anne Hidalgo)將把最繁忙的主要交通幹道規劃給自行車,以減少民眾對大眾運輸工具的依賴,進而避免群聚感染。

伊達戈今(5日)指出,城市解封後共將保留50公里原先的汽車道給自行車使用,另外將有30條街道將被設置為行人專用道,她強調,「特別是在學校周圍,以避免人群聚集」。

法國政府也宣布了一項2000萬歐元(約新台幣6.5億元)的自行車計畫,用以刺激民眾在封鎖解除後對自行車的使用度,其中包括每人50歐元(約新台幣1620元)的自行車維修或調整補貼。

生活環境
國際新聞
法國
檢疫封鎖
解除
自行車道

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

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

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

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

分類
發燒車訊

非洲豬瘟迫降! 韓媒爆北韓豬瘟再起 邊境恐成傳播溫床

摘錄自2020年5月5日自由時報報導

北韓在去年5月底爆出非洲豬瘟,9月時更爆出豬瘟疫情全面失控,但之後卻未有通報案例。不過南韓媒體爆料,非洲豬瘟在北韓又再度爆發,尤其是黃海北道、平安南道以及平安北道三處。

由脫北者經營的南韓媒體《每日北韓》報導,平安南道消息人士透露,非洲豬瘟再次席捲北韓,獸醫機構視其為緊急狀態,尤其是黃海北道、平安南道以及平安北道三處的私人豬舍或合作經營農場。

由於北韓當局最近發布《非洲豬瘟防疫指南》,因此有分析指出,北韓非洲豬瘟疫情仍持續。北韓官報也向民眾宣導牲畜疾病防疫對民眾的重要性。

生活環境
國際新聞
北韓
非洲豬瘟
食品安全

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

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

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

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

分類
發燒車訊

真不是隨便選的,原來車漆顏色的選擇有那麼多門道

而且合適的車漆能讓我們的愛車有着更好的外觀效果。

筆者總結:

所以說車漆的選擇是有一定門道,這是我們在購車前就應該了解的,畢竟這關乎到我們用車養車的各個方面。而且合適的車漆能讓我們的愛車有着更好的外觀效果。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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

分類
發燒車訊

30萬價格卻有50萬級的大氣場豪華中大型轎車

內飾方面也保持了旗艦車型應有的氣場,棕色為主的色調,大量實木材質飾板提升了不少檔次感,沉穩而大方,電動吸合門這麼高逼格的配置40。90萬的輝昂居然配備了,要知道同價位的BBA都沒有的東西,檔次感一下子就上去了。

在外打拚多年的老陳買了輛車子,過年帶着媳婦回到村子。

村民都投來了羡慕的眼光,鄰居家小黃問他:“陳哥賺了不少錢吧,都換了五六十萬的車子了”。

老陳心裏偷着樂:“嘿嘿,這豪華中大型轎車裸車才20幾萬呢,氣場就是強大,”

一說起豪華中大型轎車,大家都犹如耳濡目染,基本是被德系車如奧迪A6L、奔馳E級、寶馬5系等車型所包攬,但是如果價格去到30萬出頭,就只能是買到乞丐版車型了,那還不如買一些擁有強大氣場而且有着很高行車品質的車型,而且性價比也比較高,一起來看一下吧!

雷克薩斯-ES

指導價:29.80-49.80萬

說起雷克薩斯品牌總是給人一種溫文爾雅的感覺,前臉誇張的紡錘形設計進氣格柵,搭配外圈鍍鉻飾條,極具視覺衝擊感,提升了不少氣場,流暢的車身線條,立體感十足的尾燈,使得整輛車的氣質都提升了。

不同配置間的車型內飾材質也是略有不同,但是做工和品質還是一如既往的上乘,即使是最低配車型,也配備了胎壓監測、無鑰匙啟動/進入、上坡輔助、電動天窗、倒車影像、自動頭燈等配置,非常實用。

座椅採用了打孔皮革材料,坐上去感覺很厚實,與身體十分貼合,舒適性好,動力方面提供了2.0L最大功率167馬力或者2.5L最大功率184馬力的發動機,匹配6擋手自一體變速器,輕鬆好開才是重點,輸出和換擋都非常平順。

上汽大眾-輝昂

指導價:34.90-65.90萬

輝昂是上汽大眾打造的首款中大型轎車,與奧迪A6L出自MLB同一平台,足以吸引人的眼球,在大眾透視套娃式的外觀設計中,輝昂還是有這獨特的氣質的,寬大的前臉線條,雙邊四齣的排氣管裝飾罩,氣場還是挺嚇唬人的。

內飾方面也保持了旗艦車型應有的氣場,棕色為主的色調,大量實木材質飾板提升了不少檔次感,沉穩而大方,電動吸合門這麼高逼格的配置40.90萬的輝昂居然配備了,要知道同價位的BBA都沒有的東西,檔次感一下子就上去了。

輝昂的軸距達到了3009mm,想怎麼坐就怎麼坐,蹺二郎腿什麼的不在話下,寬厚的座椅設計人體工程學很到位,乘坐舒適性良好,動力提供了2.0T或者3.0T V6發動機的選擇,搭配7擋雙離合變速器,開起來很輕鬆就能上手駕馭,整車調校偏舒適,底盤是一如既往的沉穩。

英菲尼迪(進口)-Q70

指導價:39.98-64.98萬

作為英菲尼迪家族的旗艦豪華轎車,Q70L有着略帶攻擊性的外觀設計,菱形進氣格柵變得更加年輕了,犀利的全LED大燈組被大面積的鍍鉻飾條包裹,豪華氛圍濃厚,而車尾部的造型非常的飽滿、健碩,整體風格更加運動化。

環抱式的內飾設計給人很熟悉的感覺,真皮包裹的中控台手感很好,大量木紋飾板的點綴,加上中控上的石英鐘,豪華感非常強,除了最低配車型外,全系標配BOSE音響,還有電動吸合門也是全系標配的,這配置實在夠強大的。

座椅寬大厚實,對身體的各部位支撐到位,乘坐感受很出色,後排空間絕對是Q70L的一大亮點,3050mm的軸距競爭力很強,動力提供了V6布局的2.5L或者3.5L自然吸氣發動機,全系標配駕駛模式切換,動力輸出很線性,發動機聲音在高轉速是令人興奮的,但是不會給人很激烈駕駛的慾望。

總結:30萬左右的價格,選擇這些非主流的中大型豪華轎車,卻有着50萬級別車該有的氣場,而且配置上比寶馬奔馳奧迪那些主流品牌車型更為豐富,可以作為購車的一個新選擇。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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

分類
發燒車訊

論冠道具備何種洪荒之力,從SUV戰場突圍

在通常情況下,車輛處於前輪驅動行駛狀態,這套系統會實時監控發動機扭矩以及各車輪轉速等信息參數。當需要後輪的驅動力時,电子系統就會將動力分配給後輪,得到一定的脫困能力和爬坡能力,比我們平常熟悉的適時四驅系統智能上不少。

熟悉數碼產品的你們,應該都會知道有句話叫做“索尼大法好”,這讓索尼上升到了宗師級的地位,這滿滿的都是情懷。而在汽車界,“本田大法好”也是我們經常聊到的話題,本田的“黑科技”使不少朋友們都成為了本田粉,這也是滿滿的情懷之說。

繼小型化10AT變速箱之後,前不久,本田又要在變速箱領域中想要大顯身手,據海外媒體報道,本田已向日本專利局為其全新變速箱提出申請,這台變速箱有11個擋位並且包括了3個離合器。

這再次證明了本田在研製和調校變速箱有着絕對的實力,而全新上市的冠道則採用了來自德國ZF的9AT變速箱,相信大家都不陌生,它之前在路虎攬勝極光、Jeep自由光上都有搭載。

按照本田的設計和理論來說,更多的擋位和離合器會讓換擋響應效率更高,跳擋更加平順,而且還能有效減少扭矩損失,意味着能夠達到更好的燃油經濟性。

毫無疑問,搭載着9AT變速箱的冠道駕駛起來平順之餘,燃油經濟性同樣突出。根據官方的說法,這台9速自動變速箱中從6擋開始即為超速擋,也就是輸入轉速低於輸出轉速,更多的超速擋意味着在寬泛的車速區間能以更經濟的轉速行駛,這也是省油的原因之一。

告訴大家一個小秘密,冠道作為大塊頭喝93號(京92號)汽油,油箱容積為57L,加滿一箱油才不到四百塊,能夠省不少用車成本。

思域TYpE-R在本田粉心目中的地位是非常高的,紅頭髮動機對我們這一代人來說意味着本田的“最強動力”,這台發動機征戰了無數次紐博格林北環賽道,7分50秒這個数字在本田粉心中一直揮之不去。

採用2.0T發動機的冠道,其發動機就是源自思域TYpE-R的紅頭髮動機而打造的,作為一台中型SUV,採用了性能車的發動機也是實屬罕見。

最大功率 200 kW(272ps)/6500rpm,最大扭矩 370N m/2250-4500rpm,單純從數據上看,或許你以為這就是一台小鋼炮。

冠道在同級別車型中擁有着最強動力,比起2.0T漢蘭達最大功率162kW(220ps)強上不是一星半點,8秒內能時速破百,看到這裏你服氣嗎?你要想想這大塊頭擁有着1.8噸左右的車重…

●VTEC渦輪增壓技術,有着更高更徹底的燃燒效率;

●帶電動廢氣門的高功率渦輪增壓以及雙進排氣VTC,告別渦輪遲滯;

●全系標配發動機節能自動啟停系統,進一步實現燃油經濟性.

對於一台中型SUV來說,車輛的脫困能力自然要求不低,所以作為一台中型SUV的冠道,在四驅系統方面一點也不馬虎,採用的四驅系統為全路況的Real-Time AWD智能四驅,那麼該如何理解呢?

在通常情況下,車輛處於前輪驅動行駛狀態,這套系統會實時監控發動機扭矩以及各車輪轉速等信息參數。當需要後輪的驅動力時,电子系統就會將動力分配給後輪,得到一定的脫困能力和爬坡能力,比我們平常熟悉的適時四驅系統智能上不少。

▲IDM多路況駕駛適應系統

擁有一套完善優秀的四驅系統還不夠,講求越野或是舒適還是得靠底盤,冠道的IDM多路況駕駛適應系統既能滿足城市駕駛也能應對越野路況,總能給人一種最合適的駕駛感受,SpORT OR COMFORT?這是你的選擇。

或許很多人都質疑冠道為什麼沒有7座版本,但從另外一個角度來想,其實這才是明智的選擇。

相比雞肋的第三排,還不如更加寬敞的第二排來得實在,老實說,七座SUV的第三排座椅的利用率是真的低,換作是誰都不願意去第三排座椅坐,不是頂頭就是雙腳放着難受,總之第三排座椅的乘坐體驗是不太好。

就特別心疼老人家坐第三排座椅,為了讓年輕人或小孩子坐前排,通常都是強顏歡笑說不難受,可是作為兒子來說,心裏真的不好受,家裡人多還是選擇7座的MpV更好。

如果你是一名公務人員,經常接待客戶的話,冠道的超寬敞空間能給你的客戶帶來輕鬆的乘坐體驗,加上雙層靜音玻璃、12個音響環繞、後排獨立空調出風口、電動遮陽簾以及超大的全景天窗,這些處處都能給你重要的客戶或長輩帶來與眾不同的體驗。

當然,冠道有着大容量滑道式對開手扶箱,想一想从里面拿出一份資料給客戶看的情景,會心一笑。

冠道採用了本田CONCEpT D概念車的設計理念,什麼?你不知道CONCEpT D長啥樣?下面放圖希望大家都能HOLD住…

從CONCEpT D的設計理念中看,近來本田上市的車型都有着其中一些設計元素,從外貌上更新換代,也能猜到了本田往後推出車型的外觀設計方向。

近兩年,在前臉的設計上大家都喜歡將大燈總成和中網格柵連接在一起,這樣更顯得前衛一些。冠道基於CONCEpT-D的原型打造,我們不難看出有不少共同之處,最令人喜歡的莫過於就是全系LED的燈光,處處彰顯着高端大氣的形象。

足以可以用“迷人”兩個字來形容冠道的鷹翼式全LED前大燈,另外還搭配了ACL主動轉向照明系統,根據車輛的轉向,調節燈光動態,減少了行駛中的“盲區”,增加轉彎時的安全。

這樣的外觀設計,你覺得能支撐起冠道之名嗎?

冠道帶着洪荒之力,

從SUV戰場中突圍,

你期待嗎?

總結:

本田一向以緊湊型轎車和SUV打天下,如今冠道的推出,不斷完善本田SUV家族的矩陣,雖說冠道的起步定價高,但未來將會推出1.5T發動機版本的冠道,價格會更加親民一些,而一款優質的SUV車型擺在你眼前,不好好珍惜,又更待何時呢?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

※回頭車貨運收費標準

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

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

分類
發燒車訊

中德電動汽車充電項目取得新進展 第三階段正式啟動

德國Spiegel Institut Mannheim對半公共充電樁用戶的充電和駕駛行為進行了研究,提出了提高充電效率、付費方式便捷化等建議。本研討會的另一重要議題是介紹並啟動項目第三階段的研究工作。作為項目第三階段的主要研究機構,普華永道思略特在研討會上向與會人員介紹了項目第三階段的主要課題內容和部分課題的初步研究成果。

在中德兩國政府以及大眾汽車、寶馬、戴姆勒、北汽的大力支持下,“中德電動汽車充電項目”於2016年11月8日在北京召開了第二階段總結暨第三階段啟動會。來自相關政府部門、行業協會、電力企業、中德車企和研究機構的代表出席了會議。國家發改委產業協調司机械裝備處處長吳衛和德國聯邦環境、自然保護、建築和核安全部主管排放控制,設備安全與交通司副司長Dr. Norbert Salomon出席會議並致辭。

“中德電動汽車充電項目”第二階段於2015年3月在北京啟動,於2015年12月底完成。項目選取北京地區住宅小區的公共停車區域、寫字樓、政府機關事業單位以及公共商業物業等(半)公共領域開展充電解決方案研究。參与項目運營的電動汽車包括奧迪 A3 e-tron、北汽EV200、大眾汽車electric up!、寶馬i3、奔馳Smart ED、華晨寶馬之諾1E 和騰勢。

“中德電動汽車充電項目”第二階段針對(半)公共領域充電開展了三個課題的研究,即“電動汽車用戶信息研究”、“半公共區域電動汽車充電設施商業模式實證研究”和“基於電動汽車發展的北京市(半)公共區域充電地點選擇和可行性分析”。清華大學、中國汽車技術研究中心以及德國Spiegel Institut Mannheim作為課題研究機構,在會上分別彙報了研究成果。

清華大學研究團隊以北京為例開展研究,得出的基本結論是在中國推廣半公共充電有其可行性。此外,通過對車位及充電設施使用開放度的分析,研究團隊認為,在保證合理商業運營及管理模式的前提下,對寫字樓、公共商業物業甚至是政府及事業單位中低峰時段的車位加以利用也有其可行性,值得积極探索。

中國汽車技術研究中心研究團隊從充電基礎設施商業運營模式角度,建議政府適時出檯面向運營環節的補貼、停車費用減免等政策,使半公共充電成為私人充電的有效補充和替代。同時要鼓勵運營商积極創新、嘗試新型業務和商業模式,通過擴展業務範圍及實現與其他相關業務的協同發展來拓寬收入來源,有效縮短投資回收周期。同時,中國汽車技術研究中心研究團隊也提出在半公共區域單獨報裝充電設施、建設充電專屬車位等其他相關建議。

德國Spiegel Institut Mannheim對半公共充電樁用戶的充電和駕駛行為進行了研究,提出了提高充電效率、付費方式便捷化等建議。

本研討會的另一重要議題是介紹並啟動項目第三階段的研究工作。作為項目第三階段的主要研究機構,普華永道思略特在研討會上向與會人員介紹了項目第三階段的主要課題內容和部分課題的初步研究成果。

項目第三階段的研究課題主要圍繞未來長里程電動汽車的充電需求及其與環境的相互影響。課題分為六大模塊:長里程電動車需求預測、消費者充電需求及充電行為分析、相關政策法規及技術參數分析、電動汽車發展與電力供應的相互影響、電動汽車發展對住建行業的主要影響,以及充電基礎設施發展分析等。

其中,普華永道思略特在研討會上針對“電動汽車發展與電力供應的相互影響”模塊的一些初步成果也進行了彙報與討論。普華永道思略特分析,由於中國呈現電力過剩的特點,電動汽車不但不會對發電端造成壓力,還能消耗過剩電能。從用電負荷分析,在無序充電的情景下,2020~2025年電動汽車引起的用電負荷增加量佔全國裝機量的比例較少,在全國層面造成的影響較小;當電動汽車佔比達到較高水平時,部分省市峰值用電負荷將顯著增加,為電網帶來一定壓力。另外,隨着電動汽車的發展,部分小區將出現配電系統升級的需求。

針對電網如何能夠更好地支持電動汽車產業的發展,普華永道思略特給出了三點建議:建立跨行業溝通平台,推動各利益相關方的合作,积極促進各方達成共識並提高資源利用效率;更好的發揮價格指導作用,激勵消費者,並加快發展智能化、信息化技術,實現有序充電;研究制定傳導機制,解決因電動汽車發展帶來的配電網備擴容成本問題,確保有效傳遞電力企業或者產權方承擔的成本增加。

最後,中德雙方均對“中德電動汽車充電項目”第二階段研究成果表示肯定,並期待第三階段的研究成果能夠更加豐富。中德兩國政府將會繼續支持中德電動汽車充電項目的持續推進。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

※回頭車貨運收費標準