美文网首页Spring相关
6、CXF与spring的整合(WebService的整合)

6、CXF与spring的整合(WebService的整合)

作者: yjaal | 来源:发表于2016-06-29 22:22 被阅读0次

    一、环境搭建

    • 这里只是初步整合,我们直接将CXF中的lib目录中的所有jar包全部加入(除去jetty相关包、geronimo-servlet_3.0_spec-1.0.jar)。
    • 将之前工程中的包拷贝到本工程(cxf_spring)中,
      分别是org.fkjava.cxf.ws.domain、org.fkjava.cxf.ws.service、org.fkjava.cxf.ws.service.impl、org.fkjava.cxf.ws、org.fkjava.cxf.ws.impl、org.fkjava.cxf.ws.util、org.fkjava.cxf.ws.server
    • 相关的配置文件

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!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>
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
        </context-param>
        
        <!-- 使用一个监听器加载spring容器,保证web应用启动时加载spring -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        
        <!-- 下面的配置表明所有来自/myService/*的请求都交给CXFServlet处理 -->
        <servlet>
            <servlet-name>cxf</servlet-name>
            <!-- 下面这个类在API文档中是查不到的 -->
            <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        </servlet>
        
        <servlet-mapping>
            <servlet-name>cxf</servlet-name>
            <url-pattern>/myService/*</url-pattern>
        </servlet-mapping>
    </web-app>
    

    说明:这里主要配置了spring的配置文件地址,spring监听器、CXF核心控制器。

    applicationContext.xml

    <?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:jaxws="http://cxf.apache.org/jaxws" 
             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-4.0.xsd
               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
               http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
               http://cxf.apache.org/jaxws
               http://cxf.apache.org/schemas/jaxws.xsd">
        <!-- web应用的类加载路径有两类:
        1.WEB-INF/classes目录。2.WEB-INF/lib目录下,两者的唯一区别是前者是散的class文件,后者是打成jar包的class文件
         -->
        <import resource="classpath:META-INF/cxf/cxf.xml"/>
            
        <bean id="userService" class="org.fkjava.cxf.impl.service.impl.UserServiceImpl"/>
    </beans>
    

    说明:

    • 这里我们需要将CXF相关的配置文件加入进去,同时配置相关的业务类。
    • spring配置文件(applicationContext.xml)中注入CXF提供的schema、xml配置。
      • 对于schema的配置:
        beans标签中加入xmlns:jaxws=http://cxf.apache.org/jaxws然后在xsi:schemaLocation中加入http://cxf.apache.org/jaxws(命名空间)http://cxf.apache.org/schemas/jaxws.xsd(物理路径)。
      • 对于xml的配置:
        web应用的类加载路径有两类:1.WEB-INF/classes目录。2.WEB-INF/lib目录下,两者的唯一区别是前者是散的class文件,后者是打成jar包的class文件。
        <import resource="classpath:META-INF/cxf/cxf.xml"/>
        其实导入的cxf-servlet.xmlcxf.extension-soap.xml一般不需要,在之后的版本中可以不需要导入了,一般只是为了兼容性才会导入。

    二、进行开发

    2.1 暴露WebService

    spring的配置文件中使用jaxws:endpoint元素来暴露WebService,这里有两种方式:

    <1>直接给定服务器提供者的类名(不太好用)

    <jaxws:endpoint
            implementor="org.fkjava.cxf.ws.impl.HelloWorldWs"
            address="/fkjava">
    </jaxws:endpoint>
    

    然后我们就可以将工程部署到tomcat中,在浏览器中使用
    地址http://localhost:8080/cxf_spring/myService访问我们的WebService工程。

    1
    • 新建一个java工程进行测试(工程Call_CXFSpring
      首先还是使用命令:wsdl2java http://localhost:8080/cxf_spring/myService/fkjava?wsdl将相关文件考出来。之后刷新工程,在工程中新建一个类MyClient.java访问WebService即可。

    MyClient.java

    package org.fkjava.cxf.ws.client;
    import org.apache.cxf.endpoint.Client;
    import org.apache.cxf.frontend.ClientProxy;
    import org.fkjava.cxf.ws.auth.AddHeaderInterceptor;
    import org.fkjava.cxf.ws.Entry;
    import org.fkjava.cxf.ws.HelloWorld;
    import org.fkjava.cxf.ws.StringCat;
    import org.fkjava.cxf.ws.impl.HelloWorldWs;
    
    public class MyClient {
    
        public static void main(String[] args) {
            HelloWorldWs factory = new HelloWorldWs();
            HelloWorld hw = factory.getHelloWorldWsPort();
            System.out.println(hw.sayHi("张三"));
            
            StringCat sc = hw.getAllCats();
            for(Entry entry : sc.getEntries()){
                System.out.println(entry.getKey() + ":" + entry.getValue().getName());
            }
        }
    }
    

    注意:myService指定我们的服务名字(在web.xml中配置),而fkjava指定服务提供者的地址(在applicationContext.xml中配置)。同时这种集成不好,因为将地址写死了,没有使用spring的注入方式。
    我们看HelloWorldWs.java这个服务类:

    package org.fkjava.cxf.ws.impl;
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import javax.jws.WebService;
    import org.fkjava.cxf.ws.HelloWorld;
    import org.fkjava.cxf.ws.domain.Cat;
    import org.fkjava.cxf.ws.domain.User;
    import org.fkjava.cxf.ws.service.UserService;
    import org.fkjava.cxf.ws.service.impl.UserServiceImpl;
    
    @WebService(endpointInterface = "org.fkjava.cxf.ws.HelloWorld", serviceName = "HelloWorldWs")
    public class HelloWorldWs implements HelloWorld {
    
        @Override
        public String sayHi(String name) {
            return name + "您好!" + "现在的时间是: " + new Date();
        }
    
        @Override
        public List<Cat> getCatsByUser(User user) {
            //这里我们需要手工new,如果交给spring管理可以将对象注入进来
            UserService service = new UserServiceImpl();
            return service.getCatByUser(user);
        }
        
        //新增方法
        @Override
        public Map<String, Cat> getAllCats() {
            UserService service = new UserServiceImpl();
            return service.getAllCats();
        }
    }
    

    可以看到其中的实际业务处理类还是使用的手工方法进行实例化,没有使用spring的注入方式。

    <2>使用注入方式

    spring的配置文件中改变暴露WebService的方式:

    <bean id="helloWorldWs" class="org.fkjava.cxf.ws.impl.HelloWorldWs">
            <property name="userService" ref="userService"></property>
        </bean>
        <jaxws:endpoint
            implementor="#helloWorldWs"
            address="/fkjava">
        </jaxws:endpoint>
    

    说明:#号是为了让服务器知道这个名字不是一个类 ,而只是一个id
    然后改造HelloWorldWs.java服务类:

    package org.fkjava.cxf.ws.impl;
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import javax.jws.WebService;
    import org.fkjava.cxf.ws.HelloWorld;
    import org.fkjava.cxf.ws.domain.Cat;
    import org.fkjava.cxf.ws.domain.User;
    import org.fkjava.cxf.ws.service.UserService;
    import org.fkjava.cxf.ws.service.impl.UserServiceImpl;
    
    @WebService(endpointInterface = "org.fkjava.cxf.ws.HelloWorld", serviceName = "HelloWorldWs")
    public class HelloWorldWs implements HelloWorld {
        
        private UserService userService;
        @Override
        public String sayHi(String name) {
            return name + "您好!" + "现在的时间是: " + new Date();
        }
    
        @Override
        public List<Cat> getCatsByUser(User user) {
            return userService.getCatByUser(user);
        }
        
        //新增方法
        @Override
        public Map<String, Cat> getAllCats() {
            return userService.getAllCats();
        }
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    }
    

    然后我们再次使用之前的地址进行访问,发现效果还是一样的。

    2.2 添加拦截器

    在上面配置的基础上进行添加,在applicationContext.xml中:

    <jaxws:endpoint
        implementor="#helloWorldWs"
        address="/fkjava">
        <!-- 如果要添加out拦截器,则使用 jaxws:outInterceptors标签定义 -->
        <jaxws:inInterceptors>
            <!--这里是临时定义的一个嵌套bean,这是cxf提供的拦截器-->
            <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
            <!--这里是引用容器中已有的一个bean-->
            <!--<ref bean="anotherInterceptor"/>-->
            <!--这里将我们自己的权限控制器引进来-->
            <bean class="org.fkjava.cxf.ws.auth.AuthInterceptor"/>
        </jaxws:inInterceptors>
    </jaxws:endpoint>
    

    此时,和以前一样我们需要在客户端(工程Call_CXFSpring)那边加上拦截器,添加上用户名和密码的头,然后对服务器进行访问。以此来进行验证。客户端中我们运行类:
    MyClient.java

    package org.fkjava.cxf.ws.client;
    import org.apache.cxf.endpoint.Client;
    import org.apache.cxf.frontend.ClientProxy;
    import org.fkjava.cxf.ws.auth.AddHeaderInterceptor;
    import org.fkjava.cxf.ws.Entry;
    import org.fkjava.cxf.ws.HelloWorld;
    import org.fkjava.cxf.ws.StringCat;
    import org.fkjava.cxf.ws.impl.HelloWorldWs;
    
    public class MyClient {
    
        public static void main(String[] args) {
            HelloWorldWs factory = new HelloWorldWs();
            HelloWorld hw = factory.getHelloWorldWsPort();
            
            Client client = ClientProxy.getClient(hw) ;//调用此方法,以远程WebService的代理为参数
            client.getOutInterceptors().add(new AddHeaderInterceptor("大熊", "111"));
            
            System.out.println(hw.sayHi("张三"));
            StringCat sc = hw.getAllCats();
            for(Entry entry : sc.getEntries()){
                System.out.println(entry.getKey() + ":" + entry.getValue().getName());
            }
        }
    }
    

    访问服务端。


    2

    三、另一种整合方式

    传统的SSH项目中,一般在本地是有相关的数据的,但是有一种场景是我们需要调用别人的数据,但是别人的数据不可能让我们进行修改等操作,那么别人只会暴露一个WebService,而我们就需要去调用别人的WebService服务器。我们在访问别人时,只能得到WSDL文档。此时我们的项目中就不需要业务逻辑组件了,直接去调用别人的WebService的一个代理即可。

    3.1 环境

    首先我们拷贝上面的工程,改名为cxf_springClient,然后需要增加struts2的相关jar包:

    asm-3.3.jar(会和CXF包中的重复,删掉低版本)、
    asm-commons-3.3.jar、
    asm-tree-3.3.jar、
    commons-lang3-3.2.jar、
    commons-fileupload-1.3.1.jar、
    commons-io-2.2.jar、
    commons-lang-2.4.jar(会和CXF中的重复,删掉低版本)、
    freemarker-2.3.22.jar、
    javassist-3.11.0.GA.jar、
    ognl-3.0.6.jar、
    struts2-core-2.3.24.jar、
    xworks-core-2.3.24.jar。
    strut22-spring-plugin-2.3.24.1.jar(用于和spring集成的插件)
    

    将原有的一些包删掉,留下权限包org.fkjava.cxf.ws.auth。然后我们启动工程Auth_Server提供远程服务。在web工程中生成相应的包及程序。

    3.2 配置

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!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>
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
        </context-param>
    
        <!-- struts2 -->
        <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>
        
        <!-- 使用一个监听器加载spring容器,保证web应用启动时加载spring -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    </web-app>
    

    说明:这里我们不再需要CXFservlet了,因为不需要业务类了,我们直接调用远程业务即可。同时配置struts2的核心控制器。

    applicationContext.xml

    <?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:jaxws="http://cxf.apache.org/jaxws" 
             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-4.0.xsd
               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
               http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
               http://cxf.apache.org/jaxws
               http://cxf.apache.org/schemas/jaxws.xsd">
    
        <import resource="classpath:META-INF/cxf/cxf.xml"/>
            
        <!-- action依赖的是远程WebService的代理,所以这里不能配置本地的业务逻辑组件,而是需要
        配置远程WebService代理,为了保证该WebService代理对象可以自动装配给action,因此应该保证该id的值与action中的setter方法名对应 -->
        <jaxws:client   id="hw"
                        serviceClass="org.fkjava.cxf.ws.HelloWorld"
                        address="http://localhost:8888/myService">
                        <jaxws:outInterceptors>
                            <bean class="org.fkjava.cxf.ws.auth.AddHeaderInterceptor">
                                <constructor-arg value="大熊"/>
                                <constructor-arg value="111"/>
                            </bean>
                        </jaxws:outInterceptors>
        </jaxws:client>
    </beans>
    

    说明:这里我们同样不需要业务类了,但是需要配置远程业务代理类(serviceClass)。同时注意:不要将端口设置为8080,会冲突。可以看到我们使用serviceClass将接口配置进去,而这里的id不能随便写,要和action中定义的接口名一致。由于远程服务器设置了权限拦截,所以这里使用过滤器将用户名和密码设置到wsdl文档的头中。然后在这个类中我们需要使用execute方法去获取相应的数据。

    struts.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    <struts>
        <constant name="struts.enable.DynamicMethodInvocation" value="false" />
        <constant name="struts.devMode" value="true" />
        <package name="default" namespace="/" extends="struts-default">
            <action name="listCats" class="org.fkjava.cxf.ws.action.ListCatsAction">
                <result name="success">
                    /WEB-INF/content/listCats.jsp
                </result>
            </action>
        </package>
    </struts>
    

    3.3 Action

    ListCatsAction .java

    package org.fkjava.cxf.ws.action;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import org.fkjava.cxf.ws.Entry;
    import org.fkjava.cxf.ws.Cat;
    import org.fkjava.cxf.ws.HelloWorld;
    import org.fkjava.cxf.ws.StringCat;
    import com.opensymphony.xwork2.ActionSupport;
    
    public class ListCatsAction extends ActionSupport {
        
        private HelloWorld hw ;
        private Map<String, Cat> cats;
        
        public HelloWorld getHw() {
            return hw;
        }
        public void setHw(HelloWorld hw) {
            this.hw = hw;
        }
    
        public Map<String, Cat> getCats() {
            return cats;
        }
        public void setCats(Map<String, Cat> cats) {
            this.cats = cats;
        }
        
        //此处的action调用的是远程WebService方法
        public String execute(){
            StringCat sc = hw.getAllCats();
            Map<String, Cat> map = new HashMap<String, Cat>();
            for(Entry entry : sc.getEntries()){
                map.put(entry.getKey(), entry.getValue());
            }
            setCats(map);
            return SUCCESS;
        }
    }
    

    说明:此时我们就可以使用地址http://localhost:8080/cxf_springClient/listCats进行访问了,当然会报找不到jsp的错误。

    3.4 listCats.jsp

    content/listCats.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
                pageEncoding="UTF-8" isELIgnored="false"%>
    <%@taglib prefix="s" uri="/struts-tags"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>所有的猫</title>
    </head>
    <body>
        <ul>
            <s:iterator var="entry" value="cats" >
                <li>${entry.key }-->${entry.value.name }-->${entry.value.color }</li>
            </s:iterator>
        </ul>
    </body>
    </html>
    

    说明:此时访问就可以看到

    1
    这样就表示成功。

    相关文章

      网友评论

        本文标题:6、CXF与spring的整合(WebService的整合)

        本文链接:https://www.haomeiwen.com/subject/zeexjttx.html