Webservice使用xfire发布及客户端调用

 
             这几天研究了一下WebService的发布及调用,没做之前觉得挺难得,还好项目中有这样的实例自己学着做了一个使用Xfire发布并在另一个项目中调用,感觉做成了还是挺有成就感的,下面记录下实现的步骤有需要的同学可以试一下,也为自己以后使用留个备份。

第一步:先建立一个发布WebService的项目(项目使用SpringMvc架构搭建一个环境):

项目目录结构如下图所示

 

主要使用的类有,User.java,Tree.java,UserService.java,UserServiceImpl.java

下面将代码文件附上:

public class User {

	private String id;
	private String userName;
	private String password;
	private int age;
	private String sex;

	public User() {

	}

	public User(String id, String userName, String password, int age, String sex) {
		this.id = id;
		this.userName = userName;
		this.password = password;
		this.age = age;
		this.sex = sex;
	}


	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", userName=" + userName + ", password="
				+ password + ", age=" + age + ", sex=" + sex + "]";
	}


}
public class Tree {

	private String id;
	private String childNode;
	private String treeName;

	public Tree(String id, String childNode, String treeName) {
		this.id = id;
		this.childNode = childNode;
		this.treeName = treeName;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getChildNode() {
		return childNode;
	}

	public void setChildNode(String childNode) {
		this.childNode = childNode;
	}

	public String getTreeName() {
		return treeName;
	}

	public void setTreeName(String treeName) {
		this.treeName = treeName;
	}

}

 UserService接口,也就是我们要暴露出来的类供其他项目访问的。

public interface UserService {

	public String getUserByUserName(String userName);

	public String getTreeByTreeId(String id);

	public String selectUserById(String id);
}

 实现类代码如下,我这里为了方便测试没有返回XML格式的字符串了,项目中一般返回的都是XML格式的数据到本地后在使用dom方式解析XML得到我们需要的数据。

@Service
public class UserServiceImpl implements UserService {

	@Override
	public String getUserByUserName(String userName) {
		User user = new User("1", userName, "111111", 24, "女");
		return user.toString() + "方法==getUserByUserName==调用成功!";
	}

	@Override
	public String getTreeByTreeId(String id) {
		Tree tree = new Tree("5", "子节点", "树节点");
		return tree.toString() + "方法==getTreeByTreeId==调用成功!";
	}

	@Override
	public String selectUserById(String id) {
		User user = new User(id, "userName", "111111", 24, "女");
		return user.toString() + "方法==selectUserById==调用成功!";
	}

}

 spring-webservice.xml 文件,这个文件是定义我们要发布出去的接口是什么,并且指定了接口的实现类是谁。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

<beans default-autowire="byName">

	<!-- ====================SpringXfire================= -->
	<bean id="userServiceImpl" class="com.ebiz.service.impl.UserServiceImpl" />
	<bean id="addressingHandler" class="org.codehaus.xfire.addressing.AddressingInHandler" />
	<bean name="userService" class="org.codehaus.xfire.spring.ServiceBean">
		<property name="serviceBean" ref="userServiceImpl"></property>
		<property name="serviceClass" value="com.ebiz.service.UserService"></property>
		<property name="inHandlers">
			<list>
				<ref bean="addressingHandler" />
			</list>
		</property>
	</bean>

</beans>

springMVC.xml文件配置,这个是spring的主要配置文件大家用过的应该都知道的

<?xml version="1.0" encoding="UTF-8"?>
<!--看到下面的beans这个元素标签没有,必须有标签的声明 -->
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
    	http://www.springframework.org/schema/context/spring-context.xsd
    	http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<!-- 对web包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 -->
	<!-- <bean name="/hello" class="com.gyl_test.action.UserController"/> -->
	<context:component-scan base-package="com.*" />
	<!-- 支持spring3.0新的mvc注解 -->
	<mvc:annotation-driven />
 	<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
	<!-- ViewResolver -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass"
			value="org.springframework.web.servlet.view.JstlView" />
		<property name="prefix" value="/WEB-INF/" />
		<property name="suffix" value=".jsp" />
	</bean>
	
	<!-- 总错误处理-->  
	<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
		<property name="defaultErrorView">    
	 		<value>/error/error</value>  
		</property>  
		<property name="defaultStatusCode">    
			<value>500</value>  
		</property>     
		<property name="warnLogCategory">    
			<value>org.springframework.web.servlet.handler.SimpleMappingExceptionResolver</value>  
		</property>     
	</bean> 
	<import resource="classpath:org/codehaus/xfire/spring/xfire.xml" />
	<import resource="spring-webservice.xml" />
</beans>

    下面要重点讲一下这个web.xml,这个文件的配置我是吃了亏的,目前为止还是不太懂

因为少了下面的代码所以调用的时候老是提示contextConfigLocation 这个没有能初始化,后来加了这一段就好了,有大神知道原因的可以给我解释下谢谢啦!

<listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        <!-- 默认情况下加载的是/WEB-INF目录下的applicationContext.xml -->
    </listener>
   
    <!-- 指定spring需要的xml文件,用contextConfigLocation指定 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:spring-conf/springMVC.xml
        </param-value>
    </context-param>

   我个人觉得这个我已经在配置SpringMvc的时候加载了,但是不知道为啥不加还是不行。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  
  <display-name>springMVC</display-name>
  <servlet>
  	<servlet-name>springMVC</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	<init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-conf/springMVC.xml</param-value>
    </init-param>
  	<!-- <load-on-startup>2</load-on-startup> -->
  </servlet> 
  
  <servlet-mapping>
  	<servlet-name>springMVC</servlet-name>
  	<url-pattern>*.do</url-pattern>
  </servlet-mapping>
  
  	<listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        <!-- 默认情况下加载的是/WEB-INF目录下的applicationContext.xml -->
    </listener>
    
    <!-- 指定spring需要的xml文件,用contextConfigLocation指定 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:spring-conf/springMVC.xml
        </param-value>
    </context-param>
  
  <!-- xfire BEGIN -->
	<servlet>
		<servlet-name>XFireServlet</servlet-name>
		<servlet-class>org.codehaus.xfire.spring.XFireSpringServlet</servlet-class>
	</servlet>
	<!-- <servlet-mapping>
		<servlet-name>XFireServlet</servlet-name>
		<url-pattern>/servlet/XFireServlet/*</url-pattern>
	</servlet-mapping> -->
	<servlet-mapping>
		<servlet-name>XFireServlet</servlet-name>
		<url-pattern>/services/*</url-pattern>
	</servlet-mapping> 
	<!-- xfire END -->
  
  <!--获取session-->
  <listener>
      <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>
  <display-name>gyl_test</display-name>
  <welcome-file-list>
     <welcome-file>index.jsp</welcome-file>
     <welcome-file>commons/hello.jsp</welcome-file>
  </welcome-file-list>
</web-app>

    发布项目的代码基本就好了,然后我们看下发布的效果如图:

    发布的wsdl地址是:http://localhost:8080/gyl_test/services/UserService?wsdl

   

 如果你看到这个页面就代表你发布wsdl已经成功了!

第二步:新建一个调用wsdl的web项目名称叫:WebServiceTest

我这里用二种方式来调用一下我们发布的wsdl接口

第一种比较死板,而且要求比较高,我说的要求是指对于接口发布项目的源代码的依赖性比较强,使用第一种方式调用必须要得到源代码的接口类UserService.java 将他放到自己调用接口的项目中来使用。(是不是比较麻烦,如果接口项目是别人写的而你又没有源代码就比较麻烦了)。

第二种是使用JAW-WS方式来调用接口,其实原理就是使用jdk6.0自带的工具wsimport.exe 生成客户端代码(这个会生成一些接口调用必须的一些java类,有了这些类就可以直接调用接口的方法),当然这个代码和接口项目的源码是不一样的,但是已经能满足我们客户端调用的需求啦!代码如下:

public class TestAction {

	public static void main(String[] args) {

		// 调用方式一:
		/*
		 * String url =
		 * "http://localhost:8080/gyl_test/services/UserService?wsdl"; url =
		 * "http://localhost:8080/gyl_test/services/UserService";
		 * 
		 * Service service = new
		 * ObjectServiceFactory().create(UserService.class, null,
		 * "http://localhost:8080/gyl_test/services/UserService?wsdl", null);
		 * XFireProxyFactory serviceFactory = new XFireProxyFactory();
		 * 
		 * try {
		 * 
		 * UserService userService = (UserService) serviceFactory.create(
		 * service, url); String msg = userService.getUserByUserName("hello");
		 * System.out.println("++++" + msg);
		 * 
		 * msg = userService.getTreeByTreeId("测试Tree");
		 * System.out.println("-------------" + msg + "-------------");
		 * 
		 * msg = userService.selectUserById("测试UserId");
		 * System.out.println("-------------" + msg + "-------------"); } catch
		 * (Exception e) { e.printStackTrace(); }
		 */

		// 调用方式二:

		UserService server = new UserService();
		UserServicePortType spt = server.getUserServiceHttpPort();
		System.out.println(spt.getUserByUserName("远程调用"));
	}
}

下面简单介绍下wsimport.exe 工具怎么使用,网上又很多,我简单说明一下,首先进入到你本机jdk的bin目录下,我本机的目录是这样的 D:\java\lib\jdk1.6.0_18\bin:

打开cmd----> cd D:\java\lib\jdk1.6.0_18\bin 回车----> 然后输入 d:    

这样就进入了jdk的bin目录如图所示

 

 然后输入命令:wsimport  -keep -d d:\ -s  d:\WorkSpace\WebServiceTest\src http://localhost:8080/gyl_test/services/UserService?wsdl

这个命令里面 -d 后面指示的是class文件存放的地方 可以随便写一个 例如 d:\(D盘根目录下),-s后面是源文件存放的目录也就是生成的java文件 这个建议选择项目的src目录 我这里选择d:\WorkSpace\WebServiceTest\src 最后面的是我们的wsdl地址,运行命令如图所示:

wsimport命令执行前WebServiceTest项目结构图

 

 wsimport命令执行结果截图

 wsimport命令执行后WebServiceTest项目结构图

 

 WSDL调用成功截图如下:

 

这一步需要注意的是在调用项目中不能加入xfire-all-1.2.6.jar和xfire-jsr181-api-1.0-M1.jar 包否则调用过程中会抱一个错误,

webservice: Could not initialize Service NoSuchMethodException getPortClassMap()

导致错误的原因是类加载的问题,因为xfire的包在tomcat/webapps/app/web-inf的lib下,其加载顺序高于由根classloader加载的jdk中的javax.xml.ws.spi.Provider,所以在创建Service的代理的时候没有使用jdk自带的javax.xml.ws.spi.Provider,而是使用了xfire包中的javax.xml.ws.spi.Provider导致了错误。(这个也是本人亲身尝试)

实例比较简单重在阐述这么一个实现过程,希望大牛们看到不要笑话我,有说的不对的地方还请指教,平时比较懒散哈哈技术总结比较少。

最后附件中附上要用的Xfire组件jar包。

猜你喜欢

转载自gyl892014311.iteye.com/blog/2201082