基于注解方式的XFire之WebService框架与SSJ架构集成案例

最近在给公司做一个基于webservice的数据提供接口,接口提供给第三方公司业务系统调用,完成数据对接。实现起来也相对简单,其实就是通过中间件服务提取内部系统授权数据组织相应的数据格式然后通过webservice的方式暴露获取数据接口给第三方应用,供其调用。要实现这样的需求每个公司的实现方式有可能不一样,根据每个公司实现中间件服务应用使用的实现语言而定。可选择的方案很多,比如如果你们公司的使用的C#的来实现,那么可选择的方案有WCF等技术方案;但是如果你们的中间件服务实现语言是java,那么实现的方案也很多,比如webservice,而webservice相对应的开源框架也很多,比如xfire,又或者你可以完全不适用开源框架来使用webservice技术完成跨平台的服务调用。这些根据每个公司的情况或者说是项目经理的需要而定。下面就针对xfire来讲这个案例。

下面我在一个大家或者大部分公司使用的开源架构SSJ来讲解这个案例。下面我们来准备一下这个案例需要的环境。首先我们准备两个项目,一个是服务端(提供[暴露]webservice服务接口端),一个是客户端(webservice 服务使用[消费、调用]端)。下面我们需要准备一下相应的案例环境,因此我创建了如下两个项目,如下图所示:

针对客户端项目我们只需要添加xfire下相关jar类库即可,而服务端SSJ架构应用需要添加的支持库除了xfire之外还包含struts2\spring\hibernate(jpa,hibernate便是jpa标准下的一个实现产品)的相关jar即可。好了以上两个截图便是集成好的两个项目。下面我开始讲解一些集成的细节。

首先是服务端集成说明如下:

web.xml的相关配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<!-- 应用显示的名称 -->
	<display-name>tsHisWeixinService</display-name>
	<description>tsHisWeixinService Application</description>
	<!-- WEB-INF/classes/tsTelemedicine*.xml, -->
	<!-- spring要读取的配置文件的上下文路径,这个上下文参数会放在servletContext范围内,这个参数也可以不知道,spring会从它默认的位置读取配置文件,来初始化spring容器 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			WEB-INF/classes/tsTelemedicine-core.xml
		</param-value>
	</context-param>
	<!-- 对Spring容器进行实例化-->
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	<!--日志的配置-->
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>/WEB-INF/classes/log4j.properties</param-value>
	</context-param>
	<listener>
		<listener-class>
			org.springframework.web.util.Log4jConfigListener
		</listener-class>
	</listener>
	<!-- 内存溢出 -->
	<listener>
		<listener-class>
			org.springframework.web.util.IntrospectorCleanupListener
		</listener-class>
	</listener>
	<filter>
		<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
		<filter-class>
			org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
		</filter-class>
		<init-param>
			<!-- 指定org.springframework.orm.jpa.LocalEntityManagerFactoryBean在spring配置文件中的名称,默认值为entityManagerFactory
				如果LocalEntityManagerFactoryBean在spring中的名称不是entityManagerFactory,该参数一定要指定,否则会出现找不到entityManagerFactory的例外 -->
			<param-name>entityManagerFactoryBeanName</param-name>
			<param-value>entityManagerFactory</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<!-- struts2 核心filter -->
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>
			org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
		</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
	<!-- webservice 相关配置1,这种配置方式xfire在启动时候会读取META-INFO/xfire/services.xml下面关于webservice bean相关配置  -->
	<!-- 

		<servlet>
		<servlet-name>XFireServlet</servlet-name>
		<servlet-class>
		org.codehaus.xfire.transport.http.XFireConfigurableServlet
		</servlet-class>
		<load-on-startup>0</load-on-startup>
		</servlet>

		<servlet-mapping>
		<servlet-name>XFireServlet</servlet-name>
		<url-pattern>/services/*</url-pattern>
		</servlet-mapping>
	-->
	<!-- webservice 相关配置2,这种配置方式xfire在启动时候根据spring配置文件关于xfire配置内容来启动 -->
	<servlet>
		<servlet-name>XFireServlet</servlet-name>
		<servlet-class>
			org.codehaus.xfire.spring.XFireSpringServlet
		</servlet-class>
		<load-on-startup>0</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>XFireServlet</servlet-name>
		<url-pattern>/services/*</url-pattern>
	</servlet-mapping>
</web-app>

spring的相关配置

<?xml version="1.0" encoding="UTF-8"?>
<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:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
	<aop:aspectj-autoproxy />
	<context:component-scan base-package="com.tenshine" />
	<!--  使用数据源和指定persistence.xml位置的方式创建entityManagerFactory,如果使用的不是hibernate JPA实现,
		需要在tomcat作一些特殊配置.具体参考手册
		注意:使用该方式需要把persistence.xml中的hibernate.connection.driver_class,hibernate.connection.username,hibernate.connection.password,hibernate.connection.url配置删除
	-->
	<!-- 在这里我使用c3p0作为数据库连接池 -->
	<bean id="dataSource"
		class="com.mchange.v2.c3p0.ComboPooledDataSource"
		destroy-method="close">
		<property name="driverClass" value="${driverClass}" />
		<property name="jdbcUrl" value="${jdbcUrl}" />
		<property name="user" value="${user}" />
		<property name="password" value="${password}" />
		<!-- 初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3  -->
		<property name="initialPoolSize" value="1" />
		<!-- 连接池中保留的最小连接数。 -->
		<property name="minPoolSize" value="1" />
		<!-- 连接池中保留的最大连接数。Default: 15  -->
		<property name="maxPoolSize" value="100" />
		<!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0  -->
		<property name="maxIdleTime" value="60" />
		<!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3  -->
		<property name="acquireIncrement" value="5" />
		<!-- 每60秒检查所有连接池中的空闲连接。Default: 0  -->
		<property name="idleConnectionTestPeriod" value="60" />
	</bean>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="persistenceXmlLocation"
			value="classpath:META-INF/persistence.xml" />
		<property name="loadTimeWeaver">
			<bean
				class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
		</property>
	</bean>
	<!-- 使用JPA方式的事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory"
			ref="entityManagerFactory" />
	</bean>
	<!-- 使用注解的方式使用事务 -->
	<tx:annotation-driven transaction-manager="transactionManager" />
	<!-- 指定相应的jdbc连接数据库的配置文件 -->
	<context:property-placeholder location="classpath:jdbc.properties" />

	<!-- 基于注解配置XFire -->
	<import resource="classpath:org/codehaus/xfire/spring/xfire.xml" />
	<bean id="webAnnotations"
		class="org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations" />
	<bean id="jsr181HandlerMapping"
		class="org.codehaus.xfire.spring.remoting.Jsr181HandlerMapping">
		<property name="xfire" ref="xfire" />
		<property name="webAnnotations" ref="webAnnotations" />
	</bean>
</beans>

以上便是服务端的关键配置信息了,配置好了以上内容我们就可以在我们服务端项目中基于注解的方式定于我们需要发布的服务了。下面举一个简单的例子如下:

定义WebService接口:

package com.tenshine.hisWeixin.service;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface ValidationLoginService {
	@WebMethod
	public boolean validateLogin(String userAccount,String passWord) throws Exception;
}

实现WebService接口,并指定服务名:

package com.tenshine.hisWeixin.service.impl;

import javax.jws.WebService;
import org.springframework.stereotype.Service;
import com.tenshine.hisWeixin.service.ValidationLoginService;

@Service
@WebService(serviceName="ValidationLoginService", endpointInterface = "com.tenshine.hisWeixin.service.ValidationLoginService")
public class ValidationLoginServiceImpl implements ValidationLoginService{
	public boolean validateLogin(String userAccount, String passWord)
			throws Exception {
		System.out.println("远程调用服务端webservice 业务方法");
		System.out.println("远程调用服务端webservice 业务方法");
		System.out.println("远程调用服务端webservice 业务方法");
		System.out.println("远程调用服务端webservice 业务方法");
		System.out.println("远程调用服务端webservice 业务方法");
		System.out.println("远程调用服务端webservice 业务方法");
		System.out.println("远程调用服务端webservice 业务方法");
		return false;
	}

}

好了以上配置完之后我们就可以启动我们服务端,发布我们定义的服务,然后通过浏览器的访问相应的webservice服务连接地址看服务是否发布成功,或者我xfire是否集成SSJ成功。我们在浏览器地址栏输入:http://127.0.0.1:8080/tsweixin/services/ValidationLoginService?wsdl。出现如下内容说明集成成功:

其次是客户端调用服务说明如下:

一般我们有两种方式使用服务,一种是服务提供商直接提供服务接口源码给服务使用者。

客户端调用代码片段如下:

package com.tenshine.hisweixin.test;

import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import org.junit.Test;

//import com.tenshine.hisweixin.service.ValidationLoginService;

public class HisWeixinServiceTest {
	@Test
	public void testBookService() {
//	    Service serviceModel = new ObjectServiceFactory().create(ValidationLoginService.class);
//	    String url = "http://127.0.0.1:8080/tsweixin/services/ValidationLoginService";
//	    ValidationLoginService service = null;
//	    try {
//	        service = (ValidationLoginService) new XFireProxyFactory().create(serviceModel, url);
//	        System.out.println("返回值 "+service.validateLogin("admin", "admin"));
//	    } catch (Exception e) {
//	        e.printStackTrace();
//	    }
	}
}

另外一种则是用过wsdl文件或者wsdl地址生成客户端代码(一般一些专业公司会手写webservice对应的wsdl规范[wsdl文件],也就是我们常听到的“契约优先”的概念,而不是“代码优先”,两种方式即可),我们可以使用jdk给我提供工具来生成webservice客户端代码【wsimport 】,wsimport
的使用详情大家自己百度去。在这里就不多说了。在控制台上出入如下命令:wsimport -keep -verbose -d D:\ http://127.0.0.1:8080/tsweixin/services/ValidationLoginService?wsdl

好了,通过以上这中方式生成客户端代码就可以被调用了。是不是很简单。当然可以通过myeclipse这个IDE里面生成客户端代码,操作如下:将普通的项目变成xfire项目,右键项目选择“Myeclipse”->"add XFire Web Service Capabilities",然后再进行新建xfire webservice客户端。操作为“右键->new->other->Web
services”,然后按照提示傻瓜式的操作即可。如下图所示:

生成完之后生成如下代码:

下面便是生成的客户端调用代码:

package com.tenshine.service.client;

import java.net.MalformedURLException;
import java.util.Collection;
import java.util.HashMap;
import javax.xml.namespace.QName;
import org.codehaus.xfire.XFireRuntimeException;
import org.codehaus.xfire.aegis.AegisBindingProvider;
import org.codehaus.xfire.annotations.AnnotationServiceFactory;
import org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.jaxb2.JaxbTypeRegistry;
import org.codehaus.xfire.service.Endpoint;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.soap.AbstractSoapBinding;
import org.codehaus.xfire.transport.TransportManager;

public class ValidationLoginServiceClient {

    private static XFireProxyFactory proxyFactory = new XFireProxyFactory();
    private HashMap endpoints = new HashMap();
    private Service service0;

    public ValidationLoginServiceClient() {
        create0();
        Endpoint ValidationLoginServicePortTypeLocalEndpointEP = service0 .addEndpoint(new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServicePortTypeLocalEndpoint"), new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServicePortTypeLocalBinding"), "xfire.local://ValidationLoginService");
        endpoints.put(new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServicePortTypeLocalEndpoint"), ValidationLoginServicePortTypeLocalEndpointEP);
        Endpoint ValidationLoginServiceHttpPortEP = service0 .addEndpoint(new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServiceHttpPort"), new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServiceHttpBinding"), "http://127.0.0.1:8080/tsweixin/services/ValidationLoginService");
        endpoints.put(new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServiceHttpPort"), ValidationLoginServiceHttpPortEP);
    }

    public Object getEndpoint(Endpoint endpoint) {
        try {
            return proxyFactory.create((endpoint).getBinding(), (endpoint).getUrl());
        } catch (MalformedURLException e) {
            throw new XFireRuntimeException("Invalid URL", e);
        }
    }

    public Object getEndpoint(QName name) {
        Endpoint endpoint = ((Endpoint) endpoints.get((name)));
        if ((endpoint) == null) {
            throw new IllegalStateException("No such endpoint!");
        }
        return getEndpoint((endpoint));
    }

    public Collection getEndpoints() {
        return endpoints.values();
    }

    private void create0() {
        TransportManager tm = (org.codehaus.xfire.XFireFactory.newInstance().getXFire().getTransportManager());
        HashMap props = new HashMap();
        props.put("annotations.allow.interface", true);
        AnnotationServiceFactory asf = new AnnotationServiceFactory(new Jsr181WebAnnotations(), tm, new AegisBindingProvider(new JaxbTypeRegistry()));
        asf.setBindingCreationEnabled(false);
        service0 = asf.create((com.tenshine.service.client.ValidationLoginServicePortType.class), props);
        {
            AbstractSoapBinding soapBinding = asf.createSoap11Binding(service0, new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServiceHttpBinding"), "http://schemas.xmlsoap.org/soap/http");
        }
        {
            AbstractSoapBinding soapBinding = asf.createSoap11Binding(service0, new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServicePortTypeLocalBinding"), "urn:xfire:transport:local");
        }
    }

    public ValidationLoginServicePortType getValidationLoginServicePortTypeLocalEndpoint() {
        return ((ValidationLoginServicePortType)(this).getEndpoint(new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServicePortTypeLocalEndpoint")));
    }

    public ValidationLoginServicePortType getValidationLoginServicePortTypeLocalEndpoint(String url) {
        ValidationLoginServicePortType var = getValidationLoginServicePortTypeLocalEndpoint();
        org.codehaus.xfire.client.Client.getInstance(var).setUrl(url);
        return var;
    }

    public ValidationLoginServicePortType getValidationLoginServiceHttpPort() {
        return ((ValidationLoginServicePortType)(this).getEndpoint(new QName("http://service.hisWeixin.tenshine.com", "ValidationLoginServiceHttpPort")));
    }

    public ValidationLoginServicePortType getValidationLoginServiceHttpPort(String url) {
        ValidationLoginServicePortType var = getValidationLoginServiceHttpPort();
        org.codehaus.xfire.client.Client.getInstance(var).setUrl(url);
        return var;
    }

    public static void main(String[] args) {

        ValidationLoginServiceClient client = new ValidationLoginServiceClient();

		//create a default service endpoint
        ValidationLoginServicePortType service = client.getValidationLoginServiceHttpPort();

		//TODO: Add custom client code here
        		//
        		//service.yourServiceOperationHere();
        service.validateLogin("admin", "admin");
		System.out.println("test client completed");
    }

}

调用结果如下:

客户端:

服务端:

好了一个完整案例就这样完了!希望以上内容对你有所帮助。

时间: 2024-10-14 00:01:58

基于注解方式的XFire之WebService框架与SSJ架构集成案例的相关文章

Spring声明式事务管理(基于注解方式实现)

----------------------siwuxie095 Spring 声明式事务管理(基于注解方式实现) 以转账为例 1.导入相关 jar 包(共 10 个包) (1)导入核心 jar 包和日志相关的 jar 包 (2)导入 JdbcTemplate 的 jar 包 (3)导入 MySQL 的 JDBC 驱动包 mysql-connector-java 下载链接: https://dev.mysql.com/downloads/connector/j/ (4)导入 AOP 的 jar

Hibernate基于注解方式的各种映射全面总结

1. 使用Hibernate Annotation来做对象关系映射 1) 添加必须包: hibernate-jpa-2.0-api-1.0.0.Final.jar 2) 在实体类中添加JPA的标准注解来进行对象关系映射.注解可以添加在属性上,也可以添加在getXxx()方法之上. a) @Entity 映射一个实体类 @Table 指定关联的表 b) @Id 映射OID c) @GeneratedValue 指定OID的生成策略 d) @Version 映射版本号属性 e) @Column 指定

springMVC+freemarker+slf4j整合(基于注解方式)

springmvc在项目中使用较多,本文将基于spring注解springMVC+freemarker+slf4j整合在一起,便于开发,后续还会将ibatis整合进来. 第一步:使用编程工具建立web工程,本文使用eclipse + tomcat 7.0 + jdk 1.7. 第二步:引入工程使用到的jar文件: commons-logging-1.1.3.jar.freemarker-2.3.20.jar.logback-classic-1.0.9.jar.logback-core-1.0.9

在spring的配置中,基于注解方式是否比xml方式配置更好?——翻译

简短的回答就是“看情况了”.长篇大论来说(辩证的看待),每种方式都有利弊,通常来说,这取决于开发者选择最适合他们的策略.由于注解的定义方式,在其声明中提供了大量上下文,从而导致更短更简洁的配置.但是,XML的方式优势在于连接组件时解耦源代码或无需重新编译.一些开发人员更喜欢将配置连接靠近源头,而另一些则认为注释类不再是POJO,而且配置变得分散且难以控制. 不管是哪种方式,spring可以兼容两种风格并且混合使用都可以.值得提出的是,通过其JavaConfig选项,Spring允许以非侵入方式使

Spring学习事务管理--基于注解方式(三)

图书类接口 package com.spring.tx; public interface BookShopDao { /** * 根据书号查找加个 * @param isbn * @return */ public int findBookPriceByIsbn(String isbn); /** * 更新书的库存 * @param isbn */ public void updateBookStock(String isbn); /** * 更新账户 * @param username *

springMVC+freemarker+slf4j整合(基于注解方式)准尊篆遵祖宗

http://www.ebay.com/cln/3t9_vznf/2015-01-29/166763640011 http://www.ebay.com/cln/lbv_dlrh/2015-01-29/166763632011 http://www.ebay.com/cln/lvx_xhlb/2015-01-29/166613270010 http://www.ebay.com/cln/l53_nfpf/2015-01-29/166613253010 http://www.ebay.com/cl

springMVC+freemarker+slf4j整合(基于注解方式)滋走综浊罪妆

http://www.ebay.com/cln/brx_tbxp/2015-01-29/166662145014 http://www.ebay.com/cln/7hn_dnvn/2015-01-29/166690691010 http://www.ebay.com/cln/5rf_jhrb/2015-01-29/166576097017 http://www.ebay.com/cln/znp_xbrd/2015-01-29/166496780019 http://www.ebay.com/cl

spring AOP (包含基于注解和配置文件两种方式)

spring AOP?面向切面编程,区别于面向对象编程OOP AspectJ: 是Java社区里面最完整最流行的AOP框架,下面就用aspectJ来上例子 一.基于注解方式 步骤如下: 引入jar包(spring的必要jar包 以及aspectj的jar包) 业务方法HelloworldService (类上加上注解@Component,放入到spring ioc容器中) 切面LogingAop (类上加上注解@Component使其加入到ioc容器中,还需要注解@Aspect,使其成为一个切面

基于已构建S2SH项目配置全注解方式简化配置文件

如果还不熟悉s2sh项目搭建的朋友可以先阅读 eclipse环境下基于已构建struts2项目整合spring+hibernate 这两篇文章熟悉一下. 本文是基于以上两篇文章的基础构建的,以下给出全注解方式配置S2SH项目的参考步骤. 第一步:实体类映射数据库表,简化hibernate通过xml配置文件映射 首先我们新建实体类作为测试,包结构如图所示: 新建User到model包下,实体类字段信息如下所示: package wjt.com.test.model; import javax.pe