Spring中的Web Service消费者集成(应该被淘汰的技术)
问题
最近需要对接一个老系统的web service接口,我已经有7,8年没有遇到过这种接口了。
思路
先用Spring空项目中的jaxws-maven-plugin插件生成一波web service客户端,然后,集成到现有的SpringBoot3项目中使用就可以了。
生成web service客户端代码
直接使用Consuming a SOAP web service的文章空Spring项目,然后,直接在这个项目使用已经集成好的jaxws-maven-plugin插件生产web service客户端代码即可。
注意:这里需要提前把WSDL文件准备好放在本地。
拉取一下示例代码:
git clone https://github.com/spring-guides/gs-consuming-web-service.git
进入initial
文件夹,修改pom.xml:
具体添加如下内容:
<plugin>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 需要的工程包名 -->
<packageName>com.xx.xxx.wsdl</packageName>
<wsdlFiles>
<!-- 需要解析本地WSDL文件 -->
<wsdlFile>${project.basedir}/src/wsdl/xxxx.wsdl</wsdlFile>
</wsdlFiles>
<sourceDestDir>${sourcesDir}</sourceDestDir>
<destDir>${classesDir}</destDir>
<extension>true</extension>
</configuration>
</plugin>
然后,在这个目录${project.basedir}/src/wsdl/xxxx.wsdl
保持需要对接的WSDL文件,如果开发环境能够正常访问web service的wsdl文件,则可以wsdlUrls替代wsdlFiles,类似配置如下:
<wsdlUrls>
<wsdlUrl>http://localhost:8080/ws/countries.wsdl</wsdlUrl>
</wsdlUrls>
最后,运行./mvnw compile
命令,则可以在target/generated-sources目录找到生成的web service客户端代码。具体在 如下:
将客户端代码集成到SpringBoot项目中
将上述生成在wsdl包项目的客户端代码复制到已有的SpringBoot源代码工程中即可。复制完成后,需要引入spring-boot-starter-web-services
依赖,需要去掉其中的tomcat依赖,以免重复依赖,具体配置如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
完成上面maven依赖后,需要进一步配置spring-boot-starter-web-services
,具体就是配置 Web Service的客户端类和通用配置类:
WsClient.java
package com.xxx.xxxx.wsdl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
/**
* web service客户端
*/
@Slf4j
public class WsClient extends WebServiceGatewaySupport {
public int sxWork(String xml, String xxx){
log.info("消息:{}", uniteWorkXml);
// 这里的SxxxWork类,不过是,之前根据web service服务生成的请求类
SxxxWork sxxxWork = new SxxxWork();
sxxxWork.setArg0(xml);
sxxxWork.setArg1(xxx);
// 这里是关键,使用getWebServiceTemplate()的marshalSendAndReceive方法来调用web service
// 这里请求参数和返回参数,都是依赖 web service服务的接口类定义
return (int) getWebServiceTemplate().marshalSendAndReceive(sxxxWork);
}
}
WsxxxConfiguration.java
下面是web service客户端的xml序列化与反序列化配置,具体如下:
package com.xxx.xxxx.wsdl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
@Configuration
@RefreshScope
public class WsxxxConfiguration {
@Value("${web-service.uri}")
private String uri;
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
// this package must match the package in the <generatePackage> specified in
// pom.xml
// 这里主要是告诉jaxb需要解析xml与java bean相互转化的模型类在哪里
marshaller.setContextPath("com.xxx.xxxx.wsdl");
return marshaller;
}
@Bean
public WsClient wsClient(Jaxb2Marshaller marshaller) {
WsClient client = new WsClient();
client.setDefaultUri(uri);
// web service客户端的xml序列化与反序列化使用Jaxb
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
看吧,序列化成xml,这是json的前辈。到这里,就可以在Spring中自动注入WsClient.java类,来调用第三方web service方法。
总结
Web Service这种技术,我是看好几天,才大概摸明白这个协议,上次我真正对接这个技术的时候,还是入行初期,这东西都快被淘汰,wsdl太难看懂了。
希望之后的时光,不要遇到wsdl这种东西。
参考:
- Consuming a SOAP web service
- jaxws:wsimport
- JAXB使用
- Web服务
- Consuming a SOAP web service
- Web Service Client in Spring Boot
- Web Services Description Language
- Web Service Client in Spring Boot