前段時間忽然想用SpringMVC結合Ext作一個框架原型,整合後發現SpringMVC配合Ext簡直完美無缺,固然SpringMVC結合別的 UI框架應該也是完美無缺的。SpringMVC比Struts2確實要強大不少,特別對於Ext框架JSON數據的完美支撐,開發起來至關舒服。 Spring3整合Hibernate4的時候可能有點問題,跟Spring2+Hibernate3有很大的區別,區別在於Hibernate4實現了 對事務的管理,因此Spring針對Hibernate4就沒有提供HibernateDaoSupport這個類。html
整合有個原則是分框架的整合,好比咱們先整合Spring、在整合SpringMVC接着整合Hibernatejava
整合的第一步將Jar引入到工程裏面來,引入以後更改配置項目配置。下面是項目的web.xml文件的詳細信息:web
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- log4j 配置 開始 --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value> /WEB-INF/classes/com/avicit/resource/log4j/log4j.properties </param-value> </context-param> <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>600000</param-value> </context-param> <context-param> <param-name>webAppRootKey</param-name> <param-value>fes.root</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <!-- log4j 配置 結束 --> <!-- 設置servlet編碼開始 --> <filter> <filter-name>CharacterEncodingFilter</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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 設置servlet編碼結束 --> <!-- 設置BackURL開始 --> <filter> <filter-name>BackURLFilter</filter-name> <filter-class>com.avicit.framework.web.filter.BackURLFilter</filter-class> </filter> <filter-mapping> <filter-name>BackURLFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 設置BackURL結束 --> <!-- Spring配置文件開始 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:com/avicit/resource/spring/spring-base.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- Spring配置文件結束 --> <filter> <filter-name>openSessionInVieFilter</filter-name> <filter-class> org.springframework.orm.hibernate4.support.OpenSessionInViewFilter </filter-class> </filter> <filter-mapping> <filter-name>openSessionInVieFilter</filter-name> <servlet-name>spring</servlet-name> </filter-mapping> <!-- 瀏覽器不支持put,delete等method, 由該filter將/blog?_method=delete轉換爲標準的http delete方法 --> <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>spring</servlet-name> </filter-mapping> <servlet> <servlet-name>spring-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:com/avicit/resource/spring/spring-dispather.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <error-page> <error-code>500</error-code> <location>/error.jsp?code=500</location> </error-page> <error-page> <error-code>404</error-code> <location>/error.jsp?code=404</location> </error-page> <error-page> <error-code>405</error-code> <location>/error.jsp?code=405</location> </error-page> <error-page> <error-code>406</error-code> <location>/error.jsp?code=406</location> </error-page> <error-page> <error-code>415</error-code> <location>/error.jsp?code=415</location> </error-page> <error-page> <error-code>400</error-code> <location>/error.jsp?code=400</location> </error-page> <welcome-file-list> <welcome-file>/index</welcome-file> </welcome-file-list></web-app>
其實Spring的配置跟之前沒多大區別,關鍵就是設置Spring的啓動監聽器和Spring配置文件的地址,下面是spring-base.xml的內容: spring
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd "> <!-- 掃描註解Bean --> <context:component-scan base-package="com.avicit"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath*:com/avicit/resource/jdbc/jdbc.properties</value> <value>classpath*:com/avicit/resource/hibernate/hibernate.properties</value> </list> </property> </bean> <!-- 國際化的消息資源文件 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <!-- 在web環境中必定要定位到classpath 不然默認到當前web應用下找 --> <value>classpath:com/avicit/resource/message/messages</value> </list> </property> <property name="defaultEncoding" value="UTF-8"/> <property name="cacheSeconds" value="60"/> </bean> <import resource="classpath*:com/avicit/resource/spring/spring-dao.xml"/></beans>
這一段配置也沒有什麼特別地方,加載jdbc.properties數據庫配置和hiberate.properties配置文件、sql
設置掃描Annotation註冊Bean的包,可是下面有段配置可能不是很熟悉: 數據庫
<context:component-scan base-package="com.avicit"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
這裏設置了不掃描的Annotation的類型,這是由於org.springframework.stereotype.Controller是 SpringMVC的控制器的註解,使用這個註解註冊的Bean在SpringMVC容器啓動的時候已經實例化了,因此在Spring容器裏面就不須要進 行實例化了。express
在web.xml文件的配置中能夠看到這麼一段配置:json
<servlet> <servlet-name>spring-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:com/avicit/resource/spring/spring-dispather.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
這個就是SpringMVC的配置,配置SpringMVC的容器也能夠說是調度器,下面看下spring-dispather.xml中的配置:瀏覽器
<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:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd 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"> <!-- 會自動註冊了validator ConversionService --> <mvc:annotation-driven validator="validator" conversion-service="conversion-service" /> <!-- 如下 validator ConversionService 在使用 mvc:annotation-driven 會 自動註冊 --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="providerClass" value="org.hibernate.validator.HibernateValidator" /> <!-- 若是不加默認到 使用classpath下的 ValidationMessages.properties --> <property name="validationMessageSource" ref="messageSource" /> </bean> <bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" /> <!-- 開啓controller註解支持 --> <!-- 注:若是base-package=com.avicit 則註解事務不起做用 TODO 讀源碼 --> <context:component-scan base-package="com.avicit"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> </context:component-scan> <mvc:resources mapping="/**" location="/" /> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*" /> <bean class="com.avicit.framework.interceptor.dispatcher.HandlerDispatcherContextInterceptor"> </bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/*" /> <bean class="com.avicit.framework.interceptor.pagination.HandlerPaginationInterceptor"> </bean> </mvc:interceptor> </mvc:interceptors> <mvc:view-controller path="/" view-name="forward:/index" /> <!-- 當在web.xml 中 DispatcherServlet使用 <url-pattern>/</url-pattern> 映射時, 能映射靜態資源 --> <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /> <bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> </bean> <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="mediaTypes"> <map> <entry key="json" value="application/json" /> <entry key="xml" value="application/xml" /> <entry key="html" value="text/html" /> </map> </property> <property name="viewResolvers"> <list> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" /> <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/" /> <property name="suffix" value=".jsp" /> </bean> </list> </property> </bean> <!-- 控制器異常處理 --> <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="java.lang.Exception"> error </prop> </props> </property> </bean> </beans>
這一部分配置是依據官方來的文檔來的,你們看看文檔就能夠明白這段配置,在這裏就不贅述了。可是這裏有很關鍵的一處配置是官方文檔沒有提到的,也是整合Hiberate4中關鍵的配置,若是沒有配置Hibernate確定跑不起來,這段配置: spring-mvc
<!-- 開啓controller註解支持 --> <!-- 注:若是base-package=com.avicit 則註解事務不起做用 TODO 讀源碼 --> <context:component-scan base-package="com.avicit"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> </context:component-scan>
這裏配置了掃描Controller,經過Controller註解註冊的Bean是SpringMVC的控制器,可是爲何要排除Service註解 呢?這是由於經過Service註冊的Bean是要進行事務處理的。要生成動態代理進行事務控制,因此若是不排除的話,Service註冊的Bean是不 帶事務處理的。因此在整合Hibernate的時候就會報沒有事務的異常。
最後看Hibernate在Spring中如何配置,也就是spring-dao.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" x mlns: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: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-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/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource"> <property name="alias" value="proxoolDataSource" /> <property name="driver" value="${jdbc.driver}" /> <property name="driverUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="maximumConnectionCount" value="${jdbc.maximum.connection.count}" /> <property name="minimumConnectionCount" value="${jdbc.minimum.connection.count}" /> <property name="statistics" value="${jdbc.statistics}" /> <property name="simultaneousBuildThrottle" v alue="${jdbc.simultaneous.build.throttle}" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan" value="com.avicit" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.query.substitutions"> ${hibernate.query.substitutions}</prop> <prop key="hibernate.default_batch_fetch_size"> ${hibernate.default_batch_fetch_size}</prop> <prop key="hibernate.max_fetch_depth">${hibernate.max_fetch_depth}</prop> <prop key="hibernate.generate_statistics"> ${hibernate.generate_statistics}</prop> <prop key="hibernate.bytecode.use_reflection_optimizer"> ${hibernate.bytecode.use_reflection_optimizer}</prop> <prop key="hibernate.cache.use_second_level_cache"> ${hibernate.cache.use_second_level_cache}</prop> <prop key="hibernate.cache.use_query_cache"> ${hibernate.cache.use_query_cache}</prop> <prop key="hibernate.cache.region.factory_class"> ${hibernate.cache.region.factory_class}</prop> <prop key="net.sf.ehcache.configurationResourceName"> ${net.sf.ehcache.configurationResourceName}</prop> <prop key="hibernate.cache.use_structured_entries"> ${hibernate.cache.use_structured_entries}</prop> </props> </property> </bean> <bean id="lookupResolver" class="com.avicit.framework.support.matchrule.context.HibernateMatchRuleResolver"> <property name="packagesToScan" value="com.avicit.fes.*" /> </bean> <!-- 開啓AOP監聽 只對當前配置文件有效 --> <aop:aspectj-autoproxy expose-proxy="true" /> <!-- 開啓註解事務 只對當前配置文件有效 --> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="merge*" propagation="REQUIRED" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="put*" propagation="REQUIRED" /> <tx:method name="use*" propagation="REQUIRED" /> <!--hibernate4必須配置爲開啓事務 不然 getCurrentSession()獲取不到 --> <tx:method name="get*" propagation="REQUIRED" read-only="true" /> <tx:method name="count*" propagation="REQUIRED" read-only="true" /> <tx:method name="find*" propagation="REQUIRED" read-only="true" /> <tx:method name="list*" propagation="REQUIRED" read-only="true" /> <tx:method name="*" read-only="true" /> </tx:attributes> </tx:advice> <aop:config expose-proxy="true"> <!-- 只對業務邏輯層實施事務 --> <aop:pointcut id="txPointcut" expression="execution(* com.avicit..service..*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" /> </aop:config> </beans>
Hibernate的配置跟Hibernate3沒有很大的區別,惟一的區別就是全部的操做都必須開啓事務。
Spring3+Hibernate4的框架整合差很少,後面會寫如何實現SpringMVC整合Ext,那纔是更有意思的部分。