spring webservice (一) 服务器端开发

  • Post author:
  • Post category:其他



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(zdsoft.yang@foxmail.com)
 *
 * @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(zdsoft.yang@foxmail.com)
 *
 * @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整合在一起。



参考文章:



版权声明:本文为kwgjbj原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。