http://fuxueliang.iteye.com/blog/175184
Spring Web Service是Spring社區(qū)基于Spring提供的一個關(guān)注于創(chuàng)建”文檔驅(qū)動”的Web Service的模塊, 它的主要目標(biāo)是方便基于”契約優(yōu)先”(Contract-First)的SOAP服務(wù)的開發(fā). 好像沒有多少人討論, 大多數(shù)的話題都是圍繞xfire, cxf, axis/axis2等主流的Web Service框架.盡管是從事這方面的工作, 不過實際開發(fā)中還是公司內(nèi)部開發(fā)的一個Web Service模塊, 發(fā)現(xiàn)與Spring提供的這個模塊的構(gòu)架很像,所以拿出來學(xué)習(xí)學(xué)習(xí).還是先來跑一個類似于Hello Wrold的例子吧.
?
1, 確定SOAP Body中包含的xml
客戶端向服務(wù)端發(fā)出的xml如下:
Java代碼 <?xml?version="1.0"?encoding="UTF-8"?> ??
<HelloRequest?xmlns=”http://www.fuxueliang.com/ws/hello”?> ?? ????Rondy.F ?? </HelloRequest>???
<?xml version="1.0" encoding="UTF-8"?><HelloRequest xmlns=”http://www.fuxueliang.com/ws/hello” > Rondy.F</HelloRequest>?
?
服務(wù)端返回的xml如下:
Java代碼 <?xml?version="1.0"?encoding="UTF-8"?> ??
<HelloResponse?xmlns=”http://www.fuxueliang.com/ws/hello”?> ?? ????Hello,?Rondy.F! ?? </HelloResponse>??
<?xml version="1.0" encoding="UTF-8"?><HelloResponse xmlns=”http://www.fuxueliang.com/ws/hello” > Hello, Rondy.F!</HelloResponse>
?
2, 確定WSDL
Java代碼 <?xml?version="1.0"?encoding="UTF-8"?> ??
<wsdl:definitions? ?? ????xmlns:wsdl=”http://schemas.xmlsoap.org/wsdl/”? ?? ????xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"?? ????xmlns:schema=”http://www.fuxueliang.com/ws/hello” ?? ????xmlns:tns="http://www.fuxueliang.com/ws/hello/definitions"?? ????targetNamespace="http://www.fuxueliang.com/ws/hello/definitions">???? ?? ????<wsdl:types> ?? ????<schema?xmlns="htp://www.w3.org/2001/XMLSchema"?? ?? ????????argetNamespace="http://www.fuxueliang.com/ws/hello"> ?? ????????<element?name="HelloRequest"?type="string"?/> ?? ????????<element?name="HelloResponse"?type="string"?/> ?? ????</schema> ?? ????</wsdl:types> ?? ????<wsdl:message?name="HelloRequest"> ?? ????????<wsdl:part?element="schema:HelloRequest"?name="HelloRequest"?/> ?? ????</wsdl:message> ?? ????<wsdl:message?name="HelloResponse"> ?? ????????<wsdl:part?element="schema:HelloResponse"?name="HelloResponse"?/> ?? ????</wsdl:message> ?? ????<wsdl:portType?name="HelloPortType"> ?? ????????<wsdl:operation?name="Hello"> ?? ????????????<wsdl:input?message="tns:HelloRequest"?name="HelloRequest"?/> ?? ????????????<wsdl:output?message="tns:HelloResponse"?name="HelloResponse"?/> ?? ????????</wsdl:operation> ?? ????</wsdl:portType> ?? ????<wsdl:binding?name="HelloBinding"?type="tns:HelloPortType"> ?? ????????<soap:binding?style="document"?transport="http://schemas.xmlsoap.org/soap/http"?/> ?? ????????<wsdl:operation?name="Hello"> ?? ????????????<soap:operation?soapAction=""?/> ?? ????????????<wsdl:input?name="HelloRequest"> ?? ????????????????<soap:body?use="literal"?/> ?? ????????????</wsdl:input> ?? ????????????<wsdl:output?name="HelloResponse"> ?? ????????????????<soap:body?use="literal"?/> ?? ????????????</wsdl:output> ?? ????????</wsdl:operation> ?? ????</wsdl:binding> ?? ????<wsdl:service?name="HelloService"> ?? ????????<wsdl:port?binding="tns:HelloBinding"?name="HelloPort"> ?? ????????????<soap:address?location="http://localhost:8080/springws/webservice"?/> ?? ????????</wsdl:port> ?? ????</wsdl:service> ?? </wsdl:definitions>??
<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions xmlns:wsdl=”http://schemas.xmlsoap.org/wsdl/” xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:schema=”http://www.fuxueliang.com/ws/hello” xmlns:tns="http://www.fuxueliang.com/ws/hello/definitions" targetNamespace="http://www.fuxueliang.com/ws/hello/definitions"> <wsdl:types> <schema xmlns="htp://www.w3.org/2001/XMLSchema" argetNamespace="http://www.fuxueliang.com/ws/hello"> <element name="HelloRequest" type="string" /> <element name="HelloResponse" type="string" /> </schema> </wsdl:types> <wsdl:message name="HelloRequest"> <wsdl:part element="schema:HelloRequest" name="HelloRequest" /> </wsdl:message> <wsdl:message name="HelloResponse"> <wsdl:part element="schema:HelloResponse" name="HelloResponse" /> </wsdl:message> <wsdl:portType name="HelloPortType"> <wsdl:operation name="Hello"> <wsdl:input message="tns:HelloRequest" name="HelloRequest" /> <wsdl:output message="tns:HelloResponse" name="HelloResponse" /> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HelloBinding" type="tns:HelloPortType"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="Hello"> <soap:operation soapAction="" /> <wsdl:input name="HelloRequest"> <soap:body use="literal" /> </wsdl:input> <wsdl:output name="HelloResponse"> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloService"> <wsdl:port binding="tns:HelloBinding" name="HelloPort"> <soap:address location="http://localhost:8080/springws/webservice" /> </wsdl:port> </wsdl:service></wsdl:definitions>
??
?3, 創(chuàng)建一個Web項目, 由于Spring Web Service是基于Spring MVC的, 在web.xml中添加如下servlet, 并在WEB-INF下建立SpringMVC的默認配置文件spring-ws-servlet.xml:
Java代碼 <servlet>????? ??
????<servlet-name>spring-ws</servlet-name>?????? ?? ????<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class> ?? </servlet> ?? <servlet-mapping> ?? ????<servlet-name>spring-ws</servlet-name> ?? ????<url-pattern>/*</url-pattern> ?? </servlet-mapping>??
<servlet> <servlet-name>spring-ws</servlet-name> <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class></servlet><servlet-mapping> <servlet-name>spring-ws</servlet-name> <url-pattern>/*</url-pattern></servlet-mapping>
?
4, 創(chuàng)建業(yè)務(wù)方法及具體實現(xiàn)如下:
Java代碼 /** ?
?*?@author?Rondy.F ? ?*? ? ?*/?? public?interface?HelloService?{ ?? ?? ????String?hello(String?name); ?? ?? }??
/** * @author Rondy.F * */public interface HelloService { String hello(String name);}
?
Java代碼 /** ?
?*?@author?Rondy.F ? ?*? ? ?*/?? public?class?HelloServiceImpl?implements?HelloService?{ ?? ?? ????public?String?hello(String?name)?{ ?? ????????return?"Hello,?"?+?name?+?"!"; ?? ????} ?? ?? }??
/** * @author Rondy.F * */public class HelloServiceImpl implements HelloService { public String hello(String name) { return "Hello, " + name + "!"; }}
?
5, 實現(xiàn)一個EndPoint來處理接收到的xml及返回xml.當(dāng)然, Spring Web Service提供了很多抽象的實現(xiàn), 包括Dom4j, JDom等等.這里我們使用JDK自帶的, 需要繼承org.springframework.ws.server.endpoint.AbstractDomPayloadEndpoint.
Java代碼 /** ?
?*?@author?Rondy.F ? ?*? ? ?*/?? public?class?HelloEndPoint?extends?AbstractDomPayloadEndpoint?{ ?? ?? ????/** ? ?????*?Namespace?of?both?request?and?response. ? ?????*/?? ????public?static?final?String?NAMESPACE_URI?=?"http://www.fuxueliang.com/ws/hello"; ?? ?? ????/** ? ?????*?The?local?name?of?the?expected?request. ? ?????*/?? ????public?static?final?String?HELLO_REQUEST_LOCAL_NAME?=?"HelloRequest"; ?? ?? ????/** ? ?????*?The?local?name?of?the?created?response. ? ?????*/?? ????public?static?final?String?HELLO_RESPONSE_LOCAL_NAME?=?"HelloResponse"; ?? ?? ????private?HelloService?helloService; ?? ?? ????@Override ?? ????protected?Element?invokeInternal(Element?requestElement,?Document?document)?throws?Exception?{?????? ?? ????????Assert.isTrue(NAMESPACE_URI.equals(requestElement.getNamespaceURI()),?"Invalid?namespace");????? ?? ????????Assert.isTrue(HELLO_REQUEST_LOCAL_NAME.equals(requestElement.getLocalName()),?"Invalid?local?name"); ?? ????????NodeList?children?=?requestElement.getChildNodes(); ?? ????????Text?requestText?=?null; ?? ????????for?(int?i?=?0 ;?i?<?children.getLength();?i++)?{ ?? ????????????if?(children.item(i).getNodeType()?==?Node.TEXT_NODE)?{ ?? ????????????????requestText?=?(Text)?children.item(i); ?? ????????????????break; ?? ????????????} ?? ????????} ?? ????????if?(requestText?==?null)?{ ?? ????????????throw?new?IllegalArgumentException("Could?not?find?request?text?node"); ?? ????????} ?? ?? ????????String?response?=?helloService.hello(requestText.getNodeValue()); ?? ????????Element?responseElement?=?document.createElementNS(NAMESPACE_URI,?HELLO_RESPONSE_LOCAL_NAME); ?? ????????Text?responseText?=?document.createTextNode(response); ?? ????????responseElement.appendChild(responseText); ?? ????????return?responseElement; ?? ????} ?? ?? ????public?void?setHelloService(HelloService?helloService)?{ ?? ????????this.helloService?=?helloService; ?? ????} ?? ?? }??
/** * @author Rondy.F * */public class HelloEndPoint extends AbstractDomPayloadEndpoint { /** * Namespace of both request and response. */ public static final String NAMESPACE_URI = "http://www.fuxueliang.com/ws/hello"; /** * The local name of the expected request. */ public static final String HELLO_REQUEST_LOCAL_NAME = "HelloRequest"; /** * The local name of the created response. */ public static final String HELLO_RESPONSE_LOCAL_NAME = "HelloResponse"; private HelloService helloService; @Override protected Element invokeInternal(Element requestElement, Document document) throws Exception { Assert.isTrue(NAMESPACE_URI.equals(requestElement.getNamespaceURI()), "Invalid namespace"); Assert.isTrue(HELLO_REQUEST_LOCAL_NAME.equals(requestElement.getLocalName()), "Invalid local name"); NodeList children = requestElement.getChildNodes(); Text requestText = null; for (int i = 0; i < children.getLength(); i++) { if (children.item(i).getNodeType() == Node.TEXT_NODE) { requestText = (Text) children.item(i); break; } } if (requestText == null) { throw new IllegalArgumentException("Could not find request text node"); } String response = helloService.hello(requestText.getNodeValue()); Element responseElement = document.createElementNS(NAMESPACE_URI, HELLO_RESPONSE_LOCAL_NAME); Text responseText = document.createTextNode(response); responseElement.appendChild(responseText); return responseElement; } public void setHelloService(HelloService helloService) { this.helloService = helloService; }}
?
6, 修改配置文件spring-ws-servlet.xml.
Java代碼 <?xml?version="1.0"?encoding="UTF-8"?> ??
<beans?xmlns="http://www.springframework.org/schema/beans"? ?? ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?? ????xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> ?? ?? ????<bean?id="payloadMapping"?class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping"> ?? ????????<property?name="endpointMap"> ?? ????????????<map> ?? ????????????????<entry?key=”{http://www.fuxueliang.com/ws/hello}HelloRequest”?/>?????? ?? ????????????????????<ref?bean="helloEndpoint"?/> ?? ????????????????</entry> ?? ????????????</map> ?? ????????</property> ?? ????</bean> ?? ????<bean?id="hello"?class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition"> ?? ????????<property?name="wsdl"?value="/WEB-INF/hello.wsdl"/> ?? ????</bean> ?? ????<bean?id="helloEndpoint"?class="org.rondy.ws.HelloEndPoint"> ?? ????????<property?name="helloService"?ref="helloService"?/> ?? ????</bean> ?? ????<bean?id="helloService"?class="org.rondy.service.HelloServiceImpl"?/> ?? </beans>??
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="payloadMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping"> <property name="endpointMap"> <map> <entry key=”{http://www.fuxueliang.com/ws/hello}HelloRequest” /> <ref bean="helloEndpoint" /> </entry> </map> </property> </bean> <bean id="hello" class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition"> <property name="wsdl" value="/WEB-INF/hello.wsdl"/> </bean> <bean id="helloEndpoint" class="org.rondy.ws.HelloEndPoint"> <property name="helloService" ref="helloService" /> </bean> <bean id="helloService" class="org.rondy.service.HelloServiceImpl" /></beans>
???
注: 其中最主要的bean就是payloadMapping, 它定義了接收到的message與endpoint之間的mapping關(guān)系:將SOAP Body中包含的xml的根節(jié)點的QName為{http://www.fuxueliang.com/ws/hello}HelloRequest交給helloEndpoint處理 . SimpleWsdl11Definition這個bean則是定義了這個服務(wù)的wsdl, 訪問地址是:http://localhost:8080/springws/hello.wsdl.
?
7, 客戶端(saaj實現(xiàn))的代碼如下:
Java代碼 /** ?
?*? ? ?*?@author?Rondy.F ? ?*? ? ?*/?? public?class?HelloWebServiceClient?{ ?? ?? ????public?static?final?String?NAMESPACE_URI?=?"http://www.fuxueliang.com/ws/hello"; ?? ?? ????public?static?final?String?PREFIX?=?"tns"; ?? ?? ????private?SOAPConnectionFactory?connectionFactory; ?? ?? ????private?MessageFactory?messageFactory; ?? ?? ????private?URL?url; ?? ?? ????public?HelloWebServiceClient(String?url)?throws?SOAPException,?MalformedURLException?{ ?? ????????connectionFactory?=?SOAPConnectionFactory.newInstance(); ?? ????????messageFactory?=?MessageFactory.newInstance(); ?? ????????this.url?=?new?URL(url); ?? ????} ?? ?? ????private?SOAPMessage?createHelloRequest()?throws?SOAPException?{ ?? ????????SOAPMessage?message?=?messageFactory.createMessage(); ?? ????????SOAPEnvelope?envelope?=?message.getSOAPPart().getEnvelope(); ?? ????????Name?helloRequestName?=?envelope.createName("HelloRequest",?PREFIX,?NAMESPACE_URI); ?? ????????SOAPBodyElement?helloRequestElement?=?message.getSOAPBody().addBodyElement(helloRequestName); ?? ????????helloRequestElement.setValue("Rondy.F"); ?? ????????return?message; ?? ????} ?? ?? ????public?void?callWebService()?throws?SOAPException,?IOException?{ ?? ????????SOAPMessage?request?=?createHelloRequest(); ?? ????????SOAPConnection?connection?=?connectionFactory.createConnection(); ?? ????????SOAPMessage?response?=?connection.call(request,?url); ?? ????????if?(!response.getSOAPBody().hasFault())?{ ?? ????????????writeHelloResponse(response); ?? ????????}?else?{ ?? ????????????SOAPFault?fault?=?response.getSOAPBody().getFault(); ?? ????????????System.err.println("Received?SOAP?Fault"); ?? ????????????System.err.println("SOAP?Fault?Code?:"?+?fault.getFaultCode()); ?? ????????????System.err.println("SOAP?Fault?String?:"?+?fault.getFaultString()); ?? ????????} ?? ????} ?? ?? ????@SuppressWarnings ("unchecked") ?? ????private?void?writeHelloResponse(SOAPMessage?message)?throws?SOAPException?{ ?? ????????SOAPEnvelope?envelope?=?message.getSOAPPart().getEnvelope(); ?? ????????Name?helloResponseName?=?envelope.createName("HelloResponse",?PREFIX,?NAMESPACE_URI); ?? ????????Iterator?childElements?=?message.getSOAPBody().getChildElements(helloResponseName); ?? ????????SOAPBodyElement?helloResponseElement?=?(SOAPBodyElement)?childElements.next(); ?? ????????String?value?=?helloResponseElement.getTextContent(); ?? ????????System.out.println("Hello?Response?["?+?value?+?"]"); ?? ????} ?? ?? ????public?static?void?main(String[]?args)?throws?Exception?{ ?? ????????String?url?=?"http://localhost:8080/springws"; ?? ????????HelloWebServiceClient?helloClient?=?new?HelloWebServiceClient(url); ?? ????????helloClient.callWebService(); ?? ????} ?? }??
/** * * @author Rondy.F * */public class HelloWebServiceClient { public static final String NAMESPACE_URI = "http://www.fuxueliang.com/ws/hello"; public static final String PREFIX = "tns"; private SOAPConnectionFactory connectionFactory; private MessageFactory messageFactory; private URL url; public HelloWebServiceClient(String url) throws SOAPException, MalformedURLException { connectionFactory = SOAPConnectionFactory.newInstance(); messageFactory = MessageFactory.newInstance(); this.url = new URL(url); } private SOAPMessage createHelloRequest() throws SOAPException { SOAPMessage message = messageFactory.createMessage(); SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); Name helloRequestName = envelope.createName("HelloRequest", PREFIX, NAMESPACE_URI); SOAPBodyElement helloRequestElement = message.getSOAPBody().addBodyElement(helloRequestName); helloRequestElement.setValue("Rondy.F"); return message; } public void callWebService() throws SOAPException, IOException { SOAPMessage request = createHelloRequest(); SOAPConnection connection = connectionFactory.createConnection(); SOAPMessage response = connection.call(request, url); if (!response.getSOAPBody().hasFault()) { writeHelloResponse(response); } else { SOAPFault fault = response.getSOAPBody().getFault(); System.err.println("Received SOAP Fault"); System.err.println("SOAP Fault Code :" + fault.getFaultCode()); System.err.println("SOAP Fault String :" + fault.getFaultString()); } } @SuppressWarnings("unchecked") private void writeHelloResponse(SOAPMessage message) throws SOAPException { SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); Name helloResponseName = envelope.createName("HelloResponse", PREFIX, NAMESPACE_URI); Iterator childElements = message.getSOAPBody().getChildElements(helloResponseName); SOAPBodyElement helloResponseElement = (SOAPBodyElement) childElements.next(); String value = helloResponseElement.getTextContent(); System.out.println("Hello Response [" + value + "]"); } public static void main(String[] args) throws Exception { String url = "http://localhost:8080/springws"; HelloWebServiceClient helloClient = new HelloWebServiceClient(url); helloClient.callWebService(); }}
? ?
幾點看法:
1, 從上面代碼可以看出, 比較麻煩的部分就是客戶端和服務(wù)端對xml處理, 當(dāng)然一部分原因是由于選擇了JDK自帶的xml處理器. 在實際運用中可以考慮xml的綁定工具, 如jibx, castor等等.那么可能的EndPoint實現(xiàn)就只需要實現(xiàn)類似下面的方法:
?
Java代碼 protected?HelloResponse?invokeInternal(HelloRequest?request);??
protected HelloResponse invokeInternal(HelloRequest request);
?
2, 看看wsdl的訪問方式, 以.wsdl結(jié)尾, 而不是?wsdl, 看起來總是不爽, 看了一下源代碼,沒有顯式改變的方法, 看樣子只能自己擴展了.而且上例子中還可以以http://localhost:8080/springws/abcdx/hello.wsdl得到wsdl, 哎...
3, 對于客戶端, 直接用HttpClient, post到服務(wù)端.
?
前行的路標(biāo):
1, 毫無疑問, Spring總為你想的很全, 從SpringMVC提供的那么多的Controller就可以看出來.這次也不例外,jibx, castor, xmlBeans, jaxb, xstream全給你準(zhǔn)備了
2, EndPointMapping也提供了很多選擇,包括method, 還有注解的方式
?
這只是對Spring Web Service學(xué)習(xí)的一個過程, 有興趣的可以一起交流一下!后面將根據(jù)官方提供的文檔來學(xué)習(xí)一下它所提供的各種功能以及分析一下它的整個流程 .
?
總結(jié)
以上是生活随笔 為你收集整理的Spring Web Service 学习之Hello World篇 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。