Spring Jax-Ws. Build and consume Web Services – part 1
Following the official guide, at the chapter 19 we’ll find the Spring support about web service (honestly, could it miss?).
In this article I’ll describe the use of it with Jax-WS standard (introduced in Java EE 5 and Java 6) and we’ll see how build and consume the web service.
First of all, you have to notice that there are a huge variety of methods about build and consume web service. I think I’ve never used two times the same method for building web services. I don’t know why, probably that is the evidence about the large number of technologies for building web services.
My personal opinion is to use technologies which implements java standard, like Jax-WS.
In this first part we’ll take a look about build web service. I’m an old style developer and I’m not able to start from the WSDL definition. So, my approach is to define the interface with methods exposed rather than define the WSDL definition.
1
2
3
4
5
6
7
8
9
10
|
package
it.springjaxws;
public
interface
OrderService {
public
void
Check(Order order)
throws
Exception;
public
Order Process(Order order);
public
Order Shipping(Order order);
}
|
And its implementation:
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
it.springjaxws;
import
java.util.Date;
public
class
OrderServiceImpl
implements
OrderService{
@Override
public
void
Check(Order order)
throws
Exception{
if
(order.getItemNumber()==
0
)
{
throw
new
Exception(
"Quantity cannot be 0!!"
);
}
}
@Override
public
Order Process(Order order) {
order.setInvoice(order.getItemNumber() *
1.3
);
return
order;
}
@Override
public
Order Shipping(Order order) {
order.setShippingDate(
new
Date());
return
order;
}
}
|
The Order bean:
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
|
package
it.springjaxws;
import
java.io.Serializable;
import
java.util.Date;
import
javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
(name=
"Order"
)
public
class
Order
implements
Serializable {
/**
*
*/
private
static
final
long
serialVersionUID = 1L;
private
String orderId;
private
double
invoice;
private
int
itemNumber;
private
Date shippingDate;
public
Order()
{}
public
Order(String orderId,
double
invoice,
int
itemNumber)
{
this
.orderId = orderId;
this
.invoice = invoice;
this
.itemNumber = itemNumber;
}
public
String getOrderId() {
return
orderId;
}
public
void
setOrderId(String orderId) {
this
.orderId = orderId;
}
public
double
getInvoice() {
return
invoice;
}
public
void
setInvoice(
double
invoice) {
this
.invoice = invoice;
}
public
int
getItemNumber() {
return
itemNumber;
}
public
void
setItemNumber(
int
itemNumber) {
this
.itemNumber = itemNumber;
}
public
Date getShippingDate() {
return
shippingDate;
}
public
void
setShippingDate(Date shippingDate) {
this
.shippingDate = shippingDate;
}
@Override
public
String toString()
{
return
" orderId:"
+ orderId +
" itemNumber:"
+ itemNumber +
" invoice:"
+ invoice +
" shippingDate:"
+ shippingDate;
}
}
|
Now we have to expose the class “OrderService” by an endpoint. For this achieve we need to use a class which extends SpringBeanAutowiringSupport spring’s class. Take a look at the code.
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
|
package
it.springjaxws;
import
javax.jws.WebMethod;
import
javax.jws.WebParam;
import
javax.jws.WebService;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.web.context.support.SpringBeanAutowiringSupport;
@WebService
(serviceName=
"OrderService"
)
public
class
OrderServiceEndpoint
extends
SpringBeanAutowiringSupport{
@Autowired
private
OrderService orderService;
@WebMethod
public
void
Check(
@WebParam
(name =
"order"
) Order order)
throws
Exception
{
orderService.Check(order);
}
@WebMethod
public
Order Process(
@WebParam
(name =
"order"
) Order order)
{
return
orderService.Process(order);
}
@WebMethod
public
Order Shipping(
@WebParam
(name =
"order"
) Order order)
{
return
orderService.Shipping(order);
}
}
|
Briefly, we’ve mapped the orderService methods with the WebMethod.
The spring configuration file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:context
=
"http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
<!-- Use @Component annotations for bean definitions -->
<
context:component-scan
base-package
=
"it.springjaxws"
/>
<
bean
id
=
"orderService"
class
=
"it.springjaxws.OrderServiceImpl"
/>
<
bean
class
=
"org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"
>
</
bean
>
<
bean
id
=
"orderServiceEndpoint"
class
=
"it.springjaxws.OrderServiceEndpoint"
/>
</
beans
>
|
We expose the web service at port 8081 of localhost.
Deploy it to your tomcat and run. You’ll see something like above code when you’ll browse /OrderServiceEndpoint?WSDL
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
85
86
87
88
89
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net.
RI's version is JAX-WS RI 2.1.6 in JDK 6. -->
<!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net.
RI's version is JAX-WS RI 2.1.6 in JDK 6. -->
name
=
"OrderService"
>
<
types
>
<
xsd:schema
>
</
xsd:schema
>
</
types
>
<
message
name
=
"Check"
>
<
part
name
=
"parameters"
element
=
"tns:Check"
></
part
>
</
message
>
<
message
name
=
"CheckResponse"
>
<
part
name
=
"parameters"
element
=
"tns:CheckResponse"
></
part
>
</
message
>
<
message
name
=
"Exception"
>
<
part
name
=
"fault"
element
=
"tns:Exception"
></
part
>
</
message
>
<
message
name
=
"Process"
>
<
part
name
=
"parameters"
element
=
"tns:Process"
></
part
>
</
message
>
<
message
name
=
"ProcessResponse"
>
<
part
name
=
"parameters"
element
=
"tns:ProcessResponse"
></
part
>
</
message
>
<
message
name
=
"Shipping"
>
<
part
name
=
"parameters"
element
=
"tns:Shipping"
></
part
>
</
message
>
<
message
name
=
"ShippingResponse"
>
<
part
name
=
"parameters"
element
=
"tns:ShippingResponse"
></
part
>
</
message
>
<
portType
name
=
"OrderServiceEndpoint"
>
<
operation
name
=
"Check"
>
<
input
message
=
"tns:Check"
></
input
>
<
output
message
=
"tns:CheckResponse"
></
output
>
<
fault
message
=
"tns:Exception"
name
=
"Exception"
></
fault
>
</
operation
>
<
operation
name
=
"Process"
>
<
input
message
=
"tns:Process"
></
input
>
<
output
message
=
"tns:ProcessResponse"
></
output
>
</
operation
>
<
operation
name
=
"Shipping"
>
<
input
message
=
"tns:Shipping"
></
input
>
<
output
message
=
"tns:ShippingResponse"
></
output
>
</
operation
>
</
portType
>
<
binding
name
=
"OrderServiceEndpointPortBinding"
type
=
"tns:OrderServiceEndpoint"
>
style
=
"document"
></
soap:binding
>
<
operation
name
=
"Check"
>
<
soap:operation
soapAction
=
""
></
soap:operation
>
<
input
>
<
soap:body
use
=
"literal"
></
soap:body
>
</
input
>
<
output
>
<
soap:body
use
=
"literal"
></
soap:body
>
</
output
>
<
fault
name
=
"Exception"
>
<
soap:fault
name
=
"Exception"
use
=
"literal"
></
soap:fault
>
</
fault
>
</
operation
>
<
operation
name
=
"Process"
>
<
soap:operation
soapAction
=
""
></
soap:operation
>
<
input
>
<
soap:body
use
=
"literal"
></
soap:body
>
</
input
>
<
output
>
<
soap:body
use
=
"literal"
></
soap:body
>
</
output
>
</
operation
>
<
operation
name
=
"Shipping"
>
<
soap:operation
soapAction
=
""
></
soap:operation
>
<
input
>
<
soap:body
use
=
"literal"
></
soap:body
>
</
input
>
<
output
>
<
soap:body
use
=
"literal"
></
soap:body
>
</
output
>
</
operation
>
</
binding
>
<
service
name
=
"OrderService"
>
<
port
name
=
"OrderServiceEndpointPort"
binding
=
"tns:OrderServiceEndpointPortBinding"
>
</
port
>
</
service
>
</
definitions
>
|
In the next part I describe how consume it.
UPDATE
You can find very useful to host the web services in the same web server port (the 8080 for tomcat). For this purpose you have to use JAX-WS commons from Metro project of glassfish. More info are available at this url http://jax-ws-commons.java.net/spring/
To apply this technology at the previous example, we need to change and update some files.
First, in web.xml, we put the servlet definition
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
|
<
web-app
id
=
"WebApp_ID"
version
=
"2.4"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
<
display-name
>SpringJaxWsEmbedded</
display-name
>
<
servlet
>
<
servlet-name
>jaxwsembedded</
servlet-name
>
<
servlet-class
>
com.sun.xml.ws.transport.http.servlet.WSSpringServlet
</
servlet-class
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>jaxwsembedded</
servlet-name
>
<
url-pattern
>/order</
url-pattern
>
</
servlet-mapping
>
<!-- Register Spring Listener -->
<
listener
>
<
listener-class
>
org.springframework.web.context.ContextLoaderListener
</
listener-class
>
</
listener
>
</
web-app
>
|
After this, we edit the applicationContext.xml file
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
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:ws
=
"http://jax-ws.dev.java.net/spring/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
<!-- Use @Component annotations for bean definitions -->
<
context:component-scan
base-package
=
"it.springjaxwsembedded"
/>
<
bean
id
=
"orderService"
class
=
"it.springjaxws.OrderServiceImpl"
/>
<
wss:binding
url
=
"/order"
>
<
wss:service
>
<
ws:service
bean
=
"#orderWs"
/>
</
wss:service
>
</
wss:binding
>
<!-- Web service methods -->
<
bean
id
=
"orderWs"
class
=
"it.springjaxws.OrderServiceEndpoint"
/>
</
beans
>
|
Last point is OrderServiceEndpoint definition
1
2
3
|
public
class
OrderServiceEndpoint {
...
}
|
We’ve removed the SpringBeanAutowiringSupport extension.