天天看點

Maven搭建SpringWebService(1)

此文是寫給像我這樣的菜鳥的,是以比較簡單,大神可以略過。

我做過的項目基本上都使用的CXF或AXIS搭建WebService。SpringWebService(以下簡寫為SWS)是我這幾天一直在琢磨學習的,可是第一步完成一個Demo就難住我了。經過幾天空餘時間不懈的努力。終于完成了這個Demo。

使用工具:Eclipse4.4,JDK7,Tomcat7,Maven3

第一步:在Eclipse中建構一個Mevan的Web項目,項目結構如下:

Maven搭建SpringWebService(1)
Maven搭建SpringWebService(1)

第二步:項目中pom配置,配置如下:

<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.yonyou.dms</groupId>
	<artifactId>dmsws</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>dmsws Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.ws</groupId>
			<artifactId>spring-ws-core</artifactId>
			<version>2.2.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.ws</groupId>
			<artifactId>spring-xml</artifactId>
			<version>2.2.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>wsdl4j</groupId>
			<artifactId>wsdl4j</artifactId>
			<version>1.6.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.ws.xmlschema</groupId>
			<artifactId>xmlschema-core</artifactId>
			<version>2.2.0</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
		<finalName>dmsws</finalName>
	</build>
</project>
           

以上2步完成了基本環境的搭建,下面開始編寫SWS。

SWS差別于CXF,AXIS之一就是在于,我之前做的項目服務端WS的編寫都是從代碼開始的,而SWS是從資料描述開始的,也就是先編寫XML,這裡的XML指XSD檔案,即XML Schema檔案,與DTD檔案的作用類似,都是用來描述XML文檔結構的。不過直接編寫XSD檔案還是有點難度的,好在我們有很多工具幫助我們通過XML資料檔案反向生成XSD檔案。換句話說,我們如果需要給兩個系統做一個WS,我們可以先寫一個2個系統都可以解析的XML資料檔案。例如我現在有個2個系統。分别叫使用者管理系統(以下叫A系統),另一個是财務系統(以下叫B系統),假設B系統每次新增使用者的時候也需要在A系統中增加相同使用者。(這個例子肯定不符合生産系統的需求,這裡隻是舉例做一個Demo)。

我們現在編寫AB兩個系統都可以解析的XML資料檔案,如下:

<AddUserRequest xmlns="http://www.dmsws.com/ws/schemas">
	<User>
		<UserName>fuxiao</UserName>
		<UserAge>18</UserAge>
		<Pwd>password1234</Pwd>
	</User>
</AddUserRequest>
           

我們現在就可以根據上面的XML文檔反向生成XSD檔案。我們可以借助工具生成,如XMLSpy,這個工具很強大,至于有多強大,我也不是很清楚,隻是周圍的人用的很多。

這裡我是通過Trang Manual這個jar生成XSD檔案的。

Trang Manual官網:http://www.thaiopensource.com/relaxng/trang.html  在此頁面個Download區域下載下傳此jar的zip檔案。

下載下傳解壓,請記住自己的解壓路徑。

這裡有個前提是,自己已經将java環境搭建好了,不知道自己是否搭建好了java環境,window下請在指令行cmd下運作java -version。linux/macos請在terminal下執行此指令,如果可以看到自己配置的jdk版本資訊,就證明java環境變量已經設定好了。

假設:我們将上面的xml資料示例檔案儲存在某個檔案夾下,并給檔案起名叫AddUser.xml,現在我們在指令行下運作以下指令:

java -jar ~/Downloads/trang-20030619/trang.jar -I xml -O xsd ./AddUser.xml ./AddUser.xsd
           

我這裡是在maxos下執行的,windows下請将上面指令中的路徑換為windows路徑即可。如果想知道tang.jar後的參數意義,可執行:

java -jar ~/Downloads/trang-20030619/trang.jar
           

之後為看到參數詳解。

假設你xml檔案沒有問題,且指令正确,執行完以上指令後你會看不到任何資訊回報,證明生成XSD檔案成功(沒有消息就是最好的消息)。因為上面指令将輸出路徑設定為同路徑下,是以我在剛才的AddUser.xml檔案所在檔案夾下就可以看到生成的XSD檔案。如下:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.dmsws.com/ws/schemas" <span style="color:#ff6666;">xmlns:schemas</span>="http://www.dmsws.com/ws/schemas">
  <xs:element name="AddUserRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="<span style="color:#ff6666;">schemas:User</span>"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="User">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="<span style="color:#ff6666;">schemas:UserName</span>"/>
        <xs:element ref="<span style="color:#ff6666;">schemas:UserAge</span>"/>
        <xs:element ref="<span style="color:#ff6666;">schemas:Pwd</span>"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="UserName" type="<span style="color:#ff6666;">xs:NCName</span>"/>
  <xs:element name="UserAge" type="<span style="color:#ff6666;">xs:integer</span>"/>
  <xs:element name="Pwd" type="<span style="color:#ff6666;">xs:NCName</span>"/>
</xs:schema>
           

現在我們需要對上面生成的檔案做一些修改,如生成的資料類型:xs:NCName,修改為xs:string。并将prefix字首schema:修改為ws(修改這裡時,需要修改xs:根屬性中的xslns:schema為xmlns:ws):,修改完畢後如下:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
	elementFormDefault="qualified" targetNamespace="http://www.dmsws.com/ws/schemas"
	xmlns:ws="http://www.dmsws.com/ws/schemas">
	<xs:element name="AddUserRequest">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="User" type="ws:UserType" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:complexType name="UserType">
		<xs:sequence>
			<xs:element ref="ws:UserName"/>
			<xs:element ref="ws:UserAge"/>
			<xs:element ref="ws:Pwd"/>
		</xs:sequence>
	</xs:complexType>
	<xs:element name="UserName" type="xs:string"/>
	<xs:element name="UserAge" type="xs:string" />
	<xs:element name="Pwd" type="xs:string" />
	<xs:element name="AddUserResponse" type="xs:integer" />
</xs:schema>
           

到這一步時,SWS的前置工作就做完了,現在我們就可以在之前建立的maven的web項目中開始寫我們的第一個webservice了。

(XSD的相關内容,大家可以檢視W3CSchool中的教程,URL:http://www.w3school.com.cn/schema/index.asp)

maven的web項目結構我就不具體解釋了,因為相關教程文章很多。

我在java/resources檔案夾下建立的V1檔案夾,并将上面生成的AddUser.xsd檔案放在此檔案夾下,V1檔案夾不是必須的,你也可以直接放在resources檔案夾下。隻不過如果同一個接口有多版本共存時,使用檔案夾劃分我覺得比較好一些。比如V2檔案夾可以存放AddUser.xsd檔案的第二版本。這樣的劃分也是我參考别的教程中的。覺得這樣做的确比較好一些。

接下來配置項目中的web.xml檔案,SWS的配置與SF架構的配置類似。配置如下:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
	<display-name>Archetype Created Web Application</display-name>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath:applicationContext.xml
		</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<servlet>
		<servlet-name>ws</servlet-name>
		<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ws</servlet-name>
		<url-pattern>/service/*</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>ws</servlet-name>
		<url-pattern>*.wsdl</url-pattern>
	</servlet-mapping>
</web-app>
           

MessageDispatcherServlet類似SpringMVC中的DispatcherServlet,是它的子類,用于處理SOAP請求,将請求轉發給對應的服務端點(即我們後面用到的注解@Endpoint)。

我們在web.xml同檔案夾下建立ws-servlet.xml檔案。因為我們在web.xml檔案内使用ws起的servlet名稱,是以此檔案就叫ws-servlet.xml,如果你在web.xml中起名是其他,那麼此檔案就換為名稱-servlet.xml。這裡的配置如下:

<?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-4.0.xsd">
	<!-- WSDL定義 -->
	<bean id="AddUserService"
		class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
		<property name="schemaCollection">
			<bean id="forumSchemaCollection"
				class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
				<property name="xsds">
					<list>
						<value>classpath:v1/adduser.xsd</value>
					</list>
				</property>
				<property name="inline" value="true" />
			</bean>
		</property>
		<property name="schema">
			<bean class="org.springframework.xml.xsd.SimpleXsdSchema">
				<property name="xsd" value="classpath:v1/adduser.xsd" />
			</bean>
		</property>
		<property name="portTypeName" value="AddUserPortType" />
		<!-- 位址可使用Spring的PropertyPlaceholderConfigurer配置 -->
		<property name="locationUri" value="http://localhost:8080/dmsws/service" />
		<property name="targetNamespace" value="http://www.dmsws.com/ws/schemas" />
	</bean>
</beans>
           

這裡我的見解是:ws-servlet.xml中的配置是為了對外釋出WSDL文檔。

這裡我們還剩下最後一步:編寫服務端端點代碼,SWS架構提供了很多對SOAP消息解析的接口,也就是說我們可以選擇我們喜歡的方式解析SOAP消息内容。這裡我使用XPath對消息進行解析。代碼如下:

package com.org.dms.ws.service.ws;

import javax.xml.parsers.DocumentBuilderFactory;

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.Namespace;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import org.springframework.ws.server.endpoint.annotation.XPathParam;
import org.w3c.dom.Element;

@Endpoint
public class AddUserEndpoint {

	private static final String NAMESPACE_URI = "http://www.dmsws.com/ws/schemas";

	@PayloadRoot(localPart = "AddUserRequest", namespace = NAMESPACE_URI)
	@Namespace(prefix = "ws", uri = NAMESPACE_URI)
	@ResponsePayload
	public Element addUser(@XPathParam("//ws:UserName") String userName,
			@XPathParam("//ws:UserAge") String userAge,
			@XPathParam("//ws:Pwd") String pwd) throws Exception {
		System.out.println("userName = " + userName);
		System.out.println("userAge = " + userAge);
		System.out.println("pwd = " + pwd);

		Element response = DocumentBuilderFactory.newInstance()
				.newDocumentBuilder().newDocument()
				.createElementNS(NAMESPACE_URI, "AddUserResponse");
		response.setTextContent("1");
		return response;
	}

}
           

附加元件目至tomcat7中,配置無誤的話,啟動應該是成功的。

在浏覽器下輸入我們的URL:http://localhost:8080/dmsws/AddUserService.wsdl,如果一切配置正确,此時你會看到我們對外釋出的WSDL檔案資訊。

(請在外置浏覽器下檢視此連結位址,之前我在eclipse的内置浏覽器下通路,頁面沒有任何顯示。一片空白,調試了好久,查不到問題,還以為自己哪裡配置錯了,最後無意識的再外面浏覽器下通路,WSDL檔案就直接出來了)

如果我們這一步不編寫服務端點的java類,隻做到ws-servlet.xml配置的哪一步,wsdl文檔是否可以生成呢?答案是可以。wsdl文檔生成并不依賴我們編寫的服務端代碼,如AddUserEndpoint類。SWS架構通過我們配置聲明的DefaultWsdl11Definition類及下面的參數(如XSD檔案等)自動幫我們動态生成WSDL檔案。

WSDL檔案隻是告訴用戶端如何通路我們提供的WebService,而我們編寫的Endpoint類是具體服務的實作。舉個例子ws-servlet.xml就做菜的食材,而我們編寫的Endpoint類是食材加工廠,可以對“傳來”的食材進行加工,至于怎麼加工,就是我們編寫的方法内容了。是以二者缺一不可。

以上是服務端的編寫内容。我在編寫此Demo是遇到了不少問題,是以查了不少資料,主要參考了SWS官網的Doc文檔,還有Spring3.X企業應用開發實戰的附錄内容,還有網上的一些其他Demo。但都有一些問題。希望這邊文章可以幫助跟我一樣遇到問題的人。

服務端生成了,現在還缺少用戶端代碼。下面使用JDK的wsimport指令生成用戶端代碼并進行測試。

JDK指令如下:

wsimport -d ./ -keep -verbose http://localhost:8080/dmsws/service/AddUserService.wsdl
           

-d後面是代碼生成後的儲存路徑,-verbose是顯示生成過程的資訊,-keep是為了生成.java檔案。

參數正确的話,就可以在指定目錄看到生成的java檔案,我們将此檔案Copy至任意EclipseJava工程下,為了簡單,我直接将生成的檔案(包含檔案夾)copy至我們的SWS的demo項目,如下:

Maven搭建SpringWebService(1)

根據我們生成的工具類,我們就可以編寫測試用戶端代碼了,代碼如下:

package com.org.dms.ws.client;

import java.math.BigInteger;

import com.dmsws.ws.schemas.AddUserPortType;
import com.dmsws.ws.schemas.AddUserPortTypeService;
import com.dmsws.ws.schemas.AddUserRequest;
import com.dmsws.ws.schemas.UserType;

public class ActionLogClient {

	public static void main(String[] args) {

			UserType user = new UserType();
			user.setPwd("password1234");
			user.setUserAge("16");
			user.setUserName("fuxiao");
			AddUserRequest request = new AddUserRequest();
			request.setUser(user);
			
			AddUserPortTypeService service = new AddUserPortTypeService();
			AddUserPortType pt = service.getAddUserPortTypeSoap11();
			BigInteger n = pt.addUser(request);
			System.out.println(n);
			
	}

}
           

直接執行main方法,我們就可以在服務端控制台下,看到請求内容,如下:

Maven搭建SpringWebService(1)

至此demo編寫完畢。希望可以幫助到大家,謝謝。

(本人才疏學淺,如有有不正确的地方希望大家海涵。)