目录
JWS 简介
Java Web Service 是 Java 语言对 WebService 服务的一种实现,用来开发和发布服务,为 Java 开发者提供便捷发布和调用WebService服务的功能。无需借助任何第三方库。
Java 1.6 开始推出 JWS,在 javax.jws 包下,在线 JDK 文档:https://docs.oracle.com/javase/6/docs/api/。
开发过程十分简单:
1、服务端创建接口
2、服务端创建接口具体实现
3、服务端开启服务
4、客户端调用
编码也十分简单,因为整个 javax.jws 包一共也没多少 API。
因为 webservice 以 xml 格式进行传输数据,同时也会涉及一些 javax.xml 包下的 API。
第一个案例
创建一个服务器项目(Java SE)、同时创建一个客户端项目(Java SE),服务端创建一个接口和其实现类,其中提供数据相加与数据相乘的两个方法,然后对外提供这个数据计算的服务,客户端通过 webService 技术可以直接调用服务端系统中的计算方法。
无论是 Java SE 应用还是 Java Web 应用,对于使用 jws 的 API 都是一样的,这里为了简单以创建 Java SE 项目进行演示。
ws 服务端
新建一个 Java SE 项目如下,名称 web_server,其中的代码结构如下。
1、第一步创建 CalculatorService 接口,这是需要对外提供服务的接口,客户端需要知道其中的内容。
2、第二步创建实现类 CalculatorServiceImpl,这是接口的具体实现,客户端是无法知道其中的内容的。
3、第三步创建 Web_Service 类,用于启动 webService 服务。
具体的 API 已经在注释解释的很详细了。
1、CalculatorService 接口内容如下:
import javax.jws.*;
/**
* Created by Administrator on 2019/1/25 0025.
* 计算器接口
* SEI(Service Endpoint Interface):服务终端接口,即webService提供的服务接口
* SIB(Service Implemention Bean):服务实现类,即webService提供的服务接口的实现类
*
* @javax.jws.WebService : 将 Java 类标记为实现 Web Service,或者将 Java 接口标记为定义 Web Service 接口
* 不过是服务端还是客户端,接口上都必须写上此注解
*/
@WebService
public interface CalculatorService {
//加法
//@WebService 中的方法上可以加上 @WebMethod 注解,也可以不加
//@WebMethod 注解写或不写,服务端都会将 @WebSerivce 中的所有方法提供给客户端掉
//写上的好处就是看起来更加直观而已,如同 @Override 重写注解意义,删除也无影响
public float addition(float a, float b);
//乘法
public float multiplication(float a, float b);
}
2、CalculatorServiceImpl 实现类内容如下:
import javax.jws.WebService;
import java.util.logging.Logger;
/**
* Created by Administrator on 2019/1/25 0025.
* SEI(Service Endpoint Interface):服务终端接口,即webService提供的服务接口
* SIB(Service Implemention Bean):服务实现类,即webService提供的服务接口的实现类
*
* @javax.jws.WebService : 将 Java 类标记为实现 Web Service,或者将 Java 接口标记为定义 Web Service 接口
* endpointInterface:终端接口,定义服务抽象 Web Service 协定的服务端点接口的完整名称,通常设置为服务实现类的全路径
* 接口要写,实现类也必须写 @WebService
* @WebService 接口一共提供了以下属性,而且都有默认值,它们将来都会出现在 wsdl 的 xml 文件中
* String name() default "";
* String targetNamespace() default "";
* String serviceName() default "";
* String portName() default "";
* String wsdlLocation() default "";
* String endpointInterface() default "";
*/
@WebService(endpointInterface = "com.lct.web_service.CalculatorService")
public class CalculatorServiceImpl implements CalculatorService {
//日志记录器
public static final Logger logger = Logger.getGlobal();
@Override
public float addition(float a, float b) {
logger.info("加法计算:" + a + " + " + b + " = " + (a + b));
return a + b;
}
@Override
public float multiplication(float a, float b) {
logger.info("乘法计算:" + a + " x " + b + " = " + (a * b));
return a * b;
}
}
3、Web_Service 启动 webService 服务类内容如下:
import javax.xml.ws.Endpoint;
/**
* Created by Administrator on 2019/1/25 0025.
* webServer 启动类
*/
public class Web_Service {
public static void main(String[] args) {
/**webService服务器提供给客户端访问的地址
* 192.168.1.20 为服务器 ip、3333为指定的端口号、web_server 为应用名称、calculator为标识
* 这个地址符合 http 地址即可,为了看起来更像是 web访问,所以才写了应用名,其实 http://192.168.1.20:3333/xxx 都是可以的
*/
String wsUrl = "http://192.168.1.20:3333/web_server/calculator";
/**
* javax.xml.ws.Endpoint 表示一个 web service 终端,这是一个抽象类,其中提供了静态方法可以直接调用
* Endpoint publish(String address, Object implementor)
* address:传输协议的 url 地址;
* implementor(实现者):web service 终端的实现类,因为一个 ws 接口可能会有多个实现类
*/
Endpoint.publish(wsUrl, new CalculatorServiceImpl());
}
}
浏览器访问
webService 服务启动成功之后,根据提供 wsdl 地址,直接通过浏览器即可访问,看到服务端提供的接口(服务),客户端只需要解析这个 xml 文件即可进行服务调用。
注意地址最后的 wsdl 参数必须加上。
此 xml 文件全部内容如下:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<!--
Published by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e.
-->
<!--
Generated by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e.
-->
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://web_service.lct.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://web_service.lct.com/" name="CalculatorServiceImplService">
<types>
<xsd:schema>
<xsd:import namespace="http://web_service.lct.com/" schemaLocation="http://192.168.1.20:3333/web_server/calculator?xsd=1"/>
</xsd:schema>
</types>
<message name="multiplication">
<part name="parameters" element="tns:multiplication"/>
</message>
<message name="multiplicationResponse">
<part name="parameters" element="tns:multiplicationResponse"/>
</message>
<message name="addition">
<part name="parameters" element="tns:addition"/>
</message>
<message name="additionResponse">
<part name="parameters" element="tns:additionResponse"/>
</message>
<portType name="CalculatorService">
<operation name="multiplication">
<input wsam:Action="http://web_service.lct.com/CalculatorService/multiplicationRequest" message="tns:multiplication"/>
<output wsam:Action="http://web_service.lct.com/CalculatorService/multiplicationResponse" message="tns:multiplicationResponse"/>
</operation>
<operation name="addition">
<input wsam:Action="http://web_service.lct.com/CalculatorService/additionRequest" message="tns:addition"/>
<output wsam:Action="http://web_service.lct.com/CalculatorService/additionResponse" message="tns:additionResponse"/>
</operation>
</portType>
<binding name="CalculatorServiceImplPortBinding" type="tns:CalculatorService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="multiplication">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
<operation name="addition">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="CalculatorServiceImplService">
<port name="CalculatorServiceImplPort" binding="tns:CalculatorServiceImplPortBinding">
<soap:address location="http://192.168.1.20:3333/web_server/calculator"/>
</port>
</service>
</definitions>
客户端
调用别人发布的 WebService 服务,例如调用天气预报 WebService 服务、调用门票服务、地图服务等。因为是远程调用服务端的对象方法,所以需要在客户端也生成与服务器一致的服务接口,这通常有如下几种方式:
1、使用第三方如 Apache 的 CXF wsdl2java 工具既能生成服务端代码,也能生成客户端代码;
2、Java JDK 在 bin 目录下提供了一个 wsimport.exe 程序,用于根据 wsdl 文件生成 WebService 客户端代码,然后调用 WebService;
3、直接使用服务提供商的提供的客户端编程 API 接口;
简单的说就是客户端调用 webService 服务器的接口,客户端自己也要有与服务器一致的接口,但是客户端不需要服务端接口的实现类,显然人家服务提供商自然也不会连实现类都提供出来,再者说,如果连接口和实现都提供了,则远程调用就没有意义了,就是再调用自己了。
新建客户端项目(Java SE )如下,其中 CalculatorService 是与服务端一样的接口,Web_service 类用于调用服务器上的方法。
1、CalculatorService 接口内容如下,如果服务端、客户端都是 Java 开发,则完全可以联系服务器开发人员直接把这个接口的代码发过来即可。所以下面的代码与服务端完全是一样的。
import javax.jws.WebService;
/**
* Created by Administrator on 2019/1/25 0025.
* 计算器接口
* SEI(Service Endpoint Interface):服务终端接口,即webService提供的服务接口
* SIB(Service Implemention Bean):服务实现类,即webService提供的服务接口的实现类
*
* @javax.jws.WebService : 将 Java 类标记为实现 Web Service,或者将 Java 接口标记为定义 Web Service 接口
* 无论作为服务端还是客户端都必须写 @WebService 注解
*/
@WebService
public interface CalculatorService {
//加法
public float addition(float a, float b);
//乘法
public float multiplication(float a, float b);
}
2、Web_service 类用于调用 webService 服务,内容如下:
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;
/**
* Created by Administrator on 2019/1/25 0025.
*/
public class Web_service {
//日志记录器
public static final Logger logger = Logger.getGlobal();
public static void main(String[] args) {
try {
/** url:webservice 服务端提供的服务地址,结尾必须加 "?wsdl"*/
URL url = new URL("http://192.168.1.20:3333/web_server/calculator?wsdl");
/** QName 表示 XML 规范中定义的限定名称,QName 的值包含名称空间 URI、本地部分和前缀。
* QName(final String namespaceURI, final String localPart):指定名称空间 URI 和本地部分的 QName 构造方法。
* 如下所示的两个数据都可以浏览器访问服务端时返回 xml 中第一行找到,如:
* <definitions xmlns:wsu=xxxxxxx targetNamespace="http://web_service.lct.com/" name="CalculatorServiceImplService">
*/
QName qName = new QName("http://web_service.lct.com/", "CalculatorServiceImplService");
/**
* Service 对象提供 Web 服务的客户端视图
* Service 作为以下内容的工厂:1、目标服务端点的代理,2、用于远程操作的动态面向消息调用的 javax.xml.ws.Dispatch 实例。
* create(java.net.URL wsdlDocumentLocation,QName serviceName):创建 Service 实例。
* wsdlDocumentLocation : 服务 WSDL 文档位置的 URL
* serviceName : 服务的 QName
*/
Service service = Service.create(url, qName);
/**
* 使用 getPorts 方法可以对服务上可用的端口/接口进行枚举
* getPort(Class<T> serviceEndpointInterface):获取支持指定服务端点接口的对象实例
* serviceEndpointInterface:指定返回的代理所支持的服务端点接口
*/
CalculatorService calculatorService = service.getPort(CalculatorService.class);
float added = calculatorService.addition(100, 80);
float multied = calculatorService.multiplication(2.5F, 100);
logger.info("added:" + added);
logger.info("multied:" + multied);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
调用测试
先运行服务器开启 webService 服务,然后运行客户端看是否能调用服务端上的实现类进行计算,如果可以则说明 webService 服务提供成功。
由上可见完全成功。