10 Commits

Author SHA1 Message Date
Greg Turnquist
1c036c8093 Upgrade to Spring Boot 1.5.2.RELEASE 2017-03-03 11:12:55 -06:00
Greg Turnquist
69d1c5f793 Upgrade to Spring Boot 1.5.1.RELEASE 2017-01-30 23:29:36 -06:00
Greg Turnquist
c6783ee869 Upgrade to Spring Boot 1.5.0.RELEASE 2017-01-30 11:38:03 -06:00
Greg Turnquist
1b7fa858a0 Set maven pom.xml to Spring Boot 1.4.4.RELEASE 2017-01-26 12:47:34 -06:00
Greg Turnquist
2c03bf2281 Upgrade to Spring Boot 1.4.4.RELEASE 2017-01-26 12:37:09 -06:00
Dave Syer
a625386b76 Switch to quote service (SOAP endpoint actually exists)
The weather service we had been using no longer exists and there
doesn't seem to be a simple publicly available alternative
(everyone is using plain HTTP these days). So this change converts
the sample to a public SOAP service that does stock quotes.

Fixes gh-9
2017-01-16 11:00:22 +00:00
Greg Turnquist
537578d624 Upgrade to Spring Boot 1.4.3.RELEASE 2016-12-22 22:32:28 -06:00
KC Baltz
62359bb948 Adding a comment to help others avoid a mistake
I think "hello.wsdl" sounds too much like a file name and not a package.  My colleague changed one and not the other and didn't see the problem.  I think this comment would help.
2016-12-20 11:58:34 +00:00
Greg Turnquist
c1060bbb5a Upgrade plugin from spring-boot to o.s.boot 2016-11-30 10:06:22 -06:00
Greg Turnquist
4182b71081 Upgrade to Spring Boot 1.4.2.RELEASE 2016-11-08 11:52:23 -06:00
9 changed files with 76 additions and 112 deletions

View File

@@ -6,7 +6,7 @@ projects: [spring-ws]
:toc:
:project_id: gs-consuming-web-service
:spring_version: current
:spring_boot_version: 1.4.1.RELEASE
:spring_boot_version: 1.5.2.RELEASE
:icons: font
:source-highlighter: prettify
@@ -15,9 +15,9 @@ This guide walks you through the process of consuming a link:/understanding/SOAP
== What you'll build
You will build a client that fetches weather data from a remote, WSDL-based web service using http://en.wikipedia.org/wiki/SOAP[SOAP].
You can find out more about the weather service at http://wiki.cdyne.com/index.php/CDYNE_Weather
You can find out more about the quote service at http://www.webservicex.com/stockquote.asmx?op=GetQuote.
The service provides weather forecasts based on a zipcode. You will be able to use your own zip code.
The service provides stock market quotes. You will be able to use your own ticker symbol.
== What you'll need
@@ -44,7 +44,7 @@ only for server-side web services. That starter brings on board things like embe
== Generate domain objects based on a WSDL
The interface to a SOAP web service is captured in a http://en.wikipedia.org/wiki/Web_Services_Description_Language[WSDL]. JAXB provides an easy means to generate Java classes from a WSDL (or rather: the XSD contained in the `<Types/>` section of the WSDL).
The WSDL for the weather service can be found at http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl.
The WSDL for the quote service can be found at http://www.webservicex.com/stockquote.asmx?WSDL.
To generate Java classes from the WSDL in maven, you need the following plugin setup:
@@ -70,33 +70,33 @@ In both cases, the JAXB domain object generation process has been wired into the
To create a web service client, you simply 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:
`src/main/java/hello/WeatherClient.java`
`src/main/java/hello/QuoteClient.java`
[source,java]
----
include::complete/src/main/java/hello/WeatherClient.java[]
include::complete/src/main/java/hello/QuoteClient.java[]
----
The client contains two methods: `getCityForecastByZip` which does the actual SOAP exchange, and `printResponse` which prints the received response. We will focus on the former method.
The client contains one method: `getQuote` which does the actual SOAP exchange.
In this method, both the `GetCityForecastByZIP` and the `GetCityForecastByZIPResponse` classes are derived from the WSDL and were generated in the JAXB generation process described in the previous step.
It creates the `GetCityForecastByZIP` request object and set it with the `zipCode` parameter.
After printing out the zip code, 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 `GetCityForecastByZIP` 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 `GetCityForecastByZIPResponse` object, which is then returned.
In this method, both the `GetQuote` and the `GetQuoteResponse` classes are derived from the WSDL and were generated in the JAXB generation process described in the previous step.
It creates the `GetQuote` request object and sets it up with the `ticker` parameter.
After printing out the ticker code, 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 `GetQuote` 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 `GetQuoteResponse` 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.
`src/main/java/hello/WeatherConfiguration.java`
`src/main/java/hello/QuoteConfiguration.java`
[source,java]
----
include::complete/src/main/java/hello/WeatherConfiguration.java[]
include::complete/src/main/java/hello/QuoteConfiguration.java[]
----
The `marshaller` is pointed at the collection of generated domain objects and will use them to both serialize and deserialize between XML and link:/understanding/POJO[POJOs].
The `weatherClient` is created and configured with the URI of the weather service shown up above. It is also configured to use the JAXB marshaller.
The `quoteClient` is created and configured with the URI of the weather service shown up above. It is also configured to use the JAXB marshaller.
== Make the application executable
@@ -108,7 +108,7 @@ This application is packaged up to run from the console and retrieve a single we
include::complete/src/main/java/hello/Application.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 `WeatherConfiguration.class` as an argument to its `run()` method. This tells Spring to read the annotation metadata from `WeatherConfiguration` and to manage it as a component in the link:/understanding/application-context[Spring application context].
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 `QuoteConfiguration.class` as an argument to its `run()` method. This tells Spring to read the annotation metadata from `QuoteConfiguration` and to manage it as a component in the link:/understanding/application-context[Spring application context].
NOTE: This application is hard coded to look up zip code 94304, Palo Alto, CA. Towards the end of this guide, you'll see how to plug in a different zip code without editing the code.
@@ -120,31 +120,18 @@ include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/
Logging output is displayed. The service should be up and running within a few seconds.
```
Requesting forecast for 94304
Requesting quote for MSFT
Forecast for Palo Alto, CA
2013-01-03 Partly Cloudy °-57°
2013-01-04 Partly Cloudy 41°-58°
2013-01-05 Partly Cloudy 41°-59°
2013-01-06 Partly Cloudy 44°-56°
2013-01-07 Partly Cloudy 41°-60°
2013-01-08 Partly Cloudy 42°-60°
2013-01-09 Partly Cloudy 43°-58°
<StockQuotes><Stock><Symbol>MSFT</Symbol><Last>62.70</Last>...</StockQuotes>
```
You can plug in a different zip code by typing `java -jar build/libs/gs-consuming-web-service-0.1.0.jar 34769`
You can plug in a different ticker by typing `java -jar build/libs/gs-consuming-web-service-0.1.0.jar ORCL`
```
Requesting forecast for 34769
Requesting quote for ORCL
<StockQuotes><Stock><Symbol>ORCL</Symbol><Last>39.26</Last>...</StockQuotes>
Forecast for Saint Cloud, FL
2014-02-18 Sunny 51°-79°
2014-02-19 Sunny 55°-81°
2014-02-20 Sunny 59°-84°
2014-02-21 Partly Cloudy 63°-85°
2014-02-22 Partly Cloudy 63°-84°
2014-02-23 Partly Cloudy 63°-82°
2014-02-24 Partly Cloudy 62°-80°
```
== Summary

View File

@@ -7,14 +7,14 @@ buildscript {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE")
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'org.springframework.boot'
repositories {
mavenCentral()
@@ -24,7 +24,7 @@ repositories {
task genJaxb {
ext.sourcesDir = "${buildDir}/generated-sources/jaxb"
ext.classesDir = "${buildDir}/classes/jaxb"
ext.schema = "http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl"
ext.schema = "http://www.webservicex.com/stockquote.asmx?WSDL"
outputs.dir classesDir

View File

@@ -10,7 +10,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
<version>1.5.2.RELEASE</version>
</parent>
<properties>
@@ -51,7 +51,7 @@
<generatePackage>hello.wsdl</generatePackage>
<schemas>
<schema>
<url>http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl</url>
<url>http://www.webservicex.com/stockquote.asmx?WSDL</url>
</schema>
</schemas>
</configuration>

View File

@@ -1,7 +1,7 @@
package hello;
import hello.wsdl.GetCityForecastByZIPResponse;
import hello.wsdl.GetQuoteResponse;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
@@ -16,14 +16,15 @@ public class Application {
}
@Bean
CommandLineRunner lookup(WeatherClient weatherClient) {
CommandLineRunner lookup(QuoteClient quoteClient) {
return args -> {
String zipCode = "94304";
String ticker = "MSFT";
if (args.length > 0) {
zipCode = args[0];
ticker = args[0];
}
GetCityForecastByZIPResponse response = weatherClient.getCityForecastByZip(zipCode);
GetQuoteResponse response = quoteClient.getQuote(ticker);
System.err.println(response.getGetQuoteResult());
};
}

View File

@@ -0,0 +1,32 @@
package hello;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.soap.client.core.SoapActionCallback;
import hello.wsdl.GetQuote;
import hello.wsdl.GetQuoteResponse;
public class QuoteClient extends WebServiceGatewaySupport {
private static final Logger log = LoggerFactory.getLogger(QuoteClient.class);
public GetQuoteResponse getQuote(String ticker) {
GetQuote request = new GetQuote();
request.setSymbol(ticker);
log.info("Requesting quote for " + ticker);
GetQuoteResponse response = (GetQuoteResponse) getWebServiceTemplate()
.marshalSendAndReceive("http://www.webservicex.com/stockquote.asmx",
request,
new SoapActionCallback("http://www.webserviceX.NET/GetQuote"));
return response;
}
}

View File

@@ -6,19 +6,21 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
@Configuration
public class WeatherConfiguration {
public class QuoteConfiguration {
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
// this package must match the package in the <generatePackage> specified in
// pom.xml
marshaller.setContextPath("hello.wsdl");
return marshaller;
}
@Bean
public WeatherClient weatherClient(Jaxb2Marshaller marshaller) {
WeatherClient client = new WeatherClient();
client.setDefaultUri("http://ws.cdyne.com/WeatherWS");
public QuoteClient quoteClient(Jaxb2Marshaller marshaller) {
QuoteClient client = new QuoteClient();
client.setDefaultUri("http://www.webservicex.com/stockquote.asmx");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;

View File

@@ -1,58 +0,0 @@
package hello;
import java.text.SimpleDateFormat;
import hello.wsdl.Forecast;
import hello.wsdl.ForecastReturn;
import hello.wsdl.GetCityForecastByZIP;
import hello.wsdl.GetCityForecastByZIPResponse;
import hello.wsdl.Temp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.soap.client.core.SoapActionCallback;
public class WeatherClient extends WebServiceGatewaySupport {
private static final Logger log = LoggerFactory.getLogger(WeatherClient.class);
public GetCityForecastByZIPResponse getCityForecastByZip(String zipCode) {
GetCityForecastByZIP request = new GetCityForecastByZIP();
request.setZIP(zipCode);
log.info("Requesting forecast for " + zipCode);
GetCityForecastByZIPResponse response = (GetCityForecastByZIPResponse) getWebServiceTemplate()
.marshalSendAndReceive(
"http://wsf.cdyne.com/WeatherWS/Weather.asmx",
request,
new SoapActionCallback("http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP"));
return response;
}
public void printResponse(GetCityForecastByZIPResponse response) {
ForecastReturn forecastReturn = response.getGetCityForecastByZIPResult();
if (forecastReturn.isSuccess()) {
log.info("Forecast for " + forecastReturn.getCity() + ", " + forecastReturn.getState());
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
for (Forecast forecast : forecastReturn.getForecastResult().getForecast()) {
Temp temperature = forecast.getTemperatures();
log.info(String.format("%s %s %s°-%s°", format.format(forecast.getDate().toGregorianCalendar().getTime()),
forecast.getDesciption(), temperature.getMorningLow(), temperature.getDaytimeHigh()));
log.info("");
}
} else {
log.info("No forecast received");
}
}
}

View File

@@ -7,14 +7,14 @@ buildscript {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE")
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'org.springframework.boot'
repositories {
mavenCentral()
@@ -24,7 +24,7 @@ repositories {
task genJaxb {
ext.sourcesDir = "${buildDir}/generated-sources/jaxb"
ext.classesDir = "${buildDir}/classes/jaxb"
ext.schema = "http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl"
ext.schema = "http://www.webservicex.com/stockquote.asmx?WSDL"
outputs.dir classesDir

View File

@@ -10,7 +10,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
<version>1.5.2.RELEASE</version>
</parent>
<properties>
@@ -51,7 +51,7 @@
<generatePackage>hello.wsdl</generatePackage>
<schemas>
<schema>
<url>http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl</url>
<url>http://www.webservicex.com/stockquote.asmx?WSDL</url>
</schema>
</schemas>
</configuration>