热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

WebService案例入门(基础篇)

Webservice:跨语言跨平台的远程调用技术。Webservice即web服务,它是一种跨编程语言和跨操作系统平台的远程调用技术即跨平台远程调用技术。在做企业整体信息化时,企业

[版权申明:本文系作者原创,转载请注明出处]
文章出处:http://blog.csdn.net/sdksdk0/article/details/52106690
作者:朱培 ID:sdksdk0 邮箱: zhupei@tianfang1314.cn


一、简介

Webservice:跨语言跨平台的远程调用技术。Web service 即web服务,它是一种跨编程语言和跨操作系统平台的远程调用技术即跨平台远程调用技术。
JAVA 中共有三种WebService 规范,分别是JAX-WS(JAX-RPC)、JAXM&SAAJ、JAX-RS。
webService三要素:soap、wsdl、uddi

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 服务规范.

二、应用场景

在做企业整体信息化时,企业中一般都或多或少的存在一些既存系统,这些各种各样的系统不可能全部推翻,重新规划和开发,因为很多供应商在某一领域也做的很专业,博众家之长并进行集成应该是一个比较现实和可取的做法。各个系统之间通过WebService进行集成,不仅缩短了开发周期,降低了风险,还减少了代码复杂度,并能够增强应用程序的可维护性,因为webservice支持跨平台且遵循标准协议(soap)。

将一个软件的功能以webservice方式暴露出来,达到软件重用。例如上边分析的天气预报,将天气查询功能以webservice接口方式暴露出来非常容易集成在其它系统中;再比如一个第三方物流系统将快递查询、快递登记暴露出来,从而集成在电子商务系统中。

三、soap协议

SOAP 是一种网络通信协议
SOAP即Simple Object Access Protocol简易对象访问协议
SOAP 用于跨平台应用程序之间的通信
SOAP 被设计用来通过因特网(http)进行通信
SOAP = HTTP+XML,其实就是通过HTTP发xml数据
SOAP 很简单并可扩展支持面向对象
SOAP 允许您跨越防火墙

Socket是所有通信的基础也是语言个无关平台无关。
Socket使用的是tcp协议,传输效率高。适合传递大数据高并发场景,高并发的情况需要实现多线程并且使用到线程池,编码复杂。Sockt的高并发框架mina。
Socket只是流的传输,传输的格式需要程序员自己定义。

Webservice使用的是soap协议,soap协议基于http协议的应用层协议,本质就是http+xml。Soap协议是w3c标准,传输效率低。使用传输数据不是太大的场合,也是支持高并发的,受限于web容器。支持soap协议和wsdl两者都是国际通用标准,不需要自定义数据格式,只需要面向对象开发。

四、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中。定义了数据的类型。参数和返回值都在其中定义。

五、天气查询系统(基础)

到这里,对于webservice的基本概念都已经了解了,那么就开始我们愉快的编码步骤吧!这个的话我们需要新建两个java工程,一个做服务端,一个作为客户端。源码可以通过文末的链接下载。

5.1 服务端

1、编写一个SEI,也就是一个接口

 public interface WeatherInterface {

        String queryWeather(String cityName);
    }

2、编写一个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.

3、发布服务。使用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

技术分享
生成好之后我们就可以直接调用了:

1、创建一个服务视图对象
2、从服务试图获得porttype(SEI)对象
3、调用服务端方法
4、打印结果

    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.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);
        }
    }

技术分享

七、区域查询系统

创建区域查询服务系统,对外发布WebService服务,供客户端调用,根据parentid查询区域信息。客户端向服务端传递xml格式数据,服务端向客户端响应xml格式数据。

传递xml数据的原因:

  • 1、跨语言时可能会花费很多时间去调试,如果直接传递xml会节省调试的时间。参数和返回值都是字符串类型,非常简单。
  • 2、如果参数发生变化后,可以不要修改接口,不能重新生成客户端代码。
  • 3、xml格式的数据是跨平台的。

技术分享

实现步骤

- 创建一个java工程。
- 导入mysql数据库驱动及其相关的jar包。
- 创建一个SEI。
- 创建一个SEI实现类,调用dao查询区域列表。
- 发布服务,使用Endpoint的publish方法发布服务。

客户端:

  • 生成客户端调用代码
  • 创建服务视图
  • 从服务视图获得portType
  • 调用服务端方法

7.1 服务端

1、新建一个区域信息接口,AreaModel .java
private String areaid;
private String areaname;
private String parentid;
private String arealevel;
实现其get\set方法

2、新建一个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;

    }

3、写一个区域查询SEI

public interface AreaInterface {

    String queryArea(String area);

}

4、实现其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 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 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();
    }


}

5、发布服务

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="\n" +
                "\n"+
                ""+parentid+"\n"+
                ""+start+"\n"+
                ""+end+"\n"+
                "";
        return  xml;        
    }
}

输出结果:
技术分享

总结:本篇文章关于webservice的内容都是非常非常基础的,里面涉及到的一些协议或者使用方法估计有些人是不知道的,我们一方面需要扩展自己的视野,了解更多的新东西,内心不要对一些自己不是很常见的东西去抵触,有的朋友会说“嗯,你讲的这些东西都太基础了,我们在实际项目中要如何应用”,有的直接是调用第三方的url和参考文档就搞定了,其实是比较方便的,那么我们在使用别人的东西的时候有没有考虑过其底层的实现原理,深入到其骨髓才是真的掌握了,不然我们依然是那种只会复制黏贴、只会盲目的调用各种第三方API来的人了。共勉!下次会带来更加实用的cxf实现jax-ws。欢迎关注!

源码下载:
https://github.com/sdksdk0/WebWeather-BaseDemo-
https://github.com/sdksdk0/AreaWebService

WebService案例入门(基础篇)


推荐阅读
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
author-avatar
黑旦儿
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有