WebService案例入门(基础篇)
[版权申明:本文系作者原创,转载请注明出处]  
文章出处: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服务接口、参数、返回值。 
阅读方法:从下往上读。 
- 先找service节点:每个wsdl中,有且只有一个service节点。也叫服务视图节点。service中有port节点服务端端口。
- 根据port节点的binding属性找binding节点。根据binding节点的type属性找portType节点。
- portType节点就是我们定义的SEI服务的接口类型。Prottype中的operation 节点就是方法名称。
- operation 节点的input就是参数的定义,output就是返回值的定义。
- Input有个属性叫做message,message属性对应message节点。其中有一个element,对应element节点。
- 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<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();
    }
}
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="<?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
WebService案例入门(基础篇)的更多相关文章
- Linux入门基础篇
		Linux入门基础篇 Linux诞生 Linux发行版本说明 Linux官方网站 Linux内核官方网站 比较有名的Linux发行版 虚拟机(Virtual Machine),一个虚拟的系统,安装在系 ... 
- 智普教育Python视频教程之入门基础篇,python笔记
		智普教育Python视频教程之入门基础篇,python笔记 print id()内存地址 type()变量类型 windows命令行下edit命令 python数据类型不需要指定类型 定义hostna ... 
- Java正则表达式入门基础篇
		正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)组成的文字模式,它 用以描述在查找文字主体时待匹配的一个或多个字符串.正则表达式作为 ... 
- CSS快速入门基础篇,让你快速上手(附带代码案例)
		1.什么是CSS 学习思路 CSS是什么 怎么去用CSS(快速上手) CSS选择器(难点也是重点) 网页美化(文字,阴影,超链接,列表,渐变等) 盒子模型 浮动 定位 网页动画(特效效果) 项目格式: ... 
- object-c 入门基础篇
		原地址:http://www.cnblogs.com/moonvan/archive/2011/10/13/2210498.html 一.Objective-C与C的渊源 Objective-C诞生于 ... 
- 牛客SQL刷题第一趴——非技术入门基础篇
		user_profile表: id device_id gender age university province 1 2138 male 21 北京大学 Beijing 2 3214 male ... 
- React入门----基础篇
		React 背景介绍 React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站.做 ... 
- Spring Boot 入门之基础篇(一)
		原文地址:Spring Boot 入门之基础篇(一) 博客地址:http://www.extlight.com 一.前言 Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是 ... 
- Java入门到精通——基础篇之多线程实现简单的PV操作的进程同步
		Java入门到精通——基础篇之多线程实现简单的PV操作的进程同步 一.概述 PV操作是对信号量进行的操作. 进程同步是指在并发进程之间存在一种制约关系,一个进程的执行依赖另一个进程的消 ... 
随机推荐
- 一览Django框架(转载)
			本文面向:有python基础,刚接触web框架的初学者. 环境:windows7 python3.5.1 pycharm专业版 Django 1.10版 pip3 一.Django简介 百度百 ... 
- 从零开始系列之vue全家桶(3)安装使用vuex
			什么是vuex? vuex:Vue提供的状态管理工具,用于同一管理我们项目中各种数据的交互和重用,存储我们需要用到数据对象. 即data中属性同时有一个或几个组件同时使用,就是data中共用的属性. ... 
- Headless Chrome:服务端渲染JS站点的一个方案【上篇】【翻译】
			原文链接:https://developers.google.com/web/tools/puppeteer/articles/ssr 注:由于英文水平有限,没有逐字翻译,可以选择直接阅读原文 tip ... 
- 用ECMAScript4 ( ActionScript3)  实现Unity的热更新 -- 使用原型链和EventTrigger
			原型链是JS的必备,作为ECMAScript4,原型链也是支持的. 特别说明,ActionScript3是支持完整的面向对象继承支持的,原型链只在某些非常特殊的情况下使用. 本文旨在介绍如何使用原型链 ... 
- [HNOI 2008]玩具装箱
			Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压 缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1.. ... 
- [HNOI2012]与非
			题目描述 NAND(与非)是一种二元逻辑运算,其运算结果为真当且仅当两个输入的布尔值不全为真.NAND运算的真值表如下(1表示真,0表示假): 两个非负整数的NAND是指将它们表示成二进制数,再在对应 ... 
- POJ1222熄灯问题
			千年老题,以前用枚举做,现在用高斯消元做 自由元直接做成0即可 #include<cstdio> #include<cstdlib> #include<algorithm ... 
- [bzoj4763]雪辉&[bzoj4812][Ynoi2017]由乃打扑克
			来自FallDream的博客,未经允许,请勿转载,谢谢. cut掉部分题面. 给一个n个点的树,点有点权,有m次询问,每次询问多条链的并有多少种不同的点权以及它的mex mex就是一个集合中最小的没有 ... 
- [APIO2008]
			A.免费道路roads 题意:给定n个点m条边的图,边有黑白颜色,求是否有一个生成树满足恰好有K条黑边,并输出方案. 题解:先加白边,求出必须加的黑边,然后加黑边到K条,剩下的用白边填充. 顺便说说, ... 
- .htaccess rewrite 规则详细说明
			rewrite的语法格式: RewriteEngine On #要想rewrite起作用,必须要写上哦 RewriteBase url-path #设定基准目录,例如希望对根目录下的文件rewrtie ... 
