Creating a Web service with Spring-WS http://docs.spring.io/spring-ws/site/reference/html/server.html
难点:
1. wsdl文件说明;
WSDL 详解 http://panyongzheng.iteye.com/blog/1669447
2. 发布点EndPoint的实现;
3. 客户端如何发送和检索响应信息;
技巧: 使用SAAJ发送和接收SOAP消息 http://www.ibm.com/developerworks/cn/xml/x-jaxmsoap/
提供和响应双方共识的契约
hello.wsdl
<?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.ispring.com/ws/hello" xmlns:tns="http://www.ispring.com/ws/hello/definitions" targetNamespace="http://www.ispring.com/ws/hello/definitions"> <wsdl:types> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.ispring.com/ws/hello"> <element name="typeRequest" type="string" /> <element name="typeResponse" type="string" /> </schema> </wsdl:types> <wsdl:message name="messageRequest"> <wsdl:part element="schema:typeRequest" name="messageRequestName" /> </wsdl:message> <wsdl:message name="messageResponse"> <wsdl:part element="schema:typeResponse" name="messageResponseName" /> </wsdl:message> <wsdl:portType name="HelloPortType"> <wsdl:operation name="sayHello"> <wsdl:input message="tns:messageRequest" name="portTypeRequest" /> <wsdl:output message="tns:messageResponse" name="portTypeResponse" /> </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="sayHello"> <soap:operation soapAction="" /> <wsdl:input name="portTypeRequest"> <soap:body use="literal" /> </wsdl:input> <wsdl:output name="portTypeResponse"> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloService"> <wsdl:port binding="tns:HelloBinding" name="HelloPort"> <!-- 这里是ws客户端访问地址 --> <soap:address location="http://localhost:8080/SpringWS/ws/hello" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
源码
=======================================================================
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>SpringWS</groupId> <artifactId>SpringWS</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>3.2.8.RELEASE</spring.version> <spring.ws.version>2.1.4.RELEASE</spring.ws.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>${spring.ws.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <url>http://localhost:8080/manager/text</url> <username>admin</username> <password>admin</password> <path>/SpringWS</path> </configuration> </plugin> </plugins> </build> </project>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0"> <display-name>Spring3MVC</display-name> <!-- 配置SpringMVC的applicationContext.xml文件位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 配置SpringMVC --> <servlet> <servlet-name>spring-mvc-servlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring-mvc-servlet</servlet-name> <url-pattern>/web/*</url-pattern> </servlet-mapping> <!-- 配置SpringWS --> <servlet> <servlet-name>spring-ws-servlet</servlet-name> <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-ws-servlet.xml</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring-ws-servlet</servlet-name> <url-pattern>*.wsdl</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>spring-ws-servlet</servlet-name> <url-pattern>/ws/*</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd" default-autowire="byName" default-lazy-init="true"> <context:component-scan base-package="com"> <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation" /> </context:component-scan> </beans>
spring-mvc-servlet.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" 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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <context:component-scan base-package="com"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository" /> </context:component-scan> <mvc:annotation-driven/> <mvc:resources location="/resources/" mapping="/resources/**"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
spring-ws-servlet.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" 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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- 定义了接收到的message与endpoint之间的mapping关系:将SOAP Body中包含的xml的根节点的QName为{http://www.fuxueliang.com/ws/hello}HelloRequest交给helloEndpoint处理. --> <bean id="payloadMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping"> <property name="endpointMap"> <map> <entry key="{http://www.ispring.com/ws/hello}serviceRequest"> <ref bean="helloEndpoint"/> </entry> </map> </property> </bean> <!-- SimpleWsdl11Definition这个bean则是定义了这个服务的wsdl, 访问地址是: http://localhost:8080/springws/hello.wsdl. --> <bean id="hello" class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition"> <property name="wsdl" value="classpath:/hello.wsdl"></property> </bean> <bean id="helloEndpoint" class="com.endPoint.HelloEndPoint"> <property name="helloService" ref="helloService"></property> </bean> <bean id="helloService" class="com.service.impl.HelloServiceImpl"></bean> </beans>
接口于实现
HelloService.java
package com.service; /** * Created by Administrator on 14-5-19. */ public interface HelloService { public String sayHello(String name); }
HelloServiceImpl.java
package com.service.impl; import com.service.HelloService; /** * Created by Administrator on 14-5-19. */ public class HelloServiceImpl implements HelloService { @Override public String sayHello(String name) { return "返回到客户端信息: Hello, " + name + "!"; } }
HelloEndPoint.java
实现一个EndPoint来处理接收到的xml及返回xml.当然, Spring Web Service提供了很多抽象的实现, 包括Dom4j, JDom等等.这里我们使用JDK自带的, 需要继承org.springframework.ws.server.endpoint.AbstractDomPayloadEndpoint.
package com.endPoint; import com.service.HelloService; import org.springframework.util.Assert; import org.springframework.ws.server.endpoint.AbstractDomPayloadEndpoint; import org.w3c.dom.*; /** * Created by Administrator on 14-5-19. * 实现一个EndPoint来处理接收到的xml及返回xml.当然, Spring Web Service提供了很多抽象的实现, * 包括Dom4j, JDom等等.这里我们使用JDK自带的, * 需要继承org.springframework.ws.server.endpoint.AbstractDomPayloadEndpoint. */ public class HelloEndPoint extends AbstractDomPayloadEndpoint { //请求和响应的命名空间 public static final String NAMESPACE_URI = "http://www.ispring.com/ws/hello"; //预期要求的本地名称 public static final String HELLO_REQUEST_LOCAL_NAME = "serviceRequest"; // 创建响应的本地名称 public static final String HELLO_RESPONSE_LOCAL_NAME = "serviceResponse"; 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); } } if(requestText == null){ throw new IllegalArgumentException("Could not find request text node"); } //信息处理 String response = helloService.sayHello(requestText.getNodeValue()); //响应给客户端 Element responseElement = document.createElementNS(NAMESPACE_URI, HELLO_RESPONSE_LOCAL_NAME); Text responseText = document.createTextNode(response); responseElement.appendChild(responseText); return responseElement; } public HelloService getHelloService() { return helloService; } public void setHelloService(HelloService helloService) { this.helloService = helloService; } }
7、HelloWebServiceClient.java(saaj实现)
package com.client; /** * Created by Administrator on 14-5-19. */ import javax.xml.soap.*; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; public class HelloWebServiceClient { public static final String NAMESPACE_URI = "http://www.ispring.com/ws/hello"; public static final String PREFIX = "tns"; private SOAPConnectionFactory connectionFactory; private MessageFactory messageFactory; private URL url; public HelloWebServiceClient(String url) throws UnsupportedOperationException, SOAPException, MalformedURLException{ connectionFactory = SOAPConnectionFactory.newInstance(); messageFactory = MessageFactory.newInstance(); this.url = new URL(url); } /** *创建要远程调用的负载 * @throws SOAPException */ private SOAPMessage createHelloRequest() throws SOAPException{ SOAPMessage message = messageFactory.createMessage(); SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); Name helloRequestName = envelope.createName("serviceRequest",PREFIX,NAMESPACE_URI); SOAPBodyElement helloRequestElement = message.getSOAPBody().addBodyElement(helloRequestName); helloRequestElement.setValue("提交到服务器信息"); return message; } public void callWebService() throws SOAPException{ 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()); } } private void writeHelloResponse(SOAPMessage message) throws SOAPException{ SOAPEnvelope envelope = message.getSOAPPart().getEnvelope(); Name helloResponseName = envelope.createName("serviceResponse",PREFIX,NAMESPACE_URI); Iterator childElements = message.getSOAPBody().getChildElements(helloResponseName); SOAPBodyElement helloResponseElement = (SOAPBodyElement)childElements.next(); String value = helloResponseElement.getTextContent(); System.out.println("调用Spring-WS返回信息: [" + value + "]"); } public static void main(String[] args) throws UnsupportedOperationException, MalformedURLException, SOAPException { //在wsdl已经规定好了访问地址 String url = "http://localhost:8080/SpringWS/ws/hello"; HelloWebServiceClient helloClient = new HelloWebServiceClient(url); helloClient.callWebService(); } }