Spring mvc 和 CXF 搭建SOAP环境

最近用Spring mvc框架搭建web工程,后因为业务需要重新需要在原有web工程基础上,添加Webservice接口。这就涉及到一个问题: 在spring mvc 配置文件中如何添加一些WS框架。在添加之初发现一个问题: 当WS配置文件配置到spring**-servlet 。会遇到一个问题:能访问controller请求时候,WS会提示No Service Availble 显示 。或者Controller都访问不了。具体原因是 : 有重复定义当前当前配置信息。解决方法如下:

Spring MVC是通过DispatcherServlet来加载Spring配置文件的,因此不需要在web.xml中配 ContextLoaderListener。但是CXF却需要通过ContextLoaderListener来加载Spring。

这样就产生了一个矛盾,如果不配置ContextLoaderListener,CXF就无法正常使用。但如果配置 ContextLoaderListener,又会造成Spring的重复加载(DispatcherServlet一次,ContextLoaderListener一次)

在网上查了一下资料,只看到一个国外的程序员提出不配置ContextLoaderListener,通过写一个CXFController,来替代默认的CXFServlet。但是这种HACK的方式总是不太好

所以我采用一种折中的方式,来解决Spring MVC和cxf并存的问题。但是也不是很优雅,希望有人能给出更好的办法

首先是web.xml的配置

Xml代码收藏代码

  1. <?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" xmlns:web="http://java.sun.com/xml/ns/javaee"
        xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp"
        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>payutilservices</display-name>
        <!-- 在ContextLoaderListener里面,加载cxf和spring的公共配置信息。
        然后在DispatcherServlet中加载spring mvc所需的信息。利用Spring配置文件拆分的方式,
        既实现spring mvc和cxf的共存,又避免spring配置信息的重复加载  -->
        <context-param>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>   
                WEB-INF/beans.xml,   
                WEB-INF/cxf.xml  
            </param-value>   
        </context-param>  
          
        <listener>    
            <listener-class>    
                org.springframework.web.context.ContextLoaderListener    
            </listener-class>    
        </listener>
        
        <servlet>
            <servlet-name>payutilservices</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>payutilservices</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        
        <servlet>    
            <servlet-name>CXFServlet</servlet-name>    
            <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>    
            <load-on-startup>2</load-on-startup>    
        </servlet> 
        
        <servlet-mapping>    
            <servlet-name>CXFServlet</servlet-name>    
            <url-pattern>/webservice/*</url-pattern>    
        </servlet-mapping>    
    
        <filter>
            <filter-name>setEncoding</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>setEncoding</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <filter>
            <filter-name>HiddenHttpMethodFilter</filter-name>
            <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>HiddenHttpMethodFilter</filter-name>
            <servlet-name>payutilservices</servlet-name>
        </filter-mapping>
        
        <jsp-config>
            <jsp-property-group>
                <url-pattern>*.jsp</url-pattern>
                <trim-directive-whitespaces>true</trim-directive-whitespaces>
            </jsp-property-group>
            <jsp-property-group>
                <description>HTML Encoding</description>
                <display-name>HTML Encoding Config</display-name>
                <url-pattern>*.html</url-pattern>
                <el-ignored>true</el-ignored>
                <page-encoding>gbk</page-encoding>
                <scripting-invalid>true</scripting-invalid>
            </jsp-property-group>
        </jsp-config>
        <session-config>
            <session-timeout>60</session-timeout>
        </session-config>
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    </web-app>


在ContextLoaderListener里面,加载cxf和spring的公共配置信息。然后在DispatcherServlet中加载 spring mvc所需的信息。利用Spring配置文件拆分的方式,既实现spring mvc和cxf的共存,又避免spring配置信息的重复加载

然后是公共的配置信息,beans.xml

Xml代码收藏代码

  1. <?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:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
        xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"
          xmlns:sws="http://www.springframework.org/schema/web-services"
      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/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd    
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util-3.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    
        <!-- 基于注解的根包扫描路径 -->
        <context:component-scan base-package="com.ty.payutilservices" />
        
        <bean id="ts" class="com.ty.payutilservices.dao.GenericDaoImpl" />
        
        <!-- Spring默认的MVC基于注解风格定义的拦截器 添加自己的拦截器 <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> 
            <property name="interceptors"> <list> </list> </property> </bean> -->
        <!-- 基于注解风格的JSON配置 -->
        <bean id="json_demo" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="supportedMediaTypes">  
                <list>  
                    <value>text/html;charset=UTF-8</value>  
                </list>  
            </property>  
        </bean>  
        
        <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >  
            <property name="messageConverters">  
                 <util:list id="beanList">    
                     <ref bean="json_demo"/>  
                 </util:list>   
            </property>  
        </bean>  
    
        <!-- 加载jdbc配置 -->
        <context:property-placeholder location="classpath:jdbc.properties" />
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            <property name="url" value="${jdbc.url}" />
            <property name="driverClassName" value="${jdbc.DriverClassName}" />
            <property name="username" value="${username}" />
            <property name="password" value="${password}" />
            <property name="maxActive" value="${jdbc.maxActive}" />
            <property name="maxIdle" value="${jdbc.maxIdle}" />
            <property name="maxWait" value="${jdbc.maxWait}" />
        </bean>
    
        <!-- 声明iBatis模板类 -->
        <bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
            <property name="sqlMapClient">
                <bean class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
                    <property name="dataSource" ref="dataSource" />
                    <property name="configLocation" value="classpath:sqlMapConfig.xml" />
                </bean>
            </property>
        </bean>
    
        <!-- 事务控制器 -->
        <bean id="txManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource">
                <ref local="dataSource" />
            </property>
        </bean>
    
        <!-- 实现基于注解的事务管理 -->
        <tx:annotation-driven transaction-manager="txManager" />
    
        <!-- 全局国际化资源配置 -->
        <bean id="messageSource"
            class="org.springframework.context.support.ResourceBundleMessageSource"
            p:basename="i18n/messages" />
    
        <!-- 缺省异常页面配置 -->
        <bean id="exceptionResolver"
            class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
            <!-- to /commons/error.jsp -->
            <property name="defaultErrorView" value="/common/error" />
            <property name="exceptionMappings">
                <props>
                    <prop key="java.sql.SQLException">/common/error</prop>
                    <prop key="java.lang.Exception">/common/error</prop>
                    <prop key="java.lang.NumberFormatException">/common/error</prop>
                </props>
            </property>
        </bean>
        
    </beans>


然后是cxf所需的信息,cxf.xml

Xml代码收藏代码

  1. <?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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans  
                                http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
                                http://cxf.apache.org/jaxws   
                                http://cxf.apache.org/schemas/jaxws.xsd">
    
        <import resource="classpath:META-INF/cxf/cxf.xml" />
        <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
        
        <!-- 测试用 -->
        <bean id="hello" class="com.ty.payutilservices.controller.ws.impls.HelloWorldImpl" />
        <jaxws:endpoint id="helloWorld" implementor="#hello" address="/HelloWorld" />
    
    </beans>


最后是spring mvc所需的信息,spring-mvc.xml

Xml代码收藏代码

  1. <?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:p="http://www.springframework.org/schema/p"  
            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-3.1.xsd  
                                    http://www.springframework.org/schema/context   
                                    http://www.springframework.org/schema/context/spring-context-3.1.xsd  
                                    http://www.springframework.org/schema/mvc  
                                    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">  
        <!--当前工程项目目录 不要带*-->
        <context:component-scan base-package="com.ty.payutilservices" />  
          
        <mvc:annotation-driven />  
          
        <mvc:default-servlet-handler />  
          
        <!-- Default ViewResolver -->
        <bean id="viewResolver"
            class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="viewClass"
                value="org.springframework.web.servlet.view.JstlView" />
            <property name="prefix" value="/WEB-INF/jsp/" />
            <property name="suffix" value=".jsp"></property>
        </bean>
        
    </beans>


下面是在CXF官网添加的例子:

首先是当前WS接口:

import javax.jws.WebService;
@WebService
public interface HelloWorld {
    String sayHi(String text);
}

其次是当前WS实现类:

import javax.jws.WebService;
import com.ty.payutilservices.controller.ws.HelloWorld;
@WebService(endpointInterface = "com.ty.payutilservices.controller.ws.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
 
    public String sayHi(String text) {
        System.out.println("sayHi called");
        return "Hello " + text;
    }
}

在浏览器中输入:

http://localhost:8080/payutilservices/webservice/HelloWorld?wsdl

显示当前WS描述信息 :

Spring mvc 和 CXF 搭建SOAP环境


测试当前WS :

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class TestGreetingService {
    public static void main(String[] args) {  
        //创建WebService客户端代理工厂  
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();  
        //注册WebService接口  
        factory.setServiceClass(HelloWorld.class);  
        //设置WebService地址  
        factory.setAddress("http://localhost:8080/payutilservices/webservice/HelloWorld");  
        HelloWorld greetingService = (HelloWorld)factory.create();  
        System.out.println("invoke webservice...");  
        System.out.println("message context is:"+greetingService.sayHi("xulong"));     
    }  
}


可以看到,集成cxf和spring mvc确实不算很方便,需要绕一绕。上述方法只是一个折中的方案,希望新版本的cxf可以提供一个CXFController,这样的话就可以统一用 DispatcherServlet来加载Spring,不配置ContextLoaderListener。这样的话web.xml可以简洁很多。或者如果哪位网友有更好的方式,请指教一下

你可能感兴趣的:(spring,mvc,CXF,搭建SOAP环境)