Spring mvc 和 CXF 搭建SOAP環境

最近用Spring mvc框架搭建web工程,後由於業務須要從新須要在原有web工程基礎上,添加Webservice接口。這就涉及到一個問題: 在spring mvc 配置文件中如何添加一些WS框架。在添加之初發現一個問題: 當WS配置文件配置到spring**-servlet 。會遇到一個問題:能訪問controller請求時候,WS會提示No Service Availble 顯示 。或者Controller都訪問不了。具體緣由是 : 有重複定義當前當前配置信息。解決方法以下:
javascript

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的配置
html

Xml代碼收藏代碼java

  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代碼收藏代碼web

  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
spring

Xml代碼收藏代碼sql

  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
apache

Xml代碼收藏代碼json

  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描述信息 :


測試當前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能夠簡潔不少。或者若是哪位網友有更好的方式,請指教一下

相關文章
相關標籤/搜索