文档章节

Web Service 那点事儿(1)

黄勇
 黄勇
发布于 2014/07/01 22:34
字数 1982
阅读 8073
收藏 86

Web Service,即“Web 服务”,简写为 WS,从字面上理解,它其实就是“基于 Web 的服务”。而服务却是双方的,有服务需求方,就有服务提供方。服务提供方对外发布服务,服务需求方调用服务提供方所发布的服务。其实也就是这些了,没有多少高大上的东西。

本文将从实战的角度,描述使用 Java 开发 WS 的工具及其使用过程。

如果说得再专业一点,WS 其实就是建立在 HTTP 协议上实现异构系统通讯的工具。没错!WS 说白了还是基于 HTTP 协议的,也就是说,数据是通过 HTTP 进行传输的。

自从有了 WS,异构系统之间的通讯不再是遥不可及的梦想。比如:可在 PHP 系统中调用 Java 系统对外发布的 WS,获取 Java 系统中的数据,或者把数据推送到 Java 系统中。

如果您想了解更多关于 WS 的那些概念与术语,可以看看下面的百度百科:

http://baike.baidu.com/view/67105.htm

今天我想与大家分享的主题是,如何在 Java 中发布与调用 WS?希望本文能够对您有所帮助!

1. 使用 JDK 发布 WS

第一步:您要做的第一件事情就是,写一个服务接口。

<!-- lang: java -->
package demo.ws.soap_jdk;

import javax.jws.WebService;

@WebService
public interface HelloService {

    String say(String name);
}

在接口上放一个 WebService 注解,说明该接口是一个 WS 接口(称为“Endpoint,端点”),其中的方法是 WS 方法(称为“Operation,操作”)。

第二步:实现这个 WS 接口,在实现类中完成具体业务逻辑,为了简单,我们还是写一个 Hello World 意思一下吧。

<!-- lang: java -->
package demo.ws.soap_jdk;

import javax.jws.WebService;

@WebService(
    serviceName = "HelloService",
    portName = "HelloServicePort",
    endpointInterface = "demo.ws.soap_jdk.HelloService"
)
public class HelloServiceImpl implements HelloService {

    public String say(String name) {
        return "hello " + name;
    }
}

第三步:写一个 Server 类,用于发布 WS,直接使用 JDK 提供的工具即可实现。

<!-- lang: java -->
package demo.ws.soap_jdk;

import javax.xml.ws.Endpoint;

public class Server {

    public static void main(String[] args) {
        String address = "http://localhost:8080/ws/soap/hello";
        HelloService helloService = new HelloServiceImpl();

        Endpoint.publish(address, helloService);
        System.out.println("ws is published");
    }
}

只需使用 JDK 提供的 javax.xml.ws.Endpoint 即可发布 WS,只需提供一个 WS 的地址(address),还需提供一个服务实例(helloService)。

现在您就可以运行 Server 类的 main 方法了,会在控制台里看到“ws is published”的提示,此时恭喜您,WS 已成功发布了!

第四步:打开您的浏览器,在地址栏中输入以下地址:

http://localhost:8080/ws/soap/hello?wsdl

注意:以上地址后面有一个 ?wsdl 后缀,在 Server 类中的 address 里却没有这个后缀。此时,在浏览器中会看到如下 XML 文档:

WSDL

当看到这份 WSDL 文档时,也就意味着,您发布的 WS 服务现在可以被别人使用了。

2. 通过客户端调用 WS

第一步:使用 JDK 提供的命令行工具生成 WS 客户端 jar 包。

JDK 安装目录下有个 bin 目录,里面存放了大量的命令行工具,只要您的 Path 环境变量指向了该路径,就能在命令控制台上使用 JDK 提供的相关命令。

其中,有一个名为 wsimport 的命令行工具,正是用来通过 WSDL 生成 WS 客户端代码的,您只需要输入以下命令即可:

wsimport http://localhost:8080/ws/soap/hello?wsdl
jar -cf client.jar .
rmdir /s/q demo

对以上三行命令解释如下:

  • 第一行:通过 WSDL 地址生成 class 文件
  • 第二行:通过 jar 命令将若干 class 文件压缩为一个 jar 包
  • 第三行:删除生成的 class 文件(删除根目录即可)

最终您将会得到一份名为 client.jar 的 jar 包,将这个 jar 包配置到您的 classpath 中,方便在下面的代码中使用其中的类。

技巧:可以将以上三行命令放入一个 bat 文件中,在 Windows 中双击即可运行。

第二步:写一个 Client 类,用于调用 WS,需要使用上一步生成的 WS 客户端 jar 包。

<!-- lang: java -->
package demo.ws.soap_jdk;

public class Client {

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

        HelloService helloService = service.getHelloServicePort();
        String result = helloService.say("world");
        System.out.println(result);
    }
}

以上这段代码稍微有点怪异,其中 HelloService_Service 是 jar 包中类,可以将其理解为 WS 的工厂类,通过它可以生成具体的 WS 接口,比如,调用 service.getHelloServicePort() 方法,就获取了一个 HelloService 实例,正是通过这个实例来调用其中的方法。

运行 Client 类的 main 方法,就会看到您所期望的结果“hello world”了,不妨亲自尝试一下吧。

可见,这是一个典型的“代理模式”应用场景,您实际是面向代理对象来调用 WS 的,并且这是一种“静态代理”,下面我们来谈谈,如何使用“动态代理”的方式来调用 WS?

其实 JDK 已经具备了动态代理的功能,对于 WS 而言,JDK 同样也提供了很好的工具,就像下面这段代码那样:

<!-- lang: java -->
package demo.ws.soap_jdk;

import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

public class DynamicClient {

    public static void main(String[] args) {
        try {
            URL wsdl = new URL("http://localhost:8080/ws/soap/hello?wsdl");
            QName serviceName = new QName("http://soap_jdk.ws.demo/", "HelloService");
            QName portName = new QName("http://soap_jdk.ws.demo/", "HelloServicePort");
            Service service = Service.create(wsdl, serviceName);

            HelloService helloService = service.getPort(portName, HelloService.class);
            String result = helloService.say("world");
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

此时,只需在本地提供一个 HelloService 的接口,无需 client.jar,直接面向 WSDL 编程,只不过您需要分别定义出 serviceNameportName 这两个东西,最后才能调用 JDK 提供的 javax.xml.ws.Service 类生成 service 对象,它同样是一个工厂对象,通过该工厂对象获取我们需要的 HelloService 实例。貌似这种方式也不是特别动态,毕竟 HelloService 接口还是需要自行提供的。

3. 总结

通过本文,您可以了解到,不仅可以使用 JDK 发布 WS,也可以使用 JDK 调用 WS,这一切都是那么的简单而自然。但需要注意的是,这个特性是从 JDK 6 才开始提供的,如果您还在使用 JDK 5 或更低的版本,那就很遗憾了,您不得不使用以下工具来发布与调用 WS,它们分别是:

当然,发布与调用 WS 的工具不仅仅只有以上这些,而是它们是 Java 世界中最优秀的 WS 开源项目。

本文讲述的 WS 其实是一种 Java 规范,名为 JAX-WS(JSR-224),全称 Java API for XML-Based Web Services,可以将规范理解为官方定义的一系列接口。

JAX-WS 有一个官方实现,就是上面提到的 JAX-WS RI,它是 Oracle 公司提供的实现,而 Apache 旗下的 Axis 与 CXF 也同样实现了该规范。Axis 相对而言更加老牌一些,而 CXF 的前世就是 XFire,它是一款著名的 WS 框架,擅长与 Spring 集成。

从本质上讲,JAX-WS 是基于 SOAP 的,而 SOAP 的全称是 Simple Object Access Protocol(简单对象访问协议),虽然名称里带有“简单”二字,其实并不简单,不相信您可以百度一下。

为了让 WS 的开发与使用变得更加简单、更加轻量级,于是出现了另一种风格的 WS,名为 JAX-RS(JSR-339),全称 Java API for RESTful Web Services,同样也是一种规范,同样也有若干实现,它们分别是:

其中,Jersey 是 Oracle 官方提供的实现,Restlet 是最老牌的实现,RESTEasy 是 JBoss 公司提供的实现,CXF 是 Apache 提供的实现(上文已做介绍)。

可见,CXF 不仅用于开发基于 SOAP 的 WS,同样也适用于开发基于 REST 的 WS,这么好的框架我们怎能错过?

如何使用 CXF 简化我们的 WS 开发?我们下期再见!


系列博文:

Web Service 那点事儿(2) —— 使用 CXF 开发 SOAP 服务 Web Service 那点事儿(3) —— SOAP 及其安全控制

© 著作权归作者所有

共有 人打赏支持
黄勇

黄勇

粉丝 6465
博文 121
码字总数 216155
作品 1
浦东
CTO(技术副总裁)
私信 提问
加载中

评论(19)

zhushh
zhushh

引用来自“zzuqiang”的评论

2. 通过客户端调用 WS 中的第一步 运行后没成功!
我运行不起来,不知道咋办
Ken5233
Ken5233
博文风趣易懂,赞一个!~
lylvgg
lylvgg
很简洁易懂,赞一个!
c
cuser

引用来自“JFinal”的评论

目前看过的最WS解释最简版本,赞一个
jfinal也有ws服务发布功能吧?
c
cuser
好文
走位风骚闪着腰
走位风骚闪着腰
如果可以画个图来解释下总结部分就完美了
12叔
12叔
搬砖大半年了 还没用过 ws 一直用http json 来调用 这2者有啥区别不 啥时候必需用ws
黄勇
黄勇

引用来自“abel533”的评论

Client代码中的这一行:
HelloService_Service service = new HelloService_Service();

难道不需要写成下面这样就能执行吗?
HelloService_Service service = new HelloService_Service(new URL("http://localhost:8080/ws/soap/hello"));

我这儿执行不了。。
不需要指定 namespace,因为 jar 包里已经指定了。
Liuzh_533
Liuzh_533
Client代码中的这一行:
HelloService_Service service = new HelloService_Service();

难道不需要写成下面这样就能执行吗?
HelloService_Service service = new HelloService_Service(new URL("http://localhost:8080/ws/soap/hello"));

我这儿执行不了。。
Liuzh_533
Liuzh_533
好!
使用 CXF 开发 REST 客户端调用问题

@黄勇 你好,想跟你请教个问题: Web Service 那点事儿(4)—— 使用 CXF 开发 REST 客户端调用出现异常: javax.ws.rs.NotAuthorizedException: HTTP 401 Unauthorized 好像是没有授权认证!...

simplehpt
2015/02/13
932
0
黄勇/smart-framework

Smart Framework 简介 1. 它是一款轻量级 Java Web 框架 内置 IOC、AOP、ORM、DAO、MVC 等特性 基于 Servlet 3.0 规范 使用 Java 注解取代 XML 配置 2. 它使应用充分做到“前后端分离” 客户...

黄勇
2013/09/23
0
0
我的友情链接

新浪硬件 3GP手机视频下载 btchina seven 陈皓的个人专栏 《Java程序员,上班那点事儿》的那点事儿 李天平 Java究竟怎么玩 豆子空间 子 孑 xql888 ITMOV旗舰 Simon Xiao 肖舸的blog 我的数据...

leizhimin
2017/11/22
0
0
System.IO系列:局域网内多线程使用命名管道在进程之间通信实例

有关管道的基本用法请看System.IO之使用管道在进程间通信 (System.IO.Pipes使用)。 本文介绍命名管道使用实例,文中例子是几个客户端都通过一台服务器获得新生成的int类型id。 服务器端功能...

长平狐
2012/06/08
220
0
Json那点事儿

1.JSON介绍 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,JSON以key-value的形式提供了很好的读写,在web开发中之前用过xml来进行数据的交互和传输, 但xml的数据结构比较复...

陈小扁
2016/04/10
108
1

没有更多内容

加载失败,请刷新页面

加载更多

常用缓存淘汰算法

LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。 LRU(Least recently used,最近最少使用)算...

wangmarke
4分钟前
0
0
linux查看系统配置,例如一级缓存总大小、一级缓存行大小

chuqq@chuqq-vb:~$ getconf -a|grep CACHELEVEL1_ICACHE_SIZE 32768LEVEL1_ICACHE_ASSOC 8LEVEL1_ICACHE_LINESIZE 64LEVEL1_DCACHE_SIZE ......

chuqq
7分钟前
0
0
全职ui设计师岗位需要具备哪些工作技能

好的UI设计不仅是让软件变得有个性有品位,还要让软件的操作变得舒适简单、自由,充分体现软件的定位和特点。Ui设计师可以让网页变的更美,让图片变的更真实,而今,ui设计师成了一个公司不可...

纤纤郡主
7分钟前
0
0
分布式之数据库和缓存双写一致性方案解析

先做一个说明,从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即...

微笑向暖wx
11分钟前
0
0
正则验证整数或保留小数一位

if (!Regex.IsMatch(body.Quota.ToString(), "^[0-9]+([.][0-9]{1})$")) {}

Lytf
12分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部