最近用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代碼
<?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代碼
<?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代碼
<?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代碼
<?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能夠簡潔不少。或者若是哪位網友有更好的方式,請指教一下