webService框架CXF的簡單使用


    最近本來已經將上一個項目交活,全身心投入了另外項目的前端的開發工作。可之前的項目經理通知我,之前的項目需要做一個webService的功能,於是稍微做了一下webService,可是忘了通知我現在的項目經理,所以現在的項目經理以為我在做現在項目的前端工作,結果搞得很不好。然而我還是有私心的,因為目前兩個項目需要使用的技術是我沒有接觸過的,而我的一個臭毛病就是對想做的喜歡做的技術會有莫名的興奮感,每天早上起來的時候想到自己今天要將一個自己不了解的技術應用於工作中,就會很興奮,恨不得立刻開始工作。總之,作為一個技術總結,也還是廢話多謝,將職場經驗寫下:一定要將自己的任務讓現在的負責人知道,即便別人已經告訴你現在的負責人已經知道了,你還是要和他確認一下,否則就有可能你做的兩面不討好。

  廢話不多說,本周的技術要點如下:

  一、webService原理

    webService的有關知識網上太多了,但是我沒有看懂,webService有關的三個要素:SOAP、UDDI 、WSDL ,我只知道了WSDL的使用方法。我所理解的webService如下:

    首先,webService是為了解決什么問題呢?因為我們知道系統中前端可以使用REST接口對后台進行數據請求,但是這是程序內部的數據接口,不可能直接發布給外部讓別人使用url請求的,系統都會對這些開發的接口進行攔截和身份校驗。那么如果我們想在外界獲取到某個系統的數據,就需要webService了。比如天氣信息網站的天氣信息等公開分享的信息,我們都可以使用webService技術來獲取。

    接下來webService是什么原理呢?我們都知道使用java進行接口開發的時候,參數和返回的結果一般會使用到實體類,比如有這樣的一個接口,是通過用戶的名字獲取數據,那么此時的controller的方法可能會是這樣寫:

@RequestMapping(value = {"/list","/checkList"})
  public ResponseResult getUser(User u){
        ResponseResult re = this.createResult(u);
        return re;
    }

    接口中參數User為用戶的實體類,前台傳過來的用戶名傳到后台會自動封裝成User對象。后台接口查詢到數據后,會將數據封裝成ResponseResule對象,傳遞給前台。這樣前台就可以根據傳遞過來的信息展現數據了。

    通常開發的數據接口是前台和后台進行交互,之所以前台可以很方便的和后台進行交互,是因為前台對於參數對象和結果對象是使用JSON進行轉換了,任你后台是什么實體類,在我前台面前一律全是JSON對象。

    但是對於webService的話,並不是前台和后台進行交互,而是后台和后台進行交互。比如系統A的后台語言是java,系統B的后台語言也是java,那么當系統B使用接口對系統A發起請求的時候,也是需要將一個實體對象作為參數傳遞過去,將一個實體對象作為查詢結果進行返回。但是系統B怎么可能知道系統A的這個接口的參數實體對象和結果實體對象的構成呢?而如何讓系統B知道接口中這兩個對象的構成就成為了webService的重點。

    那么webService是怎么實現將系統A的接口的構成告訴給系統B的呢?

    首先webService需要一個服務端和客戶端,很顯然,系統A就是服務端,系統B就是客戶端了。另外這個服務端需要新開一個servlet,以專供進行服務接口的請求。此時系統A會通過webService的服務端發布一個接口,這個接口和程序開發的接口不同之處在於:

    1、這個接口可以在外部訪問,如果這個接口可以對外部共享的話,那么任何人都可以對這個接口進行訪問;

    2、接口的結尾都是?WSDL(好像還有別的可能是實現技術不同,可通過查詢天氣的服務接口查看http://www.webxml.com.cn/zh_cn/weather_icon.aspx

    3、返回的是正常人看不懂的XML文檔。

    這些東西光說是沒用的,直接掛上天氣服務的WSDL服務接口的url路徑:http://www.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl

    這樣系統B在對服務接口進行請求后會獲得一個xml文檔,這個文檔包含了想要請求到數據的前期一切信息。我們可以通過這個文檔構建系統A的接口環境,重建參數對象和結果對象,構成一個客戶端。這樣當我們在對系統A進行數據請求的時候(此時的數據接口不是前面的獲得wsdl的地址,可能放在xml文檔中)就可以通過對象進行數據傳輸了。

    那么問題來了,怎么通過wsdl的這個xml文檔重建接口環境,生成一個webService的客戶端呢?

    其實這個方法有很多種,可以網上去查,我使用的方法是使用編輯器的內置的方法,idea和eclipse應該都有(后面的CXF的具體實現會有體現)。另外jdk的bin中也有一個wsimport.exe,可以進行轉換具體使用方法為:wsimport -keep -p 自定義包名 -d 存放的地址 (wsdl地址)。不過我沒有試過。。。。

 

  二、使用CXF框架構建webService

    CXF是webService的一個框架,可以很簡單方便的搭建一個webService。現在我們做一個demo,具體過程如下:

    1、下載CXF http://cxf.apache.org/

    

 

          

    2、創建項目,將cxf的lib中的所有jar包引入到項目中

    3、創建服務端  

        我所生成的項目結構如下:

                

        其中,HelloWord是個接口,HellowWorldImp是其實現類,Servier用來創建一個服務,User是一個實體類,作為一個結構的參數對象。因此前三個是我們構成webServie服務端所必須的文件。先將三個文件的代碼貼下:

        HelloWorld.java

復制代碼
package com;

import javax.jws.WebService;
import java.util.List;

/**
 * @InterfaceName HelloWorld
 * @Description TODO
 * @Author jyy
 * @Date 2019/7/18 10:45
 * @Version 1.0
 **/
@WebService
public interface HelloWorld {
     String sayHi(String text);
     String getUser(User user);
     List<User> getListUser();
}
復制代碼

        重要的是加上@WebService注解。接口里面的方法類似於controller中url對應的方法,可以理解為這個webService提供了三個接口服務:sayHi,getUser,getListUser。

        HelloWorldImpl.java

復制代碼
package com;

import javax.jws.WebService;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName HelloWorldImp
 * @Description TODO
 * @Author jyy
 * @Date 2019/7/18 10:49
 * @Version 1.0
 **/
@WebService(endpointInterface = "com.HelloWorld", serviceName = "HelloWorldService",portName="HelloWorldServicePort")
public class HelloWorldImp implements HelloWorld {

    @Override
    public String sayHi(String text) {
        System.out.println("sayHi called...");
        return "Hi :" + text;
    }

    @Override
    public  String getUser(User user) {
        System.out.println("sayUser called...");
        return "User:[id=" + user.getId() + "][name=" + user.getName() + "]";
    }

    @Override
    public List<User> getListUser() {
        System.out.println("getListUser called...");
        List<User> lst = new ArrayList<User>();
        lst.add(new User(2, "u2"));
        lst.add(new User(3, "u3"));
        lst.add(new User(4, "u4"));
        lst.add(new User(5, "u5"));
        lst.add(new User(6, "u6"));
        return lst;
    }

}
復制代碼

        標紅的注解是必須的,具體的值可自己配置

        Server.java

復制代碼
package com;

import javax.xml.ws.Endpoint;

public class Server {

    protected Server() throws Exception {
        // START SNIPPET: publish
        System.out.println("Starting Server");
        HelloWorldImp implementor = new HelloWorldImp();
        String address = "http://localhost:8080/helloWorld";
        Endpoint.publish(address, implementor);
        // END SNIPPET: publish
    }

    public static void main(String[] args) throws Exception {
        new Server();
        System.out.println("服務端已啟動");
    }
}
復制代碼

        然后啟動server.java中的main方法,啟動一個服務器。然后在瀏覽器中輸入網址:http://localhost:8080/helloWorld?wsdl,可以看到如下網頁。

        

         此時,服務端搭建成功。

    4、創建客戶端

      另開一個項目,用來模擬系統B

      然后構建客戶端,我是用的idea,內置的構建方法截圖如下:

      

      右鍵項目根目錄,然后點擊下面兩個紅箭頭,出現如下截圖:

      

      將wsdl的url地址填入第一個箭頭所示,第二個為所創建的文件存放的文件夾,第三個是使用什么進行構建,其他的我都沒有安裝,使用的是如圖的方法。完成后,idea會在demo目錄先自動創建如下文件:

      

      記得eclipse可以通過wsdl的xml文檔生成api,應該使用到了這些文件。

 

      假設知道了服務接口的api,那么就知道了怎么去請求了,接下來就需要構建客戶端了。創建一個文件Main.java

      

復制代碼
package client;

import demo.HelloWorld;
import demo.HelloWorldService;

/**
 * @ClassName
 * @Description TODO
 * @Author jyy
 * @Date 2019/7/18 13:30
 * @Version 1.0
 **/
public class Main {
    public static void main(String[] args) {
        HelloWorldService factory = new HelloWorldService();

        // 此處返回的只是遠程WebService的代理
        HelloWorld cxfWebService = factory.getHelloWorldServicePort();
        System.out.println(cxfWebService.sayHi("jyy"));
    }
}
復制代碼

      執行文件后,控制台顯示:Hi :jyy

    至此,服務端和客戶端搭建完成,webService流程演示完畢。

 

  三、將CXF集成到SpringMVC

    想要用於實際項目,就需要和項目中的框架集成,我是用的是SpingMVC。

    1、maven引入

復制代碼
<dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.0.4</version>
</dependency>
<dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.0.4</version>
</dependency>
復制代碼

      需要注意的是版本。我使用的springmvc版本是4,那么CXF需要是3。之前看別人的技術帖子CXF用的版本是2,所以一直報錯。要是報錯,如果代碼沒有問題的話,一定就是CXF的版本引入錯了。切記切記

    2、配置文件中添加bean

<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint id="helloService" implementor="com.zzdc.cxf.CXFWebServiceImpl"  address="/cxfService" />

      注意這里的使用的是項目實際中的文件,所以服務接口路徑和文件和上一個demo中的是不同的。

    3、web.xml中創建一個servlet

復制代碼
<servlet>
      <servlet-name>CXFServlet</servlet-name>
      <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
          <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
      <servlet-name>CXFServlet</servlet-name>
      <url-pattern>/cxf/*</url-pattern>
</servlet-mapping>
復制代碼

    啟動后發布,此時url的地址應該是:localhost:8080/cxf/cxfService?wsdl,也就是由上面配置文件中bean的address和web.xml中的url-pattern所組成,需要注意。

 

第一周技術博客完成!


免責聲明!

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



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