原文链接: http://spring.io/guides/gs/consuming-web-service/

调用SOAP web service

本指南将指导你使用Spring调用一个基于SOAP的web service的整个过程。

指南内容

你将构建一个客户端,使用SOAP用来从远端的基于WSDL的web service获取天气数据。请访问http://wiki.cdyne.com/index.php/CDYNE_Weather进一步获取该天气服务的信息。

该服务根据邮编返回天气预测。你可以使用自己的邮编。

准备事项

  • 大约15分钟

  • 钟爱的编辑器或IDE

  • JDK1.6或更高版本

  • Gradle 1.11+ 或 Maven 3.0+

  • 你也可以直接参阅该指南导入代码,或通过Spring工具集(Spring Tool Suite,简称STS)通过网页浏览代码,从而帮助你学习该章节内容。源码下载地址:https://github.com/spring-guides/gs-consuming-web-service.git

如何完成该指南

如同大多数的示例教程一样,你可以从头开始并完成每个步骤,或者你也可以跳过已经熟悉的基础章节。无论怎样,最终你要得到可以工作的代码。

从头开始,请移动到使用Gradle构建章节。

跳过基础部分,请做以下事情:

  • 下载并解压该向导的源代码,或者使用Git复制一份: git clone https://github.com/spring-guides/gs-consuming-web-service.git

  • 切换到gs-consuming-web-service/initial

  • 跳到基于WSDL生成领域对象章节。

当完成后,你可以使用gs-consuming-web-service/complete目录中的代码检查你的结果。

使用Gradle构建

首先你要设置一个基本的build脚本。当构建Spring应用程序时,你可以使用任何构建系统,但是这里只包括了使用MavenGradle的代码。如果你两者都不熟悉,请访问使用Gradle构建Java项目使用Maven构建Java项目

创建目录结构

在你选择的存放项目的目录中,创建如下的子目录结构。例如,在*nix系统中使用mkdir -p src/main/java/hello

1
2
3
4
└── src
└── main
└── java
└── hello

创建Gradle 构建文件

下面是一个初始的Gradle build文件

build.gradle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
configurations {
jaxb
} buildscript {
repositories {
maven { url "http://repo.spring.io/libs-release" }
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.6.RELEASE")
}
} apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot' repositories {
mavenLocal()
mavenCentral()
maven { url 'http://repo.spring.io/libs-release' }
} // tag::wsdl[]
task genJaxb {
ext.sourcesDir = "${buildDir}/generated-sources/jaxb"
ext.classesDir = "${buildDir}/classes/jaxb"
ext.schema = "http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl" outputs.dir classesDir doLast() {
project.ant {
taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask",
classpath: configurations.jaxb.asPath
mkdir(dir: sourcesDir)
mkdir(dir: classesDir) xjc(destdir: sourcesDir, schema: schema,
package: "hello.wsdl") {
arg(value: "-wsdl")
produces(dir: sourcesDir, includes: "**/*.java")
} javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true,
debugLevel: "lines,vars,source",
classpath: configurations.jaxb.asPath) {
src(path: sourcesDir)
include(name: "**/*.java")
include(name: "*.java")
} copy(todir: classesDir) {
fileset(dir: sourcesDir, erroronmissingdir: false) {
exclude(name: "**/*.java")
}
}
}
}
}
// end::wsdl[] dependencies {
compile("org.springframework.boot:spring-boot-starter")
compile("org.springframework.ws:spring-ws-core")
compile(files(genJaxb.classesDir).builtBy(genJaxb)) jaxb "com.sun.xml.bind:jaxb-xjc:2.1.7"
} jar {
from genJaxb.classesDir
} task wrapper(type: Wrapper) {
gradleVersion = '1.11'
} task afterEclipseImport {
dependsOn genJaxb
}

Spring Boot gradle插件提供了很多便利的特性:

  • 将classpath中的所有jar包构建单个可运行的jar包,从而更容易执行和传播服务。

  • 搜索public static void main()方法并标记为可运行的类。

  • 提供了一个内置的依赖管理器,设置依赖版本以匹配Spring Boot依赖。你可以覆盖为任何你希望的版本,但默认会使用Boot选择的版本。

使用Maven构建

首先你需要设置一个基本的构建脚本。你可以使用任何构建系统来构建Spring应用程序,但这里包含了Maven的代码。如果你对Maven不熟,请访问使用Maven构建Java项目

创建目录结构

在你选择的存放项目的目录中,创建如下的子目录结构。例如,在*nix系统中使用mkdir -p src/main/java/hello

1
2
3
4
└── src
└── main
└── java
└── hello
pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>org.springframework</groupId>
<artifactId>gs-consuming-web-service</artifactId>
<version>0.1.0</version> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.6.RELEASE</version>
</parent> <properties>
<!-- use UTF-8 for everything -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- tag::wsdl[] -->
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generatePackage>hello.wsdl</generatePackage>
<forceRegenerate>true</forceRegenerate>
<schemas>
<schema>
<url>http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl</url>
</schema>
</schemas>
</configuration>
</plugin>
<!-- end::wsdl[] -->
</plugins>
</build> <repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>http://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories> </project>

注意:你可能注意到我们指定了maven-complier-plugin的版本。通常并不推荐这样做。这里主要是为了解决我们的CI系统默认运行在该插件的早期版本(java5之前)的一个问题。

Spring Boot Maven插件提供了很多便利的特性:

  • 将classpath中的所有jar包构建单个可运行的jar包,从而更容易执行和传播服务。

  • 搜索public static void main()方法并标记为可运行的类。

  • 提供了一个内置的依赖管理器,设置依赖版本以匹配Spring Boot依赖。你可以覆盖为任何你希望的版本,但默认会使用Boot选择的版本。

使用Spring工具集构建

如果你拥有Spring工具集,只需简单的直接导入该指南

注意:如果你阅读过生成SOAP web service,你可能会疑惑为什么该指南没有使用spring-boot-starter-ws?这是因为Spring Boot Starter只用于服务器端程序。Starter提供了诸如嵌入式Tomcat等功能,而服务调用则不需要这些。

基于WSDL生成领域对象

SOAP web service的接口描述在WSDL文件中。JAXB提供了一个简单的方式来从WSDL(或者WSDL中包含在<Types/>节点中的XSD)生成Java类。可以访问http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl获取该天气服务的WSDL。

你需要下列插件来使用maven从WSDL生成Java类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generatePackage>hello.wsdl</generatePackage>
<forceRegenerate>true</forceRegenerate>
<schemas>
<schema>
<url>http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl</url>
</schema>
</schemas>
</configuration>
</plugin>

该代码将通过指定的WSDL的URL生成类,并放置在hello.wsdl包中。

你也可以使用下列代码在Gradle中完成同样的事:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
task genJaxb {
ext.sourcesDir = "${buildDir}/generated-sources/jaxb"
ext.classesDir = "${buildDir}/classes/jaxb"
ext.schema = "http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl" outputs.dir classesDir doLast() {
project.ant {
taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask",
classpath: configurations.jaxb.asPath
mkdir(dir: sourcesDir)
mkdir(dir: classesDir) xjc(destdir: sourcesDir, schema: schema,
package: "hello.wsdl") {
arg(value: "-wsdl")
produces(dir: sourcesDir, includes: "**/*.java")
} javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true,
debugLevel: "lines,vars,source",
classpath: configurations.jaxb.asPath) {
src(path: sourcesDir)
include(name: "**/*.java")
include(name: "*.java")
} copy(todir: classesDir) {
fileset(dir: sourcesDir, erroronmissingdir: false) {
exclude(name: "**/*.java")
}
}
}
}
}

由于gradle还没有jaxb插件,所以它调用了一个ant任务,代码看起来比maven稍显复杂。
在maven和gradle两个示例中,JAXB领域对象生成过程被包括在构建工具的生命周期中,所以无需额外步骤来运行。

创建天气服务客户端

创建一个web service客户端,你只需要扩展WebServiceGatewaySupport类并编写操作代码:

src/main/java/hello/WeatherClient.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package hello;

import java.text.SimpleDateFormat;

import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.soap.client.core.SoapActionCallback; import hello.wsdl.Forecast;
import hello.wsdl.ForecastReturn;
import hello.wsdl.GetCityForecastByZIP;
import hello.wsdl.GetCityForecastByZIPResponse;
import hello.wsdl.Temp; public class WeatherClient extends WebServiceGatewaySupport { public GetCityForecastByZIPResponse getCityForecastByZip(String zipCode) {
GetCityForecastByZIP request = new GetCityForecastByZIP();
request.setZIP(zipCode); System.out.println();
System.out.println("Requesting forecast for " + zipCode); GetCityForecastByZIPResponse response = (GetCityForecastByZIPResponse) getWebServiceTemplate().marshalSendAndReceive(
request,
new SoapActionCallback(
"http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP")); return response;
} public void printResponse(GetCityForecastByZIPResponse response) {
ForecastReturn forecastReturn = response.getGetCityForecastByZIPResult(); if (forecastReturn.isSuccess()) {
System.out.println();
System.out.println("Forecast for " + forecastReturn.getCity() + ", "
+ forecastReturn.getState()); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
for (Forecast forecast : forecastReturn.getForecastResult().getForecast()) {
System.out.print(format.format(forecast.getDate().toGregorianCalendar().getTime()));
System.out.print(" ");
System.out.print(forecast.getDesciption());
System.out.print(" ");
Temp temperature = forecast.getTemperatures();
System.out.print(temperature.getMorningLow() + "\u00b0-"
+ temperature.getDaytimeHigh() + "\u00b0 ");
System.out.println();
}
} else {
System.out.println("No forecast received");
}
} }

该客户端包含了两个方法。getCityForecastByZip用于实际的SOAP交换;printResponse打印收到的响应结果。我们重点关注第一个方法。

在该方法中,GetCityForecastByZIPGetCityForecastByZIPResponse类衍生于WSDL中,被前一个步骤描述过的JAXB生成。该方法创建了GetCityForecastByZIP请求对象并设置了zipCode参数。打印出邮编后,使用WebServiceGatewaySupport基类提供的WebServiceTemplate来进行实际的SOAP交换。它传入GetCityForecastByZIP请求对象,以及一个SoapActionCallback来传入SOAPAction头,因为WSDL说明其需要在<soap:operation/>元素中使用该头。该方法将返回值转换为GetCityForecastByZIPResponse对象,然后返回该对象。

配置web service组件

Spring WS使用了Spring框架的OXM模块。该模块拥有Jaxb2Marshaller类来序列化和反序列化XML请求。

src/main/java/hello/WeatherConfiguration.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package hello;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller; @Configuration
public class WeatherConfiguration { @Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("hello.wsdl");
return marshaller;
} @Bean
public WeatherClient weatherClient(Jaxb2Marshaller marshaller) {
WeatherClient client = new WeatherClient();
client.setDefaultUri("http://wsf.cdyne.com/WeatherWS/Weather.asmx");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
} }

marshaller被指向了生成的领域对象集合,将使用这些对象来实现XML和POJO之间的序列化和反序列化。

我们使用了上面显示的天气服务URI创建和配置了weatherClient。他也被配置使用JAXB marshaller。

生成可执行的应用程序

该应用程序被打包后可运行与命令行,传入一个邮编则会得到一个天气预报。

src/main/java/hello/Application.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext; import hello.wsdl.GetCityForecastByZIPResponse; public class Application { public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(WeatherConfiguration.class, args); WeatherClient weatherClient = ctx.getBean(WeatherClient.class); String zipCode = "94304";
if (args.length > 0) {
zipCode = args[0];
}
GetCityForecastByZIPResponse response = weatherClient.getCityForecastByZip(zipCode);
weatherClient.printResponse(response);
} }

main()方法调用了SpringApplication辅助方法,并向其run()方法传入了WeatherConfiguration.class参数。这会使Spring从WeatherConfiguration中读取注解元数据,并作为Spring应用程序上下文中的一个组件进行管理。

注意:该应用程序硬编码了邮编94304,Palo Alto, CA。在该指南的最后,你可以看到如何添加不同的邮编而不用修改代码。

构建可执行的jar包

你可以创建一个包含所有必须的依赖,类,及资源的可执行的JAR文件。这很方便传输,版本管理以及独立于部署生命周期来部署服务,跨不同的环境,诸如此类。

1
gradlew build

然后你可以运行WAR文件:

1
java -jar build/libs/gs-consuming-web-service-0.1.0.jar

如果你使用的是maven,你可以使用mvn spring-boot:run来运行程序,或者你可以使用mvn clean package构建JAR文件,并使用下面命令来运行:

1
java -jar target/gs-consuming-web-service-0.1.0.jar

注意:上面的产出物是一个可运行JAR文件。你也可以创建一个经典的WAR文件。 

运行服务

如果使用的是Gradle,可以使用以下命令来运行服务:

1
gradlew clean build && java -jar build/libs/gs-consuming-web-service-0.1.0.jar

注意:如果你使用的是Maven,可以使用以下命令来运行服务:mvn clean package && java -jar target/gs-consuming-web-service-0.1.0.jar

你也可以通过Gradle直接运行该程序:

1
gradlew bootRun

注意:使用mvn的话,命令是mvn spring-boot:run

可以看到日志输出。该服务应该在几秒钟内启动并运行起来。

1
Requesting forecast for94304ForecastforPaloAlto, CA2013-01-03PartlyCloudy°-57°2013-01-04PartlyCloudy41°-58°2013-01-05PartlyCloudy41°-59°2013-01-06PartlyCloudy44°-56°2013-01-07PartlyCloudy41°-60°2013-01-08PartlyCloudy42°-60°2013-01-09PartlyCloudy43°-58°

你也可以使用不同的邮编:java -jar build/libs/gs-consuming-web-service-0.1.0.jar 34769

1
Requesting forecast for34769ForecastforSaintCloud, FL2014-02-18Sunny51°-79°2014-02-19Sunny55°-81°2014-02-20Sunny59°-84°2014-02-21PartlyCloudy63°-85°2014-02-22PartlyCloudy63°-84°2014-02-23PartlyCloudy63°-82°2014-02-24PartlyCloudy62°-80°

总结

恭喜你!你开发了一个客户端来使用Spring调用一个基于SOAP的web service。

翻译-使用Spring调用SOAP Web Service的更多相关文章

  1. 使用CXF框架集成Spring实现SOAP Web Service

  2. 翻译-使用Spring WebService生成SOAP Web Service

    原文链接:http://spring.io/guides/gs/producing-web-service/ 生成SOAP web service 该指南将带领你使用Spring创建一个基于SOAP的 ...

  3. [翻译]Spring MVC RESTFul Web Service CRUD 例子

    Spring MVC RESTFul Web Service CRUD 例子 本文主要翻译自:http://memorynotfound.com/spring-mvc-restful-web-serv ...

  4. Spring Boot发布和调用RESTful web service

    Spring Boot可以非常简单的发布和调用RESTful web service,下面参考官方指导体验一下 1.首先访问 http://start.spring.io/ 生成Spring Boot ...

  5. PHP soap Web Service 使用SoapDiscovery.class.php 生成wsdl文件

    PHP soap web service 使用wsdl文件 demo: ============================================================== 服 ...

  6. 构建一个基于 Spring 的 RESTful Web Service

    本文详细介绍了基于Spring创建一个“hello world” RESTful web service工程的步骤. 目标 构建一个service,接收如下HTTP GET请求: http://loc ...

  7. jboss上的soap web service开发示例

    以下示例,由jboss quickstart示例代码得来: 一.创建一个常规的dynamic web项目,建议支持maven ,项目的关键属性参考下图: 二.定义服务接口及参数对象 HelloWorl ...

  8. SOAP web service用AFNetWorking实现请求

    问: This is my current call to (asmx) SOAP web service: NSString *soapMessage = [NSString stringWithF ...

  9. 使用Apache CXF和Spring集成创建Web Service(zz)

    使用Apache CXF和Spring集成创建Web Service 您的评价:       还行  收藏该经验       1.创建HelloWorld 接口类 查看源码 打印? 1 package ...

随机推荐

  1. OSG配置问题

    BUILD_OSG_ARAPPERS: 这一项要选,不然后面编译自己的测试程序的时候,会报无法打开文件"osgIntrospectiond.lib"错误. Could not fi ...

  2. 急!JDBC问题,发生通信错误。错误位置:Reply.fill()。消息:数据不足。 ERRORCODE=-4499, SQLSTATE=08001

    代码如下:Class.forName("com.ibm.db2.jcc.DB2Driver");Connection conn = DriverManager.getConnect ...

  3. vue2 上传图片

    <template> <div class="vue-upload-img-multiple"> <div v-if="images.len ...

  4. Mac 系统下的环境变量

    1.查看电脑环境变量   -->echo $PATH 2. 新建环境变量   sudo vim ~/.bash_profile  输入密码 3. 按 I ,编辑新的环境变量地址,保存 退出 :w ...

  5. Javascript重要知识点梳理

    Javascript重要知识点梳理 一.Javascript流程控制 js中常用的数据类型 var关键字的使用 if – else if – else switch while for 二.Javas ...

  6. JS-firstChild,firstElementChild,lastChild,firstElementChild,nextSibling,nextElementSibling

    <body> <ul id="ul1"> <li>11111</li> <li>22222</li> < ...

  7. bootstrap中table的colspan不起作用

    bootstrap中table的colspan不起作用,即在不指定宽度的条件下,各个td宽度不符合colspan指定的宽度. 添加table0layout:fixed后显示正常. table{ tab ...

  8. css3 自定义动画(2)位置的移动

    <style> /*涉及到位置的必须给元素进行相对或绝对定位*/ @-webkit-keyframes move{ %{top:0px;left:0px;} %{top:0px;left: ...

  9. 从程序员到CTO的Java技术路线图 作者:zz563143188

    在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样我们清楚的知道我们大概处于那个阶段和水平. Java程序员 高级特性 反射.泛型. ...

  10. InnoDB配置文件复习

    1.文件分类 1.参数文件 2.日志文件 3.socket文件 4.pid文件 5.MySQL表文件 6.存储引擎文件 1.参数文件 1.参数内容写在my.cnf中,每次MySQL实例启动时,载入my ...