We will assume that we only know the WSDL of the web service to simulate a real client development. To generate the proxy classes, we will use the built-in wsimport tool from the JDK. To access the web service, we will use Spring's WebServiceTemplate.
What is Spring Web Services (WS)?
Spring Web Services (Spring-WS) is a product of the Spring community focused on creating document-driven Web services. Spring Web Services aims to facilitate contract-first SOAP service development, allowing for the creation of flexible web services using one of the many ways to manipulate XML payloads. The product is based on Spring itself, which means you can use the Spring concepts such as dependency injection as an integral part of your Web service.What is WebServiceTemplate?
Source: Spring WS Reference 2.0
The WebServiceTemplate is the core class for client-side Web service access in Spring-WS. It contains methods for sending Source objects, and receiving response messages as either Source or Result. Additionally, it can marshal objects to XML before sending them across a transport, and unmarshal any response XML into an object again.What is wsimport?
Source: Spring WS Reference Chapter 6
The wsimport tool generates JAX-WS portable artifacts, such as:Let's start by downloading and examining the WSDL document from the web service which is accessible in the following URL:
These artifacts can be packaged in a WAR file with the WSDL and schema documents along with the endpoint implementation to be deployed
- Service Endpoint Interface (SEI)
- Service
- Exception class mapped from wsdl:fault (if any)
- Async Reponse Bean derived from response wsdl:message (if any)
- JAXB generated value types (mapped java classes from schema types)
Source: Java™ API for XML Web Services (JAX-WS) 2.0
http://localhost:8081/spring-ws-standalone/krams/ws/subscription.wsdlsubscription.wsdl
This document has one request subscriptionRequest and one response subscriptionResponse.
The subscriptionRequest accepts the following format:
The subscriptionResponse is what we will receive in return:
The service name is SubscriptionPortService. The port type is SubscriptionPort. If you need help in reviewing the basics of a WSDL document, please visit the following tutorial from w3schools.com WSDL Tutorial.
We got our WSDL document. Next we generate the Java proxy classes or precisely the JAX-WS portable artifacts
We will use wsimport to generate the artifacts. Open a terminal and type the following:
wsimportAnd this is what you should see:
We need to keep the generated Java sources and specify the target directory. To do that we will include the -keep and -d options. Make sure you update the directory accordingly.
Here's the command to generate the classes
Type that in a terminal and hit enter. You should see the following:
parsing WSDL... generating code...Go to the directory where the file is saved. You should see a nest of folders. These folders correspond to the namespace of the WSDL document. Also, for each .class file, there's a coresponding .java file. That's the source code.
Here's an actual screenshot from my machine:
We have our WSDL. We have our artifacts. Notice we haven't done any Java or Spring development yet. These are just preparations.
Let's start the actual development. I'm using Eclipse and the m2eclipse plugin, so my instructions would be IDE-centric and Maven-centric as well.
If you're using Eclipse:
1. Create a new Dynamic Web project.
2. Create the top-level package, ie. org.krams.tutorial
3. Create a sub package, i.e org.krams.tutorial.oxm
4. Remember the files that we generated earlier? Copy all the .java files and paste them in the sub-package.
If you have the m2eclipse plugin:
1. Create a new Maven project.
2. Select the maven-archetype-webapp
3. Create a sub package, i.e org.krams.tutorial.oxm
4. Remember the files that we generated earlier? Copy all the .java files and paste them in the sub-package.
The source code for this tutorial is a Maven project which you can download the end of this tutorial.
Here's how the project looks like in my IDE:
We can now start developing our Spring MVC application.
We begin by declaring the primary controller.
MainController
This controller declares two mappings:
/main - for showing the subscribe page /main/subscribe - for processing the subscriptionNotice we have injected an instance of a WebServiceTemplate
Inside the doSubscribe() method, we process the subscription by delegating to the WebServiceTemplate
The WebServiceTemplate is able to marshall Java objects to XML and unmarshall from XML to Java objects again. In layman's term, marshall and unmarshall are another word for converting back and forth to different formats. If you need a thorough guide of the WebServiceTemplate, please check the official reference guide at SpringSource - Chapter 6. Using Spring Web Services on the Client
Once we get a valid response, we add it to the model:
If there are validation errors, the client will throw a SoapFaultClientException so we need to catch that:
SubscriptionResponse and SubscriptionRequest are JAX artifacts that were generated from the WSDL earlier. So instead of manipulating XML, we deal with Java objects.
A quick look at the contents of these two artifacts shows us the following:
SubscriptionRequest
SubscriptionResponse
Notice how the XML elements had been mapped to equivalent Java fields.
Our controller requires a single JSP page for displaying the form.
subscribepage.jsp
Here's the actual screenshot:
If there's a validation error, we see the following:
If successful, we get the following instead:
What's left are the required XML configurations.
To enable Spring MVC we need to add it in the web.xml
web.xml
Take note of the URL pattern. When accessing any pages in our MVC application, the host name must be appended with
/kramsIn the web.xml we declared a servlet-name spring. By convention, we must declare a spring-servlet.xml as well.
spring-servlet.xml
By convention, we must declare an applicationContext.xml as well.
applicationContext.xml
This XML config declares three beans to activate the Spring 3 MVC programming model. There's also an extra bean that imports Spring-WS related configuration.
spring-ws.xml
For a detailed description of this configuration, please check the official Spring Reference: Chapter 6. Using Spring Web Services on the Client
That's it. We're done with our Spring WS web service client. We've managed to integrate a Spring MVC application for the submission of subscriptions, and utilized the convenient WebServiceTemplate.
To test the client and the web service provider, you need two instances of Tomcat or Jetty : one for the web service and one for the client. Make sure to set the ports accordingly. For the provider, I chose port 8081. For the client, I chose 8080. If you change the ports, you must update the spring-ws.xml configuration of the provider and the client as well. In case you forgot, the web service provider is in my other tutorial Spring WS 2 and Spring 3 MVC Integration Tutorial
To access the Subscribe Page, use the following URL:
http://localhost:8080/spring-ws-client/krams/mainDownload the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-ws-2-0-0-rc2-tutorial/
You can download the project as a Maven build. Look for the spring-ws-client.zip in the Download sections.
You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run
If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
Share the joy:
|
Subscribe by reader Subscribe by email Share
Thank you for your hard work, you made it very easy to learn the new annotations for Spring-WS 2.0!
ReplyDeleteVery nice article, very easy to understand and well set up. I have one question, and that is where does the payloadLoggingInterceptor log the requests to? I don't see them coming out in the console.
ReplyDeleteQuestion from a WS newbee. Your package structure in java is org.krams.tutorial but your structure in your wsdl is com.blogspot.kram915 . I was under the impression they should be the same. I can deploy your service and get the wsdl. Can you straighten me out?
ReplyDeleteAwesome!Thanks a lot mate for this such a detailed and nicely written tutorial.
ReplyDeleteHi,
ReplyDeleteThanks for this nice tutorial.
Is there a way you can write a tutorial with Spring-ws client with attachment (MTOM)?
Thanks
@Emmanuel, I'm not sure if I can do it soon :-) I'm glad you liked the tutorial
DeleteHi!
ReplyDeleteVery clear, thank you very much! I was so confused after reading the chapter 6 of Spring Reference! Thank for make it clear!
If I have to call a WS within a secured conection (https), would I have to change something?
Thank you very much!
Getting ClassCastException at line
ReplyDeleteSubscriptionResponse response = (SubscriptionResponse) webServiceTemplate.marshalSendAndReceive(request);
java.lang.ClassCastException: javax.xml.bind.JAXBElement cannot be cast to
Maybe you have incompatible or old jar versions? Have you tried doing a Maven clean command? Also, I suggest using pastebin when pasting the exception so that we can see all of it.
DeleteI am using this version of spring-ws
Deleteorg.springframework.ws
spring-ws-core
2.1.2.RELEASE
Please follow the link - http://pastebin.com/238vQD5g
ReplyDeleteI did a workaround to resolve this issue by casting with JAXBElement like this.
JAXBElement response = (JAXBElement) webServiceTemplate.marshalSendAndReceive(request);
SetScopeOutcomeResponseType responseType = response.getValue();
I guess the Issue relates to ws-import as it was not generating @XmlRootElement for my generated Java Classes and I have to manually write that Element on top of the Class after Maven generates it.
I can't access http://localhost:8081/spring-ws-standalone/krams/ws/subscription.wsdl. For generating Client side Java code - Link could not be found error.
ReplyDeleteI am getting HTTP Status 404 - /spring-ws-standalone/krams/ws/subscription.wsdl even if i use 8080 port Number.
Can you please help me for accessing WSDl file.
Thanks for the nice article!
ReplyDeleteI've followed your example, but my WSDL and generated classes are in another module. I've imported it through standard maven dependency, but somehow the JaxBMarshaller can't find the classes. The error is:
javax.xml.bind.JAXBException: class XX nor any of its super class is known to this context.
Do you have any idea how to fix this?
--Frank Tan
in my case, the response retruns a list of object and the object attributes are always coming as null. Although the server side code is processing the request properly and returning the correct response. But the controller after the webServiceTemplate.marshalSendAndReceive the values are setting as null. I am not able to debug what is going wrong .Can anyone please help.
ReplyDeleteThanks a lot.
Very nice info..
ReplyDeleteWebsite Developers in Mumbai
I have read your blog its very attractive and impressive. I like it your blog.
ReplyDeleteSpring online training Spring online training Spring Hibernate online training Spring Hibernate online training Java online training
spring training in chennai spring hibernate training in chennai
Finding the time and actual effort to create a superb article like this is great thing. I’ll learn many new stuff right here! Good luck for the next post buddy..
ReplyDeleteBest Industrial Training in Noida
Best Industrial Training in Noida
Really it was an awesome article...very interesting to read..You have provided an nice article....Thanks for sharing.
ReplyDeleteBest BCA Colleges in Noida
Thanks for sharing these information. It’s a very nice topic. We are providing online training classes
ReplyDeleteBest Linux training in Noida
Linux Training Institute in Noida
Canli
ReplyDeleteggdb
ReplyDeleteoff white clothing
yeezy 500
kd shoes
yeezy gap hoodie
bape
yeezy shoes
yeezy outlet
kyrie shoes
off-white