WebService案例入門(基礎篇)


[版權申明:本文系做者原創,轉載請註明出處]
文章出處:http://blog.csdn.net/sdksdk0/article/details/52106690
做者:朱培 ID:sdksdk0 郵箱: zhupei@tianfang1314.cn java


1、簡介

Webservice:跨語言跨平臺的遠程調用技術。Web service 即web服務,它是一種跨編程語言和跨操做系統平臺的遠程調用技術即跨平臺遠程調用技術。
JAVA 中共有三種WebService 規範,分別是JAX-WS(JAX-RPC)、JAXM&SAAJ、JAX-RS。
webService三要素:soap、wsdl、uddimysql

JAX-WS 的全稱爲 Java API for XML-Based Webservices ,早期的基於SOAP 的JAVA 的Web 服務規範JAX-RPC(Java API For XML-Remote Procedure Call).
JAXM(JAVA API For XML Message)主要定義了包含了發送和接收消息所需的API,SAAJ(SOAP With Attachment API For Java,JSR 67)是與JAXM 搭配使用的API,爲構建SOAP 包和解析SOAP 包提供了重要的支持,支持附件傳輸等.
JAX-RS 是JAVA 針對REST(Representation State Transfer)風格制定的一套Web 服務規範.git

2、應用場景

在作企業總體信息化時,企業中通常都或多或少的存在一些既存系統,這些各類各樣的系統不可能所有推翻,從新規劃和開發,由於不少供應商在某一領域也作的很專業,博衆家之長並進行集成應該是一個比較現實和可取的作法。各個系統之間經過WebService進行集成,不只縮短了開發週期,下降了風險,還減小了代碼複雜度,並可以加強應用程序的可維護性,由於webservice支持跨平臺且遵循標準協議(soap)。程序員

將一個軟件的功能以webservice方式暴露出來,達到軟件重用。例如上邊分析的天氣預報,將天氣查詢功能以webservice接口方式暴露出來很是容易集成在其它系統中;再好比一個第三方物流系統將快遞查詢、快遞登記暴露出來,從而集成在電子商務系統中。github

3、soap協議

SOAP 是一種網絡通訊協議
SOAP即Simple Object Access Protocol簡易對象訪問協議
SOAP 用於跨平臺應用程序之間的通訊
SOAP 被設計用來經過因特網(http)進行通訊
SOAP = HTTP+XML,其實就是經過HTTP發xml數據
SOAP 很簡單並可擴展支持面向對象
SOAP 容許您跨越防火牆web

Socket是全部通訊的基礎也是語言個無關平臺無關。
Socket使用的是tcp協議,傳輸效率高。適合傳遞大數據高併發場景,高併發的狀況須要實現多線程而且使用到線程池,編碼複雜。Sockt的高併發框架mina。
Socket只是流的傳輸,傳輸的格式須要程序員本身定義。sql

Webservice使用的是soap協議,soap協議基於http協議的應用層協議,本質就是http+xml。Soap協議是w3c標準,傳輸效率低。使用傳輸數據不是太大的場合,也是支持高併發的,受限於web容器。支持soap協議和wsdl二者都是國際通用標準,不須要自定義數據格式,只須要面向對象開發。數據庫

4、WSDL

Webservice的使用說明書。描述了webservice的服務地址以及webservice服務接口、參數、返回值。
閱讀方法:從下往上讀。
這裏寫圖片描述編程

  1. 先找service節點:每一個wsdl中,有且只有一個service節點。也叫服務視圖節點。service中有port節點服務端端口。
  2. 根據port節點的binding屬性找binding節點。根據binding節點的type屬性找portType節點。
  3. portType節點就是咱們定義的SEI服務的接口類型。Prottype中的operation 節點就是方法名稱。
  4. operation 節點的input就是參數的定義,output就是返回值的定義。
  5. Input有個屬性叫作message,message屬性對應message節點。其中有一個element,對應element節點。
  6. Element節點定義中xsd中。定義了數據的類型。參數和返回值都在其中定義。

5、天氣查詢系統(基礎)

到這裏,對於webservice的基本概念都已經瞭解了,那麼就開始咱們愉快的編碼步驟吧!這個的話咱們須要新建兩個java工程,一個作服務端,一個做爲客戶端。源碼能夠經過文末的連接下載。瀏覽器

5.1 服務端

一、編寫一個SEI,也就是一個接口

public interface WeatherInterface {

        String queryWeather(String cityName);
    }

二、編寫一個SEI實現類,須要實現SEI接口,並且還須要在這個實現類上面添加一個@Webservice註解

@Webservice
    public class WeatherInterfaceImpl implements WeatherInterface {

        public String queryWeather(String cityName) {
            System.out.println("接收到客戶端發送的城市名稱:"+cityName);  
            String result="晴,高溫預警";
            return result;
        }
    }

在這一步,若是你由於webservice的添加註解系統報錯的話,能夠先按照報錯提示的先轉變爲jase-1.5,而後本身再去build path中從新變回你原來許須要的java1.7或者1.8.

三、發佈服務。使用Endpoint的靜態方法publish。

public class WeatherServer {


        public static void main(String[] args) {
            //發佈服務
            Endpoint.publish("http://127.0.0.1:11111/weather", new WeatherInterfaceImpl());
        }

    }

訪問地址:http://127.0.0.1:11111/weather
這裏寫圖片描述

http://127.0.0.1:11111/weather?wsdl中看到portType。
這裏寫圖片描述

看到效果則說明啓動成功了。

5.2 客戶端

對於客戶端,咱們可利用只用java中的wsimport來自動生成客戶端代碼。

使用Wsimport生成客戶端調用代碼,
在jdk的安裝目錄的bin目錄中,有一個wsimport命令。

能夠根據wsdl文檔生成客戶端調用代碼。

新建一個java工程WebServiceClient,而後到這個工程的src目錄下面,在src目錄下經過cmd運行如下命令:(注意空格)

wsimport -s . http://127.0.0.1:11111/weather?wsdl

這裏寫圖片描述
生成好以後咱們就能夠直接調用了:

一、建立一個服務視圖對象
二、從服務試圖得到porttype(SEI)對象
三、調用服務端方法
四、打印結果

public class WeatherClient {


    public static void main(String[] args) {
        WeatherInterfaceImplService  service=new WeatherInterfaceImplService();
        WeatherInterfaceImpl portType=service.getWeatherInterfaceImplPort();
        String result=portType.queryWeather("衡陽");
        System.out.println(result);

    }
    }

這裏寫圖片描述

6、天氣查詢(公網)

剛纔使用的方法是咱們本身定義了,可是每每生活中,咱們須要時時更新的天氣信息,因此這個時候咱們就能夠調用公網來處理了,和前面的同樣,咱們也須要服務端和客戶端。

6.1 服務端

服務端使用第三方的,導入其已經生成好的多個類,cn.com.webxml.這個能夠在我提供的源碼中直接下載。
這裏寫圖片描述

6.2 客戶端

public static void main(String[] args) {
        //建立服務視圖
        //WeatherWebService service=new WeatherWebService();

        URL url = null;
        try {
            url = new URL("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?WSDL");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        QName qName=new QName("http://WebXml.com.cn/", "WeatherWebService");

        Service service=Service.create(url,qName);
        WeatherWebServiceSoap  portType=service.getPort(WeatherWebServiceSoap.class);
                //service.getWeatherWebServiceSoap();

        ArrayOfString arrayOfString=portType.getWeatherbyCityName("衡陽");
        for (String string : arrayOfString.getString()) {
            System.out.println(string);
        }
    }

這裏寫圖片描述

7、區域查詢系統

建立區域查詢服務系統,對外發布WebService服務,供客戶端調用,根據parentid查詢區域信息。客戶端向服務端傳遞xml格式數據,服務端向客戶端響應xml格式數據。

傳遞xml數據的緣由:

  • 一、跨語言時可能會花費不少時間去調試,若是直接傳遞xml會節省調試的時間。參數和返回值都是字符串類型,很是簡單。
  • 二、若是參數發生變化後,能夠不要修改接口,不能從新生成客戶端代碼。
  • 三、xml格式的數據是跨平臺的。

這裏寫圖片描述

實現步驟

- 建立一個java工程。
- 導入mysql數據庫驅動及其相關的jar包。
- 建立一個SEI。
- 建立一個SEI實現類,調用dao查詢區域列表。
- 發佈服務,使用Endpoint的publish方法發佈服務。

客戶端:

  • 生成客戶端調用代碼
  • 建立服務視圖
  • 從服務視圖得到portType
  • 調用服務端方法

7.1 服務端

一、新建一個區域信息接口,AreaModel .java
private String areaid;
private String areaname;
private String parentid;
private String arealevel;
實現其get\set方法

二、新建一個AreaDao.java,用於訪問mysql數據庫中的區域信息,這個數據庫的sql腳本已放到源碼中,讀者可自行下載。就是一個鏈接數據庫的功能。

public List<AreaModel> queryArea(String parentid, int start, int end) {
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        List<AreaModel> areaList = new ArrayList<>();
        try {
            //加載數據庫驅動
            Class.forName("com.mysql.jdbc.Driver");
            //得到connection
            connection = DriverManager.getConnection("jdbc:mysql:///day15", "zp", "a");
            String sql="select *from area where parentid=? limit ?,? ";
            pstmt=connection.prepareStatement(sql);

            pstmt.setString(1,parentid);
            pstmt.setInt(2, start-1);
            pstmt.setInt(3, end-start-1);

            resultSet=pstmt.executeQuery();



            while(resultSet.next()){

                AreaModel model=new AreaModel();
                model.setAreaid(resultSet.getString("areaid"));
                model.setAreaname(resultSet.getString("areaname"));
                model.setArealevel(resultSet.getString("arealevel"));
                model.setParentid(resultSet.getString("parentid"));
                //添加到區域列表
                areaList.add(model);

            }

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            try {
                resultSet.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                pstmt.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                connection.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return areaList;

    }

三、寫一個區域查詢SEI

public interface AreaInterface {

    String queryArea(String area);

}

四、實現其Sei的dao方法。

@WebService
public class AreaInterfaceImpl implements AreaInterface {

    @Override
    public String queryArea(String area) {

        //解析xml查詢條件
        AreaModel model = null;
        try {
            model = parseXml(area);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        AreaDao dao=new AreaDao();
        List<AreaModel> list=dao.queryArea(model.getParentid(), model.getStart(), model.getEnd());
        String result = null;
        try {
            result = list2xml(list);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }



        return result;
    }

    private AreaModel parseXml(String xml) throws DocumentException{

        Document document=DocumentHelper.parseText(xml);
        String parentid=document.selectSingleNode("/queryarea/parentid").getText();
        String start=document.selectSingleNode("/queryarea/start").getText();
        String end=document.selectSingleNode("/queryarea/end").getText();

        AreaModel model=new AreaModel();
        model.setParentid(parentid);
        model.setStart(Integer.parseInt(start));
        model.setEnd(Integer.parseInt(end));
        return model;

    }
    private String list2xml(List<AreaModel> list) throws Exception {
        Document document = DocumentHelper.createDocument();
        //添加以根節點
        Element root = document.addElement("areas");

        for (AreaModel areaModel : list) {
            Element area = root.addElement("area");
            area.addElement("areaid").setText(areaModel.getAreaid());
            area.addElement("areaname").setText(areaModel.getAreaname());
            area.addElement("arealevel").setText(areaModel.getArealevel());
            area.addElement("parentid").setText(areaModel.getParentid());
        }

        return document.asXML();
    }


}

五、發佈服務

public class AreaServer {

    public static void main(String[] args) {
        Endpoint.publish("http://127.0.0.1:11111/area", new AreaInterfaceImpl());
    }
}

經過瀏覽器訪問看到這個界面就說明運行成功了。
這裏寫圖片描述

7.2 客戶端

和以前一樣的方法,使用wsimport來自動生成客戶端代碼。
在java工程的src目錄中運行cmd。
wsimport -s . http://127.0.0.1:11111/area?wsdl

生成好以後以下所示:
這裏寫圖片描述

客戶端進行調用

public class AreaClient {

    public static void main(String[] args) {
        AreaInterfaceImplService service=new AreaInterfaceImplService();

        AreaInterfaceImpl portType=service.getAreaInterfaceImplPort();
        String result=portType.queryArea(getQueryXml("1.1.",1,10));
        System.out.println(result);
    }

    private static String getQueryXml(String parentid,int start,int end){
        String  xml="<?xml version=\"1.1\" encoding=\"utf-8\"?>\n" +
                "<queryarea>\n"+
                "<parentid>"+parentid+"</parentid>\n"+
                "<start>"+start+"</start>\n"+
                "<end>"+end+"</end>\n"+
                "</queryarea>";
        return  xml;        
    }
}

輸出結果:
這裏寫圖片描述

總結:本篇文章關於webservice的內容都是很是很是基礎的,裏面涉及到的一些協議或者使用方法估計有些人是不知道的,咱們一方面須要擴展本身的視野,瞭解更多的新東西,心裏不要對一些本身不是很常見的東西去抵觸,有的朋友會說「嗯,你講的這些東西都太基礎了,咱們在實際項目中要如何應用」,有的直接是調用第三方的url和參考文檔就搞定了,實際上是比較方便的,那麼咱們在使用別人的東西的時候有沒有考慮過其底層的實現原理,深刻到其骨髓纔是真的掌握了,否則咱們依然是那種只會複製黏貼、只會盲目的調用各類第三方API來的人了。共勉!下次會帶來更加實用的cxf實現jax-ws。歡迎關注!

源碼下載:
https://github.com/sdksdk0/WebWeather-BaseDemo-
https://github.com/sdksdk0/AreaWebService

相關文章
相關標籤/搜索