spring webservice (一) 伺服器端開發
最近研究了一下spring webservice整合,由于第一次做這個,整合期間遇到了不少問題,在網上查找了好久也沒找到完整實作的server和client的demo,有的問題折騰了我好幾天,看到spring的官網裡面有人提相同的問題,但是都沒人給出解決方案,是以就隻能慢慢摸索,經過艱辛的探索,終于實作了一個完整的demo,在這裡我整理了一下分享給大家,希望能幫助大家解決這方面遇到的問題,由于在下才疏學淺,有的地方可能寫得不是很合理,希望大家提出來探讨一下,互相提高。我會盡量把自己遇到的問題展現出來,然後一一解決,廢話不多說,開始幹活:
第一部分實作spring webservice服務端的開發與部署。
1. 建立一個maven的web項目,完成一些準備工作。
1.1 在pom.xml中加入相關jar包,如下:
<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.zdsoft.webservice</groupId>
<artifactId>spring-webservice-server</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>spring-webservice-server Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
<build>
<finalName>spring-webservice-server</finalName>
</build>
</project>
1.2 建立log4j.xml檔案,配置log4j列印資訊,如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true">
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<param name="Threshold" value="ALL" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss:SSS} %p %l>> %m%n" />
</layout>
</appender>
<root>
<priority value="ALL" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
1.3 為了能讓我們的webservice能和web的容器內建到一起,需要在web.xml裡面做一些配置,如下:
<!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>
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<!--Spring-WS配置檔案的位置,預設尋找[servlet-name]-servlet.xml檔案 -->
<!--<init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/spring-ws-config.xml</param-value>
</init-param> -->
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>*.wsdl</url-pattern>
</servlet-mapping>
</web-app>
解釋上面的配置: transformWsdlLocations設定成true,就是說當你改變了項目名稱或者端口号,你的服務還是可以正常通路的(但是如果你改變了WSDL的通路路徑,釋出服務的代碼也要随之更改的)。
2. 開發webservice核心部分。
2.1 遵循契約優先的方式,我們先完成wsdl檔案的編寫,檔案名:UserService.wsdl,放在WEB-INF/wsdl/下面,内容如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions
targetNamespace="http://webservice.zdsoft.com/namespace/userservice"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://webservice.zdsoft.com/namespace/userservice"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="UserService">
<wsdl:types>
<xsd:schema targetNamespace="http://webservice.zdsoft.com/namespace/userservice">
<!-- xsd part start -->
<xsd:element name="login" type="tns:login" />
<xsd:element name="loginResponse" type="tns:loginResponse" />
<xsd:element name="getUser" type="tns:getUser" />
<xsd:element name="getUserResponse" type="tns:getUserResponse" />
<xsd:complexType name="login">
<xsd:sequence>
<xsd:element name="username" type="xsd:string" />
<xsd:element name="password" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="loginResponse">
<xsd:sequence>
<xsd:element name="info" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="getUser">
<xsd:sequence>
<xsd:element name="username" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="getUserResponse">
<xsd:sequence>
<xsd:element name="user" type="tns:user" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="user">
<xsd:sequence>
<xsd:element name="username" type="xsd:string" />
<xsd:element name="password" type="xsd:string" />
<xsd:element name="nickname" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<!-- xsd part end -->
</xsd:schema>
</wsdl:types>
<wsdl:message name="login">
<wsdl:part element="tns:login" name="parameters" />
</wsdl:message>
<wsdl:message name="loginResponse">
<wsdl:part element="tns:loginResponse" name="parameters" />
</wsdl:message>
<wsdl:message name="getUser">
<wsdl:part element="tns:getUser" name="parameters" />
</wsdl:message>
<wsdl:message name="getUserResponse">
<wsdl:part element="tns:getUserResponse" name="parameters" />
</wsdl:message>
<wsdl:portType name="IUserService">
<wsdl:operation name="login">
<wsdl:input message="tns:login" />
<wsdl:output message="tns:loginResponse" />
</wsdl:operation>
<wsdl:operation name="getUser">
<wsdl:input message="tns:getUser" />
<wsdl:output message="tns:getUserResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="userServiceSOAP" type="tns:IUserService">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="login">
<wsdl:input><soap:body use="literal" /></wsdl:input>
<wsdl:output><soap:body use="literal" /></wsdl:output>
</wsdl:operation>
<wsdl:operation name="getUser">
<wsdl:input><soap:body use="literal" /></wsdl:input>
<wsdl:output><soap:body use="literal" /></wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="UserService">
<wsdl:port binding="tns:userServiceSOAP" name="userServicePort">
<soap:address location="http://localhost:8080/spring-webservice-server/service/UserService.wsdl" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
PS: 上面xsd part這一段是可以單獨寫到一個UserService.xsd檔案中去的,然後在include到這個wsdl裡面來的,這樣看着更正規、更清新一些,我沒這樣寫的主要原因是待會用soapUI調試的時候會出現這個xsdl檔案import錯誤,我也不知道是什麼原因,不糾結這些工具的問題了,在spring裡面可以通過這個xsd檔案動态的建立wsdl檔案,這樣可以省下一些工作了,但我還是希望初學者自己動手寫wsdl檔案。
2.2 編寫spring的配置檔案[spring-ws-servlet.xml],該檔案放到WEB-INF/下面,内容如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sws="http://www.springframework.org/schema/web-services"
xmlns:ws="http://www.springframework.org/schema/integration/ws"
xmlns:context="http://www.springframework.org/schema/context"
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/web-services
http://www.springframework.org/schema/web-services/web-services-2.0.xsd
">
<context:component-scan base-package="com.zdsoft.webservice"/>
<sws:static-wsdl location="/WEB-INF/wsdl/UserService.wsdl"/>
<!-- 下面的配置可以動态的生成wsdl檔案,我們隻需要寫一個簡單的xsd檔案就可以了 -->
<!--
<sws:dynamic-wsdl id="UserService" portTypeName="IUserService" targetNamespace="http://webservice.zdsoft.com/namespace/userservice"
locationUri="/service" serviceName="UserService" >
<sws:xsd location="/WEB-INF/wsdl/UserService.xsd" />
</sws:dynamic-wsdl>
-->
</beans>
2.3 啟動我們的tomcat,在浏覽器裡面輸入:http://localhost:8080/spring-webservice-server/service/UserService.wsdl,就可以看到我們wsdl檔案了,如下:
2.4 根據wsdl檔案生成我們需要的java檔案
使用java自帶的wsimport指令生成檔案,如下:
cmd wsimport -d d:/webservice -keep http://localhost:8080/spring-webservice-server/service/UserService.wsdl
将所有的java檔案複制到我們的項目裡面來,如下:
對于上面生成的檔案要做以下幾點處理: a. 将IUserService.java檔案中帶className的屬性去掉:
@RequestWrapper(
localName = "login",
targetNamespace = "http://webservice.zdsoft.com/namespace/userservice",
className = "com.zdsoft.webservice.namespace.userservice.Login")
将上面的改成如下:
@RequestWrapper(
localName = "login",
targetNamespace = "http://webservice.zdsoft.com/namespace/userservice")
b.在GetUser.java, GetUserResponse.java,Login.java,LoginResponse.java中加上@XmlRootElement,并且指定名稱空間,如下:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "login", propOrder = {
"username",
"password"
})
@XmlRootElement(name="login", namespace="http://webservice.zdsoft.com/namespace/userservice")
public class Login {
2.5 建立UserServiceImpl類,實作IUserService接口,如下:
package com.zdsoft.webservice.service;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.zdsoft.webservice.api.user.IUserService;
import com.zdsoft.webservice.api.user.User;
/**
* @author YuYang([email protected])
*
* @date 2014年5月2日
*/
@Component("userService")
public class UserServiceImpl implements IUserService {
private static final Logger LOG = LogManager.getLogger(UserServiceImpl.class);
public String login(String username, String password) {
LOG.info("Entered into UserServiceImpl method.");
LOG.debug("username:" + username);
LOG.debug("password:" + password);
String info = "login failed.";
if("scott".equals(username) && "tiger".equals(password)) {
info = "login success.";
}
LOG.debug(info);
LOG.info("Exit from UserServiceImpl method.");
return info;
}
public User getUser(String username) {
LOG.info("Entered into getUser method.");
LOG.debug(username);
User user = new User();
user.setNickname(username + "--nickname");
user.setPassword(username + "--password");
user.setUsername(username + "--username");
LOG.info("Exit from getUser method.");
return user;
}
}
2.6 建立endpoint類:UserServiceEndpoint,如下:
package com.zdsoft.webservice.endpoint;
import javax.annotation.Resource;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import com.zdsoft.webservice.api.user.GetUser;
import com.zdsoft.webservice.api.user.GetUserResponse;
import com.zdsoft.webservice.api.user.IUserService;
import com.zdsoft.webservice.api.user.Login;
import com.zdsoft.webservice.api.user.LoginResponse;
import com.zdsoft.webservice.api.user.User;
/**
* @author YuYang([email protected])
*
* @date 2014年5月2日
*/
@Endpoint
public class UserServiceEndpoint {
private static final Logger LOG = LogManager.getLogger(UserServiceEndpoint.class);
//UserService.wsdl聲明的命名空間
public static final String USERVICE_NAMESPACE = "http://webservice.zdsoft.com/namespace/userservice";
@Resource(name="userService")
private IUserService userService;
@PayloadRoot(namespace = USERVICE_NAMESPACE, localPart = "login")
@ResponsePayload
public LoginResponse handelLoginRequest(@RequestPayload Login request) {
LOG.info("Entered into handelLoginRequest method.");
String info = userService.login(request.getUsername(), request.getPassword());
LoginResponse response = new LoginResponse();
response.setInfo(info);
LOG.info("Exit from handelLoginRequest method.");
return response;
}
@PayloadRoot(namespace = USERVICE_NAMESPACE, localPart = "getUser")
@ResponsePayload
public GetUserResponse HandelGetUserRequest(@RequestPayload GetUser request) {
LOG.info("Entered into HandelGetUserRequest method.");
User user = userService.getUser(request.getUsername());
GetUserResponse response = new GetUserResponse();
response.setUser(user);
LOG.info("Exit from HandelGetUserRequest method.");
return response;
}
}
2.7 使用SoapUI工具測試
a. 下載下傳SoapUI,官網:http://www.soapui.org/, 這個工具使用方法去Google一下。
b. 測試我們的login方法,如下:
c. 測試我們的getUser方法, 如下:
本教程的第一部分算是結束了, 源碼我也分享出來了:http://download.csdn.net/detail/kwgjbj/7283739, 下載下傳的時候需要1積分,算是給點辛苦費吧,比較寫這個教程還是很累的。
第二部分教程會寫一個用戶端與spring整合在一起。
參考文章: http://www.cnblogs.com/hippo0918/p/3662587.html
http://www.beingjavaguys.com/2013/04/create-spring-web-services-using-maven.html