關於webservice框架CXF的總結


  首先,先說一下webservice的優點吧,websevice最大的優點就是可以跨平台跨語言遠程調用,就是你在webservice平台上用java寫了一個api發布了,其他象用C++,paython寫的平台也能通過webservice調用你寫的api,同樣反過來也行的通。現在主流的webservice框架有Apache Axis1、Apache Axis2、Codehaus XFire、Apache CXF、sun JAX-WS(最簡單、方便)等等,我接觸到的就是Axis2和CXF,感覺CXF要比Axis2簡潔,方便使用一點,https://www.cnblogs.com/ruiati/p/6640287.html  這位老哥對現在較為流行的webservice框架進行了對比,有興趣的可以看看。好了接下來開始總結webservice知識和CXF框架。(因為樓主之前沒有接觸過webservice,所以會從最基本的開始)。

1.webservice組成

  webservice由XML+XSD,SOAP和WSDL組成。

  1.1 xml+xsd

  webservice通過xml來發送數據,但是由於xml並不能明確定義數據格式,而不同平台之間的數據類型可能不一致,可能導致接受數據出現錯誤,所以,不同平台之間傳輸數據時需要統一數據規范,以統一的規范發送數據,再根據規范接受數據,這樣就解決了傳輸數據類型問題。

  1.2 soap

  SOAP(simple object  access protocal)使用基於XML的數據結構超文本傳輸協議(HTTP)來傳輸數據。SOAP協議 = HTTP協議 + XML數據格式。

  1.3 wsdl

  wsdl:Web Service Description Language,即網絡服務描述語言,用來告知使用或者准備使用的群體,該webservice接口的地址,需要傳輸什么內容,會返回什么內容,會調用那個方法等詳細信息。客戶端要調用一個WebService服務之前,要知道該服務的WSDL文件的地址。 WebService服務提供商可以通過兩種方式來暴露它的WSDL文件地址:1.注冊到UDDI服務器,以便被人查找;2.直接告訴給客戶端調用者。

  1.4  SEI(WebService EndPoint Interface)

  SEI是web service的終端接口,就是WebService服務器端用來處理請求的接口。

2.CXF框架

  這里我們只是寫一下CXF發布服務和創建客戶端的大概流程,不整合其他框架,只使用CXF。

  2.1創建服務端

  首先,創建一個maven項目(省的手動導包),jdk最好用1.7的,然后新建一個接口和其實現類,添加一個方法,重點是在准備發布的接口和其實現類上添加@webservice注解,標明這是要發布的接口。

 

 

 

 

 

   例如,我在接口中添加了兩個方法,一個直接返回信息,一個做判斷后返回。

  然后,我們需要發布已經寫好的接口,首先我們要新建一個類,為方便理解命名為server。發布接口有兩種方式,一種為Javax.xml.ws包下的Endpoint,是java自帶的發布webservice的類,直接用該類的publish方法發布接口,發布的具體地址自己定義;另一種為org.apache.cxf.jaxws包下的JaxWsServerFactoryBean,是cxf的,可以設置要發布的地址,接口類,實現類,還可以添加輸入輸出攔截器,用攔截器可以實現接口的安全驗證,添加白名單等操作。

 

 

  這樣服務端基本就配置完了,對了,還要在maven中添加依賴,具體依賴如下。

       <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-core</artifactId>
            <version>3.1.5</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.1.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.1.5</version>
        </dependency>

  

  然后我們啟動tomcat,在瀏覽器上粘貼上我們定義的地址,並在后邊添加?wsdl后綴,如果能夠正常打開,看到service名稱地址等,說明我們發布成功。

 

 

  

  2.2 創建客戶端

  在我們創建客戶端前,需要下載CXF框架,我們需要用到其中的wsdl2java工具,去CXF官網下載就可以,具體下載過程不再贅述,要注意的是下載完需要配置環境變量,將其添加到path中。

  現在我們新建一個maven項目,為客戶端,我們創建客戶端需要根據服務端發布的wsdl來生成,所以,首先我們需要啟動之前的server端,然后在客戶端項目中找到要生成文件的位置,在命令行中打開要生成文件的位置,用wsdl工具生成所需文件。

 

 

 

  

   若運行之后,如上圖所示,表示成功生成了客戶端代碼,生成文件如下圖所示。

 

 

  接下來,新建一個類,名為client,在其中new一個webservice客戶端類,根據客戶端類生成接口類,根據接口類來調用我們所需方法。

 

public class Client {
    public static void main(String[] args) {
        HelloWorldServiceService helloworldServiceService =new HelloWorldServiceService();

        HelloWorldService helloworldService = helloworldServiceService.getHelloWorldServicePort();

        org.apache.cxf.endpoint.Client client = ClientProxy.getClient(helloworldService);
        client.getOutInterceptors().add(new AddHeaderInterceptor("lili","123"));//自定義輸出攔截器
        client.getInInterceptors().add(new LoggingInInterceptor());//接收數據日志攔截器
        client.getOutInterceptors().add(new LoggingOutInterceptor());//發送數據日志攔截器

//        List<String> nums = new ArrayList<String>();
//        nums.add("一號");
//        nums.add("二號");
//        nums.add("三號");
//        nums.add("六號");
//        for (String num:nums
//             ) {
//            System.out.println(helloworldService.hi(num));
//        }

        List<User> users = new ArrayList<User>();
        users.add(new User("麗麗","123"));
        users.add(new User("花花","123"));
        users.add(new User("菲菲","123"));
        for (User user:users
             ) {
            Authority au = helloworldService.judgAuthority(user);
            System.out.println(au);
        }
    }
}

 

  然后運行客戶端main方法即可看到運行結果。

  這是client端的輸出,因為我們這是簡單測試,所以在server端方法的實現中直接寫死了驗證,用戶名必須是“麗麗”或者“菲菲”密碼都必須是123,而在client端我們第一個和第三個測試例子正確,第二個不正確,所以客戶端的返回如下圖。

 

   這是server端輸出,server端我們讓他輸出他所接收到的內容。如下圖。

 

 

   2.3 創建攔截器

  攔截器是webservice進行驗證或過濾的重要方式,通過攔截器可以進行用戶名密碼驗證(當然,你也可以在接口內部實現用戶名密碼驗證,但是攔截器驗證實在接受數據之前進行了攔截驗證,更為安全嚴謹一些),ip驗證等等,也是webservice保證接口安全的重要方式。

  CXF的攔截器主要有四種,客戶端的輸入攔截器,輸出攔截器,服務器端的輸入攔截器,輸出攔截器,它們的總體流程是這樣的,客戶端輸出攔截器——>服務端輸入攔截器——>服務端輸出攔截器——>客戶端輸入攔截器。

  首先我們可以先添加日志攔截器,給客戶端服務端都加上輸入輸出攔截。主要方法為:getInInterceptor().add(要添加的攔截器),getOutInterceptor().add(要添加的攔截器)。

 

 

 

   

  然后啟動服務端,運行客戶端,會出現以下內容:

 

 

 

   上圖是客戶端的日志記錄,可以詳細看到客戶端發送接收數據的詳細情況,服務端同理,不再貼了。

  現在我們定義一個驗證用戶名密碼的攔截器,分別在客戶端和服務端添加輸出攔截器和輸入攔截器。

  首先在客戶端天界一個輸出攔截器,AddHeaderInterceptor,添加頭信息的攔截器,用來給發送的數據的頭部,添加用戶名密碼,方便服務端驗證。注意,實際操作中,怎么驗證,要服務端和客戶端雙方溝通,協商好通信驗證的內容方式。

 

 

public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage> {

    private String userName;
    private String password;

    public AddHeaderInterceptor(String userName, String password) {
        super(Phase.PREPARE_SEND);//這里的PREPARE_SEND表示在准備發送之前進行攔截
        this.userName=userName;
        this.password=password;
    }

    public void handleMessage(SoapMessage soapMessage) throws Fault {
        List<Header> headers = soapMessage.getHeaders();
        //因為發送的數據是xml格式的,所以此處是通過添加節點的方式添加用戶名密碼
        Document document = DOMUtils.createDocument();
        Element element = document.createElement("Auth");
        Element uElement = document.createElement("userName");//添加一個userName節點
        Element pElement = document.createElement("password");//添加一個password節點
        uElement.setTextContent(userName);//將用戶名填寫在節點中
        pElement.setTextContent(password);//將密碼填寫在節點中
        element.appendChild(uElement);
        element.appendChild(pElement);
        headers.add(new Header(new QName("auth"),element));
    }
}

  

  客戶端添加完成之后,同理,我們在服務端添加進行驗證的攔截器。

 

public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {


    public MyInterceptor() {
        super(Phase.PRE_INVOKE);//調用方法前調用自定義攔截器
    }

    public void handleMessage(SoapMessage soapMessage) throws Fault {
        List<Header> headers = soapMessage.getHeaders();
        if (headers==null||headers.size()==0){
            throw new Fault(new IllegalArgumentException("頭部為空,請填寫完整"));
        }
        
        //根據節點來讀取數據
        Header header = headers.get(0);
        Element element = (Element) header.getObject();
        NodeList uList = element.getElementsByTagName("userName");
        NodeList pList = element.getElementsByTagName("password");

        if (uList.getLength()!=1){
            throw new Fault(new IllegalArgumentException("用戶名格式不正確"));
        }
        if (pList.getLength()!=1){
            throw new Fault(new IllegalArgumentException("密碼格式不正確"));
        }
        String userName = uList.item(0).getTextContent();
        String password = pList.item(0).getTextContent();

            if (!"lili".equals(userName)||!"123".equals(password)){
                throw new Fault(new IllegalArgumentException("用戶名密碼不正確"));
            }
    }
}

  

  為了方便,我們直接寫死用戶名密碼,接下來我們測試一下。

  首先,測試一個錯誤的用戶名密碼,即用戶名不為“lili”或者密碼不為“123”,比如“feifei”,“123”

 

 

 

 

   

  從以上兩圖可以看到,客戶端在接受完第一條返回值后就報了用戶名密碼錯誤的異常,服務端也是在接受完第一條數據后就報了異常,說明攔截器成功了。

  將客戶端用戶名密碼改為正確的用戶名密碼后再次進行測試,結果正常。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM