to account for changes in how Spring Boot handles SOAP. Also removed the Jenkinsfile, because the test script can never succeed (due to a port collision in the /initial branch).
282 lines
10 KiB
Plaintext
282 lines
10 KiB
Plaintext
:spring_version: current
|
|
:toc:
|
|
:project_id: gs-consuming-web-service
|
|
:spring_version: current
|
|
:spring_boot_version: 2.3.2.RELEASE
|
|
:icons: font
|
|
:source-highlighter: prettify
|
|
|
|
This guide walks you through the process of consuming a SOAP-based web service with
|
|
Spring.
|
|
|
|
== What You Will Build
|
|
|
|
You will build a client that fetches country data from a remote, WSDL-based web
|
|
service by using http://en.wikipedia.org/wiki/SOAP[SOAP].
|
|
You can find out more about the country service and run the service yourself by following
|
|
https://spring.io/guides/gs/producing-web-service/[this guide].
|
|
|
|
The service provides country data. You will be able to query data about a country based on its name.
|
|
|
|
== What You Need
|
|
|
|
:java_version: 17
|
|
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/prereq_editor_jdk_buildtools.adoc[]
|
|
|
|
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/how_to_complete_this_guide.adoc[]
|
|
|
|
== Run the Target Web Service Locally
|
|
|
|
Follow the steps in the
|
|
https://spring.io/guides/gs/producing-web-service/[companion guide] or clone the
|
|
https://github.com/spring-guides/gs-producing-web-service[repository] and run the service
|
|
(for example, by using `mvn spring-boot:run`) from its `complete` directory. You can
|
|
verify that it works by visiting `http://localhost:8080/ws/countries.wsdl` in your
|
|
browser. If you do not do so, you will see a confusing exception in your build later from the JAXB tooling.
|
|
|
|
[[scratch]]
|
|
== Starting with Spring Initializr
|
|
|
|
For all Spring applications, you should start with the https://start.spring.io[Spring
|
|
Initializr]. The Initializr offers a fast way to pull in all the dependencies you need for
|
|
an application and does a lot of the setup for you. This example needs only the Spring Web
|
|
Services dependency.
|
|
|
|
You can use this https://start.spring.io/#!type=maven-project&language=java&&packaging=jar&jvmVersion=17&groupId=com.example&artifactId=consuming-web-service&name=consuming-web-service&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.consuming-web-service&dependencies=web-services[pre-initialized project] and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.
|
|
|
|
To initialize the project:
|
|
|
|
. Navigate to https://start.spring.io.
|
|
This service pulls in all the dependencies you need for an application and does most of the setup for you.
|
|
. Choose either Gradle or Maven and the language you want to use. This guide assumes that you chose Java.
|
|
. Click *Dependencies* and select *Spring Web Services*.
|
|
. Click *Generate*.
|
|
. Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.
|
|
|
|
NOTE: If your IDE has the Spring Initializr integration, you can complete this process from your IDE.
|
|
|
|
NOTE: You can also fork the project from Github and open it in your IDE or other editor.
|
|
|
|
== Modify the Build Files
|
|
|
|
The build files created by the Spring Initializr need quite a bit of work for this guide.
|
|
Also, the modifications to `pom.xml` (for Maven) and `build.gradle` (for Gradle) differ
|
|
substantially.
|
|
|
|
=== Maven
|
|
|
|
For Maven, you need to add a dependency, a profile, and a WSDL generation plugin.
|
|
|
|
The following listing shows the dependency you need to add in Maven:
|
|
|
|
====
|
|
[source,xml,indent=0]
|
|
----
|
|
include::complete/pom.xml[tags=dependency]
|
|
----
|
|
====
|
|
|
|
The <<initial>> section describes the WSDL generation plugin.
|
|
|
|
The following listing shows the final `pom.xml` file:
|
|
|
|
====
|
|
[source,xml,indent=0]
|
|
----
|
|
include::complete/pom.xml[]
|
|
----
|
|
====
|
|
|
|
=== Gradle
|
|
|
|
For Gradle, you need to add a dependency, a configuration, a `bootJar` section, and a WSDL
|
|
generation plugin.
|
|
|
|
The following listing shows the dependency you need to add in Gradle:
|
|
|
|
====
|
|
[source,xml,indent=0]
|
|
----
|
|
include::complete/build.gradle[tags=dependency]
|
|
----
|
|
====
|
|
|
|
Note the exclusion of Tomcat. If Tomcat is allowed to run in this build, you get a port
|
|
collision with the Tomcat instance that provides the country data.
|
|
|
|
NOTE: Due to this port collision, the initial project fails to start.
|
|
You can fix it by adding an `application.properties` file with a single property of
|
|
`server.port=8081`. Since the initial project exists to be a starting point, you
|
|
can skip trying to get it to run.
|
|
|
|
The <<initial>> section describes the WSDL generation plugin.
|
|
|
|
The following listing shows the final `build.gradle` file:
|
|
|
|
====
|
|
[source,xml,indent=0]
|
|
----
|
|
include::complete/build.gradle[]
|
|
----
|
|
====
|
|
|
|
[[initial]]
|
|
== Generate Domain Objects Based on a WSDL
|
|
|
|
The interface to a SOAP web service is captured in
|
|
http://en.wikipedia.org/wiki/Web_Services_Description_Language[WSDL]. JAXB provides a way
|
|
to generate Java classes from WSDL (or rather, the XSD contained in the `<Types/>` section
|
|
of the WSDL). You can find the WSDL for the country service at
|
|
`http://localhost:8080/ws/countries.wsdl`.
|
|
|
|
To generate Java classes from the WSDL in Maven, you need the following plugin setup:
|
|
|
|
====
|
|
[source,xml,indent=0]
|
|
----
|
|
include::complete/pom.xml[tags=wsdl]
|
|
----
|
|
====
|
|
|
|
This setup generates classes for the WSDL found at the specified URL, putting those
|
|
classes in the `com.example.consumingwebservice.wsdl` package. To generate that code run, `./mvnw compile`
|
|
and then look in `target/generated-sources` if you want to check that it worked.
|
|
|
|
To do the same with Gradle, you need the following in your build file:
|
|
|
|
====
|
|
[source,java,tabsize=2,indent=0]
|
|
----
|
|
include::complete/build.gradle[tags=wsdl]
|
|
----
|
|
====
|
|
|
|
As Gradle does not (yet) have a JAXB plugin, it involves an Ant task, which makes it a bit
|
|
more complex than in Maven. To generate that code run `./gradlew compileJava`
|
|
and then look in `build/generated-sources` if you want to check that it worked.
|
|
|
|
In both Maven and Gradle, the JAXB domain object generation process has been wired into the build
|
|
tool's lifecycle, so you need not run any extra steps once you have a successful build.
|
|
|
|
== Create a Country Service Client
|
|
|
|
To create a web service client, you have to extend the
|
|
http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/client/core/support/WebServiceGatewaySupport.html[`WebServiceGatewaySupport`]
|
|
class and code your operations, as the following example (from
|
|
`src/main/java/com/example/consumingwebservice/CountryClient.java`) shows:
|
|
|
|
====
|
|
[source,java,tabsize=2]
|
|
----
|
|
include::complete/src/main/java/com/example/consumingwebservice/CountryClient.java[]
|
|
----
|
|
====
|
|
|
|
The client contains one method (`getCountry`) that does the actual SOAP exchange.
|
|
|
|
In this method, both the `GetCountryRequest` and the `GetCountryResponse` classes are
|
|
derived from the WSDL and were generated in the JAXB generation process (described in
|
|
<<initial>>). It creates the `GetCountryRequest` request object and sets it up with the
|
|
`country` parameter (the name of the country). After printing out the country name, it
|
|
uses the
|
|
http://docs.spring.io/spring-ws/sites/2.0/apidocs/org/springframework/ws/client/core/WebServiceTemplate.html[`WebServiceTemplate`]
|
|
supplied by the `WebServiceGatewaySupport` base class to do the actual SOAP exchange. It
|
|
passes the `GetCountryRequest` request object (as well as a `SoapActionCallback` to pass
|
|
on a http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383528[SOAPAction] header with
|
|
the request) as the WSDL described that it needed this header in the `<soap:operation/>`
|
|
elements. It casts the response into a `GetCountryResponse` object, which is then
|
|
returned.
|
|
|
|
== Configuring Web Service Components
|
|
|
|
Spring WS uses Spring Framework's OXM module, which has the `Jaxb2Marshaller` to serialize
|
|
and deserialize XML requests, as the following example (from
|
|
`src/main/java/com/example/consumingwebservice/CountryConfiguration.java`) shows:
|
|
|
|
====
|
|
[source,java,tabsize=2]
|
|
----
|
|
include::complete/src/main/java/com/example/consumingwebservice/CountryConfiguration.java[]
|
|
----
|
|
====
|
|
|
|
The `marshaller` is pointed at the collection of generated domain objects and will use
|
|
them to both serialize and deserialize between XML and POJOs.
|
|
|
|
The `countryClient` is created and configured with the URI of the country service shown
|
|
earlier. It is also configured to use the JAXB marshaller.
|
|
|
|
== Run the Application
|
|
|
|
This application is packaged up to run from the console and retrieve the data for a given
|
|
country name, as the following listing (from
|
|
`src/main/java/com/example/consumingwebservice/ConsumingWebServiceApplication.java`)
|
|
shows:
|
|
|
|
====
|
|
[source,java,tabsize=2]
|
|
----
|
|
include::complete/src/main/java/com/example/consumingwebservice/ConsumingWebServiceApplication.java[]
|
|
----
|
|
====
|
|
|
|
The `main()` method defers to the
|
|
http://docs.spring.io/spring-boot/docs/{spring_boot_version}/api/org/springframework/boot/SpringApplication.html[`SpringApplication`] helper class, providing
|
|
`CountryConfiguration.class` as an argument to its `run()` method. This tells Spring to
|
|
read the annotation metadata from `CountryConfiguration` and to manage it as a component
|
|
in the Spring application context.
|
|
|
|
NOTE: This application is hard-coded to look up 'Spain'. Later in this guide, you will see
|
|
how to enter a different symbol without editing the code.
|
|
|
|
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_an_executable_jar_subhead.adoc[]
|
|
|
|
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_an_executable_jar_with_both.adoc[]
|
|
|
|
Logging output is displayed. The service should be up and running within a few seconds.
|
|
|
|
The following listing shows the initial response:
|
|
|
|
====
|
|
[source]
|
|
----
|
|
Requesting country data for Spain
|
|
|
|
<getCountryRequest><name>Spain</name>...</getCountryRequest>
|
|
----
|
|
====
|
|
|
|
You can plug in a different country by running the following command:
|
|
|
|
====
|
|
[source,bash]
|
|
----
|
|
java -jar build/libs/gs-consuming-web-service-0.1.0.jar Poland
|
|
----
|
|
====
|
|
|
|
Then the response changes to the following:
|
|
|
|
====
|
|
[source]
|
|
----
|
|
Requesting location for Poland
|
|
|
|
<getCountryRequest><name>Poland</name>...</getCountryRequest>
|
|
----
|
|
====
|
|
|
|
== Summary
|
|
|
|
Congratulations! You have just developed a client to consume a SOAP-based web service with
|
|
Spring.
|
|
|
|
== See Also
|
|
|
|
The following guides may also be helpful:
|
|
|
|
* https://spring.io/guides/gs/producing-web-service/[Producing a SOAP web service]
|
|
* https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot]
|
|
|
|
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/footer.adoc[]
|