1、什么是WebService?
WebService是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的交互操作的应用程序。Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。Web Service是自描述、 自包含的可用网络模块, 可以执行具体的业务功能。Web Service也很容易部署, 因为它们基于一些常规的产业标准以及已有的一些技术,诸如标准通用标记语言下的子集XML、HTTP。Web Service减少了应用接口的花费。Web Service为整个企业甚至多个组织之间的业务流程的集成提供了一个通用机制。
2、WebService应用场景?
(1)异构系统(不同的开发语言)的整合:例如,在一个企业内部,可能有多个部门使用不同的系统和编程语言。通过使用Webservice,这些系统可以互相通信并共享数据。
(2)不同客户端的整合:例如,一个网站可能需要同时支持浏览器、手机端(Android/iOS)、微信等不同平台的访问。通过使用Webservice,可以在后端实现统一的数据处理和业务逻辑,并为不同客户端提供接口调用。
(3)软件集成和复用:例如,气象局可以通过Webservice向天气查询网站提供实时天气数据。这种情况下,气象局作为服务端,提供数据服务;天气查询网站作为客户端,通过调用Webservice来获取数据。
3、java怎么对接WebService呢?
在Java中,我们可以使用不同的方式来对接外部系统提供的Web服务接口。以下是几种常见的方法:
(1)使用JAX-WS(Java API for XML Web Services):JAX-WS是Java EE的一部分,它提供了一种简单但强大的方式来开发基于SOAP的Web服务。您可以使用wsimport
工具来生成客户端代理代码,该代码可用于调用外部Web服务的方法。下面是一个简单的示例:
wsimport -s src -d build -p com.example http://www.example.com/YourService?wsdl
上述命令将根据WSDL文件生成客户端代码,并包含在指定的包中。一旦代码生成完成,您可以像在本地调用本地方法一样调用外部Web服务的方法。
(2)使用第三方库(例如CXF、Axis等):除了JAX-WS之外,还有许多第三方的Java Web服务库可以帮助您对接外部系统提供的Web服务接口。比如Apache CXF和Apache Axis都提供了强大的Web服务客户端和服务端库。您可以根据自己的喜好和需求选择合适的库进行开发。
在实际应用中,您需要考虑以下几点:
-
安全性:外部Web服务接口可能需要认证,您需要了解如何在Java中处理认证信息,如用户名/密码、密钥等。
-
异常处理:调用外部Web服务时可能会出现各种异常情况,例如网络中断、超时等。您需要了解如何在客户端代码中处理这些异常。
-
数据传输格式:Web服务接口通常支持多种数据传输格式,如XML、JSON等。您需要了解如何在Java中处理这些数据格式。
(3)使用Spring框架提供的WebServiceTemplate类。WebServiceTemplate类提供了一种简单而灵活的方式来调用Web服务,并且集成了许多常见的Web服务调用需求,如消息处理、异常处理等。
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
public class WebServiceClient {
public static void main(String[] args) {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
// 设置Web服务地址
webServiceTemplate.setDefaultUri("http://www.example.com/YourService");
// 设置编组器和解组器
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.example.yourpackage"); // 设置上下文路径,用于识别要编组/解组的类
webServiceTemplate.setMarshaller(marshaller);
webServiceTemplate.setUnmarshaller(marshaller);
// 构造请求数据
YourRequestObject request = new YourRequestObject();
// 调用外部Web服务接口
YourResponseObject response = (YourResponseObject) webServiceTemplate.marshalSendAndReceive(request);
// 处理响应数据
// ...
}
}
在上述示例中,我们使用了Jaxb2Marshaller作为编组器和解组器,并设置了要编组/解组的目标类的上下文路径。您需要将"com.example.yourpackage"替换为实际的包路径,以便编组/解组器能够识别请求和响应对象。这个上下文路径通常是您生成的Web服务客户端代码的包路径。
但经过查找资料,并进行测试与尝试。我最终选择的是使用hutool工具包所提供的方法,我也推荐此方法。
3.1 自己编写一个WebService服务端
我这里方便测试,所以编写了一个服务端
3.1.1 代码
package com.webservice.server;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author ZhaoShuHao
* @Date 2023/11/15 16:16
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User
{
//姓名
private String name;
//性别
private String sex;
//年龄
private int age;
}
package com.webservice.server;
/**
* @Author ZhaoShuHao
* @Date 2023/11/15 16:16
*/
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService(targetNamespace = "http://service.cn.com/")
public interface UserService
{
/**
* 1.在类上添加@WebService注解,代表发布一个WebService服务。
* 2.给类添加上@WebService注解后,类中所有的非静态方法都将会对外公布。
* 3.如果希望某个方法不对外公开,可以在方法上添加@WebMethod(exclude=true),阻止对外公开。
* 4.如果一个类上,被添加了@WebService注解,则必须此类至少有一个可以公开的方法,否则将会启动失败。
* protected、private、final、static方法不能对外公开。
* 5.@targetNamespace 设置命名空间,默认包名,取反
*/
@WebMethod
public User getUserInfo(@WebParam(name = "name", targetNamespace = "http://service.cn.com/") String name,
@WebParam(name = "sex", targetNamespace = "http://service.cn.com/") String sex,
@WebParam(name = "age", targetNamespace = "http://service.cn.com/") int age);
}
package com.webservice.server;
/**
* @Author ZhaoShuHao
* @Date 2023/11/15 16:17
*/
public class UserServiceImpl implements UserService
{
@Override
public User getUserInfo(String name,String sex,int age)
{
User user = new User(name,sex,age);
return user;
}
}
package com.webservice.server;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
/**
* @Author ZhaoShuHao
* @Date 2023/11/15 16:18
*/
public class ServerTest
{
public static void main(String[] args)
{
//发布服务的工厂
JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
//设置服务的地址
factory.setAddress("http://127.0.0.1:9999/test");
//设置服务类
factory.setServiceBean(new UserServiceImpl());
//发布服务
factory.create();
System.out.println(("发布服务成功,wsdl地址是:http://127.0.0.1:9999/test?wsdl"));
}
}
3.1.2 运行结果
wsdl文件格式如下:
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://server.webservice.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns2="http://schemas.xmlsoap.org/soap/http" xmlns:ns1="http://service.cn.com/" name="UserServiceImplService" targetNamespace="http://server.webservice.com/">
<wsdl:import location="http://127.0.0.1:9999/test?wsdl=UserService.wsdl" namespace="http://service.cn.com/"> </wsdl:import>
<wsdl:binding name="UserServiceImplServiceSoapBinding" type="ns1:UserService">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getUserInfo">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="getUserInfo">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getUserInfoResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="UserServiceImplService">
<wsdl:port binding="tns:UserServiceImplServiceSoapBinding" name="UserServiceImplPort">
<soap:address location="http://127.0.0.1:9999/test"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
3.2 编写客户端
3.2.1代码
package com.webservice.client;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.webservice.SoapClient;
import org.w3c.dom.Document;
import javax.xml.xpath.XPathConstants;
/**
* @Author ZhaoShuHao
* @Date 2023/11/15 16:20
*/
public class ClientTest
{
public static void main(String[] args)
{
//设置webservice服务地址
SoapClient client = SoapClient.create("http://127.0.0.1:9999/test?wsdl")
// 设置要请求的方法,传入对应的命名空间
.setMethod("getUserInfo", "http://service.cn.com/")
// 设置参数
.setParam("name", "张三")
.setParam("sex", "男")
.setParam("age", 23);
// 发送请求,参数true表示返回一个格式化后的XML内容
String result = client.send(true);
System.out.println(result);
System.out.println("----------------------------");
// 返回内容为XML字符串,可以配合XmlUtil解析这个响应
Document docResult = XmlUtil.readXML(result);
Object name = XmlUtil.getByXPath("//return//name", docResult, XPathConstants.STRING);
Object sex = XmlUtil.getByXPath("//return//sex", docResult, XPathConstants.STRING);
Object age = XmlUtil.getByXPath("//return//age", docResult, XPathConstants.STRING);
System.out.println("name = " + name);
System.out.println("sex = " + sex);
System.out.println("age = " + age);
}
}
3.2.2 运行结果
3.3 使用图形化工具SoapUI进行测试
下载地址:The World’s Most Popular API Testing Tool | SoapUI
3.3.1 使用该工具的原因是什么?
我在开发过程中,遇到了用户提供的WebService接口是内网这种情况,而且只能是内网。所以用户只能提供堡垒机得形式,让我调用。那怎么验证我写的接口没问题呢?怎么快速确定用户的返回数据是什么呢?所以我先在本地模拟了一下WebService的客户端与服务端。并且在堡垒机上安装了SoapUI进行测试。确保用户和我的接口均没问题。
3.3.2 安装与使用
1、安装:没什么好说的,直接下一步即可
2、使用
(1)安装完成,页面大概是这样的
(2)我们直接开始调用WebService接口
点击SOAP菜单,输入一个名称(名称随意取)。输入wsdl的地址。点击ok。
左侧菜单出现一个文件夹,打开,双击最后一个
点击运行,在右侧还可以选择格式进行展示
最后,感谢博主的分享:聊聊日常开发中,如何对接WebService协议? - 掘金 (juejin.cn)