zoukankan      html  css  js  c++  java
  • xfire集成spring构建webservice

    前言:xfire、spring都是比较流行的技术,这里就不再赘述他们各自的优点;本文着重介绍xfire和spring的整合,不会做太深入的探究。

    服务端

    1. web.xml配置

    spring配置部分:contextConfigLocation定义配置文件路径,可以指定全局的配置文件路径。

    <!-- spring配置 -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
               /WEB-INF/xfire-servlet.xml
          </param-value>
        </context-param>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <!-- spring配置 -->

    XFire配置部分:xfire配置1使用spring的DispatcherServlet类来作为xfire的处理类,DispatcherServlet的配置文件名默认为[servletname]-servlet,位于WEB-INF目录下,也可以通过namespace参数来指定或者通过contextConfigLocation参数自定义配置文档的位置;这种配置方式只能通过服务名.ws的方式访问,方便隐藏其它的服务接口;xfire配置2使用xfire的XFireSpringServlet类来作为xfire的处理类,这种配置方式可以直接通过接口名访问,也可以访问所有的服务接口。

    <!-- XFire 配置 1 使用spring的DispatcherServlet作为xfire的处理类,好处是可以自定义服务的名称并隐藏所有提供的其它接口,客户端只能通过服务名.ws的方式访问-->
        <servlet>
            <!-- 配合Spring容器中XFire一起工作的Servlet -->
            <servlet-name>xfireServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <!-- WebApplicationContext命名空间,默认值是[servlet-name]-servlet,对应DispatcherServlet的定义档名称,位于 
                    /WEB-INF下,也可以通过contextConfigLocation参数自定义位置 -->
                <param-name>namespace</param-name>
                <param-value>xfire-servlet</param-value>
            </init-param>
            
            <!-- 通过contextConfigLocation参数自定义位置
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>
                       /WEB-INF/xfire-servlet.xml
                  </param-value>
            </init-param>-->
            
        </servlet>
        <servlet-mapping>
            <servlet-name>xfireServlet</servlet-name>
            <!-- 在这个URI下开放Web Service服务 -->
            <url-pattern>*.ws</url-pattern>
        </servlet-mapping>
        <!-- XFire 配置1 -->
        
        <!-- XFire 配置2 使用xfire的XFireSpringServlet作为xfire的处理类,可以直接使用接口类名来访问开放的服务,也可以查看所有开发的服务接口 -->
        <servlet>
            <!-- 配合Spring容器中XFire一起工作的Servlet -->
            <servlet-name>xfireServlet2</servlet-name>
            <servlet-class>org.codehaus.xfire.spring.XFireSpringServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>xfireServlet2</servlet-name>
            <!-- 在这个URI下开放Web Service服务 -->
            <url-pattern>/service/*</url-pattern>
        </servlet-mapping>
        <!-- XFire 配置2 -->

    2.xfire-servlet配置

    首先需要引入xfire.xml的配置;第二部分用来定义访问的服务名,若使用XFireSpringServlet作为servlet时无需此配置,直接通过接口名访问;第三部分我们通过XFireExporter将业务类导出为Web Service,对于任何导出器,我们都需要引入XFire环境,即serviceFactory和xfire,这是标准的配置。ServiceFactory是XFire的核心类,它可以将一个POJO生成为一个Web Service。在本实例中,我们通过定义一个baseWebService,其余的webService配置都将该bean作为父bean,这样可以简化Spring的配置,不需要多次引入serviceFactory和xfire,这其中的inHandlers参数用来定义xfire的SOAP的截取处理类,可以添加多个,用来完成一些安全验证等功能;最后一部分用来定义业务接口,他们都需要将baseWebService作为父bean。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
    
        <import resource="classpath:org/codehaus/xfire/spring/xfire.xml" />
    
        <!-- 定义访问的url 使用XFireSpringServlet作为servlet时无需此配置 -->
        <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <property name="urlMap">
                <map>
                
                    <entry key="/helloworld.ws">
                        <ref bean="HelloWorldService" />
                    </entry>
                    
                </map>
            </property>
        </bean>
    
        <!-- 使用XFire导出器 我们通过XFireExporter将业务类导出为Web Service,对于任何导出器,
            我们都需要引入XFire环境,即serviceFactory和xfire,这是标准的配置。ServiceFactory是
            XFire的核心类,它可以将一个POJO生成为一个Web Service。在本实例中,我们通过定义一个
            baseWebService,其余的webService配置都将该bean作为父bean,这样可以简化Spring的配置,
            不需要多次引入serviceFactory和xfire。-->
        <bean id="baseWebService" class="org.codehaus.xfire.spring.remoting.XFireExporter"
            lazy-init="false" abstract="true">
            <!-- 引用xfire.xml中定义的工厂 -->
            <property name="serviceFactory" ref="xfire.serviceFactory" />
            <!-- 引用xfire.xml中的xfire实例 -->
            <property name="xfire" ref="xfire" />
            <!-- 安全验证 -->
            <property name="inHandlers" ref="AuthenticationHandler"></property>
        </bean>
    
        <!-- 安全认证 -->
        <bean id="AuthenticationHandler" class="com.AuthenticationHandler"></bean>
    
        <bean id="HelloWorldServiceImpl" class="com.impl.HelloWorldServiceImp" />
        <bean id="HelloWorldService" parent="baseWebService">
            <!-- 业务服务bean -->
            <property name="serviceBean" ref="HelloWorldServiceImpl" />
            <!-- 业务服务bean的窄接口类 -->
            <property name="serviceClass" value="com.HelloWorldService" />
        </bean>
    
    </beans>

    3.AuthenticationHandler安全验证类

    webservice是一种开放的服务的,但有时候我们需要控制用户的访问,这里我们采用handler的方式来截取访问的SOAP报文来判断其中是否包含验证信息,这样就可以完成一个简单的安全校验;继承AbstractHandler类实现invoke方法,通过MessageContext获取请求的报文信息头中是否包含我们需要的用户名、密码等验证信息,相应的我们就需要就客户端调用时放入这些信息,客户端验证类ClientPasswordHandler我们在下面的客户端部分介绍。

    public class AuthenticationHandler extends AbstractHandler {
    
        public void invoke(MessageContext cfx) throws Exception {
            if (cfx.getInMessage().getHeader() == null) {// 是否有验证信息
                throw new org.codehaus.xfire.fault.XFireFault("请求必须包含验证信息",
                        org.codehaus.xfire.fault.XFireFault.SENDER);
            }
            Element token = cfx.getInMessage().getHeader()
                    .getChild("AuthenticationToken");// AuthenticationToken为自定义元素值
            if (token == null) {
                throw new org.codehaus.xfire.fault.XFireFault("请求必须包含身份验证信息",
                        org.codehaus.xfire.fault.XFireFault.SENDER);
            }
            String username = token.getChild("Username").getValue();
            String password = token.getChild("Password").getValue();
            try {
                // 进行身份验证 ,只有test@test的用户为授权用户
                if (username.equals("test") && password.equals("test"))
                    System.out.println("身份验证通过");
                else
                    throw new Exception();
            } catch (Exception e) {
                throw new org.codehaus.xfire.fault.XFireFault("非法的用户名和密码",
                        org.codehaus.xfire.fault.XFireFault.SENDER);
            }
        }
    
    }

    4、完整这些配置和接口的类的开发后服务端的工作就完成了,在tomcat中运行这个demo,在浏览器中输入对应的url当出现“Invalid SOAP request.”字样是表示接口可以正常访问了,在url后添加?wsdl可以获得更详细的接口信息,如下图:

    image image image

    客户端

    1.ClientPasswordHandler安全验证类

    客户端安全验证类也要继承AbstractHandler类实现invoke方法,以Element的方式构建验证信息添加到SOAP的报文头信息中,然后添加这个类到客户端访问的服务接口的请求中,就会在被服务端的AuthenticationHandler类截获完成安全验证。

    public class ClientPasswordHandler extends AbstractHandler {
        private String username = null;
        private String password = null;
    
        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 ClientPasswordHandler(String username, String password) {
            this.username = username;
            this.password = password;
        }
    
        public void invoke(MessageContext context) throws Exception {
            // 为SOAP Header构造验证信息
            Element el = new Element("header");//标头
            context.getOutMessage().setHeader(el);
            Element auth = new Element("AuthenticationToken");//自定义元素
            Element username_el = new Element("Username");
            username_el.addContent(username);
            Element password_el = new Element("Password");
            password_el.addContent(password);
            auth.addContent(username_el);
            auth.addContent(password_el);
            el.addContent(auth);
        }
    
    }

    2、访问服务端接口类

    GetServiceBean类用来获取服务端接口对象,添加客户端验证类;ClientTest通过调用GetServiceBean获取服务端接口对象,然后就可以像使用本地类一样调用其中的方法了(如下图),这里一个显而易见的要求就是客户端要保留服务端的接口类、对象类才能完成调用。

    public class GetServiceBean {
    
        private static XFireProxyFactory factory = new XFireProxyFactory();
    
        public static Object getBean(String serviceUrl, Class<?> serviceClass)
                throws MalformedURLException {
            Service service = new ObjectServiceFactory().create(serviceClass);
            Object object = factory.create(service, serviceUrl);
            Client client = ((XFireProxy) Proxy.getInvocationHandler(object))
                    .getClient(); // 获取访问服务的客户端
            client.addOutHandler(new ClientPasswordHandler("test", "test"));// 添加客户端验证类
           return object;
        }
    
    }
    public class ClientTest {
    
        public static void main(String[] args) throws Exception {
            HelloWorldService service = (HelloWorldService) GetServiceBean.getBean(
                    "http://localhost/xfireserver/helloworld.ws",
                    HelloWorldService.class);
    
            System.out.println(service.hello("小明"));
            Person person = new Person();
            person = service.getPerson();
            System.out
                    .println("id:" + person.getId() + " name:" + person.getName());
            List<Person> students = new ArrayList<Person>();
            students = service.getList();
            for (int i = 0; i < students.size(); i++) {
                Person per = students.get(i);
                System.out.println("id:" + per.getId() + " name:" + per.getName());
            }
        }
    
    }

    image 

    结语:个人理解会有偏驳和不对的地方,欢迎大家批评指正!

    demo下载地址:http://pan.baidu.com/s/1eQxRjeM

  • 相关阅读:
    vue 解决 数组和对象数据画面不更新
    js 闭包
    php 后台登陆逻辑
    PHP tp3.2模型对数据进行多表查询
    简便的三级联动
    JQ三级联动的写法
    js 选项卡
    HTML DOM对象 获取各种类型的节点
    java script 日期对象Date()
    java script 算术对象
  • 原文地址:https://www.cnblogs.com/barros/p/4173604.html
Copyright © 2011-2022 走看看