項目搭建采用技術棧為:Spring+Spring MVC+Hibernate+Jsp+Gradle+tomcat+mysql5.6
搭建環境文檔目錄結構說明:
- 使用Intellj Idea 搭建項目過程詳解
- 項目各配置文件講解及部署
- 各層包功能講解&項目搭建完畢最終效果演示圖
- 項目中重要代碼講解
- webapp文件夾下分層詳解
- 配置tomcat 運行環境
1. 使用Intellj Idea 搭建項目過程詳解
1.1 打開Intellj Idea

1.2 操縱 Intellj Idea 工具欄 新建項目







需要說明的是,最初創建的項目視圖是不完整的,包括webapp文件夾下沒有web.xml,以及src包下缺少Java文件夾(放置java源代碼文件),Resources文件夾(放置項目配置文件)。
我們繼續做以下操作,使得項目的結構符合web 應用項目的層級標准。

出現如下視圖:


接下來:單擊main文件夾按照如下操作:


點擊ok,再按照上圖操作操作一遍,輸入文件名為resources
最終的結構圖如下圖所示:

2. 項目各配置文件講解及部署
完成了項目的初始化結構創建,接下來我們需要來創建配置文件。
首先是resources文件夾下的配置文件
2.1 resources下資源文件截圖:(最終配置的結果)

2.2 data-access-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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <!-- 配置自動掃描的包 --> <context:component-scan base-package="com.fxmms" use-default-filters="false"> <context:include-filter type="regex" expression="com.fxmms.*.*.dao.*"/> <context:include-filter type="regex" expression="com.fxmms.*.dao.*"/> </context:component-scan> <!-- 配置數據源 --> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverClass}"/> <property name="url" value="${jdbc.jdbcUrl}"/> <property name="username" value="${jdbc.user}"/> <property name="password" value="${jdbc.password}"/> </bean> <!--配置hibernate SessionFactory--> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${dataSource.hibernate.dialect}</prop> <prop key="hibernate.show_sql">${dataSource.hibernate.show_sql}</prop> <prop key="hibernate.format_sql">true</prop> <!--負責自動創建數據表,基本上不能打開注釋,否則所有的數據庫中表信息都會被刪除,重新創建--> <!-- <prop key="hibernate.hbm2ddl.auto">create</prop> --> </props> </property> <!-- <property name="hibernate.jdbc.batch_size" value="50"></property> --> <property name="packagesToScan"> <list> <value>com.fxmms.*.*.domain</value> <value>com.fxmms.*.domain</value> </list> </property> </bean> <!--jdbcTemplate start --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!--Spring JDBC 中操作 LOB 數據 --> <bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" lazy-init="true"></bean> <!-- 配置JPA部分 --> <!-- 配置JPA的EntityManagerFactory --> <!-- <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean> </property> <property name="packagesToScan" value="com.fxmms"></property> <property name="jpaProperties"> <props> <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <prop key="hibernate.cache.use_second_level_cache">true</prop> <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory </prop> <prop key="hibernate.cache.use_query_cache">true</prop> </props> </property> <!–使用二級緩存–> <property name="sharedCacheMode" value="ENABLE_SELECTIVE"></property> </bean> <!– 配置事務 –> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"></property> </bean>--> <!-- <!– 配置SpringData部分 –> <jpa:repositories base-package="com.fxmms" entity-manager-factory-ref="entityManagerFactory"> </jpa:repositories>--> </beans>
2.3 service-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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"> <aop:aspectj-autoproxy/> <!--設置定時任務--> <task:annotation-driven/> <context:component-scan base-package="com.fxmms.www" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <!-- enable the configuration of transactional behavior based on annotations --> <tx:annotation-driven transaction-manager="txManager"/> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> </beans>
2.4 default-servlet.xml
設置springmvc-applicationContext.xml,前端控制器將請求轉發到相應的controller層中的處理方法上。
<?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:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!----> <mvc:annotation-driven> <!--json解析--> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"/> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven> <context:component-scan base-package="com.fxmms.www.controller"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--因為web.xml中defaultDispatcherServlet對所有請求進行了攔截,所以對一些.css .jpg .html .jsp也進行了攔截,所以此配置項 保證對對靜態資源不攔截--> <mvc:default-servlet-handler/> <!--視圖解析器--> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <!--配置文件上上傳--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="utf-8"/> <property name="maxUploadSize" value="10485760000"/> <property name="maxInMemorySize" value="40960"/> </bean> </beans>
2.5 spring-security.xml
設置spring-security 權限控制配置文件,項目中權限的控制統一在此配置文件中配置,包括從數據庫中獲取用戶的相關信息,以及配置相應pattern的請求過濾規則。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:sec="http://www.springframework.org/schema/security" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd"> <!-- <sec:http pattern="/**/*.jpg" security="none"></sec:http> <sec:http pattern="/**/*.jpeg" security="none"></sec:http> <sec:http pattern="/**/*.gif" security="none"></sec:http> <sec:http pattern="/**/*.png" security="none"></sec:http>s <sec:http pattern="/getCode" security="none" /><!– 不過濾驗證碼 –> <sec:http pattern="/test/**" security="none"></sec:http><!– 不過濾測試內容 –>--> <!--spring security 權限管理配置文件--> <context:component-scan base-package="com.fxmms.common.security"> </context:component-scan> <context:property-placeholder location="classpath:db.properties"></context:property-placeholder> <!--權限控制--> <sec:http auto-config="true" use-expressions="true"> <sec:intercept-url pattern="/superadmin/**" access="hasRole('superadmin')"/> <sec:intercept-url pattern="/admin/**" access="hasRole('admin')"/> <sec:intercept-url pattern="/customer/**" access="hasRole('customer')"/> <!--自定義登陸頁面,權限驗證失敗頁面,登錄成功頁面--> <sec:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp" login-processing-url="/j_spring_security_check" authentication-success-handler-ref="loginSuccessHandler"/> <!--用戶權限不一致出現的權限不可得情況,默認情況下跳轉到403頁面--> <sec:access-denied-handler ref="accessDeniedServletHandler" /> <sec:logout logout-success-url="/login.jsp" /> </sec:http> <sec:authentication-manager> <sec:authentication-provider> <!--配置從數據庫查詢用戶權限 and isDelete = 0 and enable = 1--> <sec:jdbc-user-service data-source-ref="dataSource" users-by-username-query="select userName,password,enable from mms_admin where userName=? and isDelete = 0 and enable = 1" authorities-by-username-query="select userName,role from mms_admin where username=?" ></sec:jdbc-user-service> </sec:authentication-provider> </sec:authentication-manager> </beans>
2.6 db.properties
數據庫訪問配置文件
jdbc.user=root
jdbc.password=feixun*123
jdbc.driverClass=com.mysql.jdbc.Driver
#jdbc.jdbcUrl=jdbc:mysql://localhost/fxmms?useUnicode=true&characterEncoding=UTF-8
jdbc.jdbcUrl=jdbc:mysql://222.73.156.132:13306/fxmms?useUnicode=true&characterEncoding=UTF-8
jdbc.initPoolSize=5
jdbc.maxPoolSize=20
dataSource.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
#######################
## local ##
#######################
dataSource.hibernate.show_sql=true
2.7 log4j.properties
配置項目日志文件,日志輸出模式為Console
###########################################################################
# Properties file for the log4j logger system
#
# Note: During the uPortal build, the file at /properties/Logger.properties is copied
# to the log4j standard location /WEB-INF/classes/log4j.properties . This means that editing the file
# at /properties/Logger.properties in a deployed uPortal will have no effect.
#
# Please read the instructions for the Log4J logging system at
# http://jakarta.apache.org/log4j/ if you want to modify this.
###########################################################################
# You should probably replace the word "debug" with "info" in the
# following line after everything is running. This will turn off
# the tons of debug messages, and leave only INFO, WARN, ERROR, etc.
#
log4j.rootLogger = info,stdout,D,E
#配置stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss,SSS} [%p]-[%l] %m%n
#配置D 保存info debug級別的系統日志信息
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#/Users/mark/mms/log.log 指定info debug級別日志信息存儲位置
log4j.appender.D.File = /Users/mark/mms/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = INFO,DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH\:mm\:ss,SSS} [%p]-[%l] %m%n
#配置E 保存系統異常日志
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
#/Users/mark/mms/error.log 指定info debug級別日志信息存儲位置
log4j.appender.E.File = /Users/mark/mms/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %d{yyyy-MM-dd HH\:mm\:ss,SSS} [%p]-[%l] %m%n
#log4j.logger.org.hibernate=INFO
#
## Log all JDBC parameters
#log4j.logger.org.hibernate.type=ALL
##Hibernate begin 打印每次數據訪問產生的sql語句至log.log 文件當中##
log4j.logger.org.hibernate=info
#配置SQL打印與輸出
log4j.logger.org.hibernate.SQL=DEBG
log4j.logger.org.hibernate.HQL=DEGUG
#log4j.logger.org.hibernate.type=ALL
2.8 web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!--配置需要加載的spring配置文件,這些文件中的配置的類都是被<context:component-scan>掃描到的,比如@Repository @Component @Service @Controller等--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:data-access-applicationContext.xml;classpath:spring-security.xml;classpath:service-applicationContext.xml</param-value> </context-param> <!--配置日志監聽 ,如果配置文件報紅,沒有關系可以正常運行,這個與idea的驗證規則有關--> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j.properties</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--配置權限過濾器,注意必須配置在springmvc 之前,因為對用戶訪問資源的權限判斷與控制是在訪問特定url之前發生的--> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置字符編碼過濾器 必須配置在所有過濾器的最前面 --> <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> <!--超級管理員 --> <!-- <filter> <filter-name>superAdminFilter</filter-name> <filter-class>com.fxmms.filter.SuperAdminFilter</filter-class> </filter> <filter-mapping> <filter-name>superAdminFilter</filter-name> <url-pattern>/fxmms/superadmin/*</url-pattern> </filter-mapping> <filter> <filter-name>adminFilter</filter-name> <filter-class>com.fxmms.filter.AdminFilter</filter-class> </filter> <filter-mapping> <filter-name>adminFilter</filter-name> <url-pattern>/fxmms/admin/*</url-pattern> </filter-mapping> <filter> <filter-name>customerFilter</filter-name> <filter-class>com.fxmms.filter.CustomerFilter</filter-class> </filter> <filter-mapping> <filter-name>customerFilter</filter-name> <url-pattern>/fxmms/customer/*</url-pattern> </filter-mapping> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>com.fxmms.servlet.LoginServlet</servlet-class> </servlet> <servlet> <servlet-name>InvalidateServlet</servlet-name> <servlet-class>com.fxmms.servlet.InvalidateServlet</servlet-class> </servlet>- <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/loginServlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>InvalidateServlet</servlet-name> <url-pattern>/invalidateServlet</url-pattern> </servlet-mapping>--> <!-- 配置看可以把POST請求轉為PUT,DELETE請求的Filter --> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--配置中央控制器,對所有請求進行攔截並做請求路徑,與處理請求樁模塊之間的映射--> <servlet> <servlet-name>defaultDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation </param-name> <param-value>classpath:default-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!--這里是攔截所有--> <servlet-mapping> <servlet-name>defaultDispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
2.9 build.gradle
項目構建腳本
group 'com.fxmms'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'war'
sourceCompatibility = 1.8
repositories {
maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
mavenLocal()
jcenter()
maven { url "http://repo.maven.apache.org/maven2/"}
maven { url 'https://repo.spring.io/libs-milestone'}
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
// servlet-api
compile group: 'javax.servlet', name: 'servlet-api', version: '2.5'
//spring相關
compile group: 'org.springframework', name: 'spring-webmvc', version: '4.3.3.RELEASE'
compile group: 'org.springframework', name: 'spring-orm', version: '4.3.3.RELEASE'
compile group: 'org.springframework', name: 'spring-aspects', version: '4.3.3.RELEASE'
compile group: 'org.springframework.security', name: 'spring-security-config', version: '3.2.0.RELEASE'
compile group: 'org.springframework.security', name: 'spring-security-taglibs', version: '3.2.0.RELEASE'
compile 'org.springframework.security:spring-security-web:3.2.0.RELEASE'
//hibernate相關
compile 'org.hibernate:hibernate-core:4.3.6.Final'
//c3p0連接池
compile group: 'org.hibernate', name: 'hibernate-c3p0', version: '4.3.6.Final'
//ehcahe二級緩存
compile group: 'org.hibernate', name: 'hibernate-ehcache', version: '4.3.6.Final'
//mysql
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.39'
//springData
compile group: 'org.springframework.data', name: 'spring-data-jpa', version: '1.10.3.RELEASE'
// https://mvnrepository.com/artifact/log4j/log4j日志
compile group: 'log4j', name: 'log4j', version: '1.2.17'
//json解析相關
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.5.4'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.5.4'
//迅雷接口有關jar 包
compile 'org.apache.httpcomponents:httpclient:4.4'
compile 'org.json:json:20141113'
compile group: 'org.apache.clerezza.ext', name: 'org.json.simple', version: '0.4'
//https://mvnrepository.com/artifact/org.apache.commons/commons-io 讀取文件相關
compile group: 'org.apache.commons', name: 'commons-io', version: '1.3.2'
// https://mvnrepository.com/artifact/org.apache.poi/poi 文件讀取相關 apache-poi
compile group: 'org.apache.poi', name: 'poi', version: '3.9'
// https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml 解決execl 版本差異
compile group: 'org.apache.poi', name: 'poi-ooxml', version: '3.9'
// https://mvnrepository.com/artifact/commons-io/commons-io 文件上傳
compile group: 'commons-io', name: 'commons-io', version: '1.3.1'
// https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload
compile group: 'commons-fileupload', name: 'commons-fileupload', version: '1.2.2'
}
3. 各層包功能講解&項目搭建完畢最終效果演示圖
3.1 項目中各層包功能講解
項目中Java源代碼層級結構如下圖所示:

對於www包中的各分層,我們對照上圖重點說明:
controller:用於路由各種HTTP訪問,其中可以實現對前台頁面參數的對象化綁定,這個功能的實現是依賴於spring mvc中的參數綁定功能,以及返回向前端頁面返回數據。也可以實現基於Restful 風格API的編寫。
dao:用於實現對數據庫的操作,包中的代碼繼承並實現自common中的dao 層代碼,采用的是類的適配器模式實現的,這里的代碼值得細細品味,可以說是整個項目的靈魂所在之處,稍后說明。
domain:項目中的所有實體類都存在於這個包中,其中的每個具體實體類與數據庫表相對應。
dto:實現了序列化的數據傳輸層對象,可用於接收前台參數,前台參數被封裝成dto 對象傳輸至后台。同時也負責對從數據庫中查詢數據的封裝。
qo:模糊查詢對象所在的包,用於封裝QBC動態查詢參數。
rowmapper:用於映射jdbcTemplate查詢數據庫返回對象的數據集,並將數據集依照以此對象為集合的實例進行封裝。
schedulejob:定時任務類所在的包,在此包中的類上都要加上@Service注解,因為定時任務注解配置在service-applicationContext.xml中,包掃描組件的規則是只掃描類上有@Service注解的組件類。
service:業務邏輯層,所有的業務邏輯組件Bean都放置在這個保重,其中的類中的業務邏輯方法調用了dao實現類中的方法,並且每個有關於數據庫操作的方法上都加上了@Transaction注解,用於實現對數據庫操作的事務管理。@Transaction是Spring Framework對AOP 的另一種區別於攔截器的自定義注解實現。
4.項目中重要代碼講解
主要講解一下Dao層中代碼對適配器設計模式的應用:
4.1 首先看下commom層中 BaseDao.java
package com.fxmms.common.dao; import com.fxmms.common.ro.Dto; import com.fxmms.common.ro.DtoResultWithPageInfo; import com.fxmms.common.ro.PageQo; import org.hibernate.Criteria; import org.springframework.stereotype.Repository; import java.io.Serializable; import java.util.List; import java.util.Map; /** * * @param <T> * @usage 數據庫公共操作接口 */ @Repository public interface BaseDao<T> { /** * * * @param id * @usage 根據id獲取數據庫中唯一紀錄,封裝成java對象並返回 * @return T */ public T getById(Serializable id); /** * * * @param id * @usage 根據id懶加載數據庫中唯一紀錄,封裝成java對象並返回 * @return T */ public T load(Serializable id); /** * * * @param columnName * * @param value * * @usage 根據列名,以及對應的值獲取數據庫中惟一紀錄,封裝成Java對象並返回 * * @return */ public T getByUniqueKey(String columnName, Object value); /** * * * @param nameValuePairs * * @return T */ public T getUniqueResult(Map<String, Object> nameValuePairs); /** * * * @param columnName * * @param value * * @param sort * * @param order * asc/desc * @return List<T> */ public List<T> getListByColumn(String columnName, Object value, String sort, String order); public List<T> getListByColumn(String columnName, Object value); /** * ͨ * * @param nameValuePairs * * @param sort * * @param order * asc/desc * @return List<T> */ public List<T> getListByColumns(Map<String, Object> nameValuePairs, String sort, String order); public List<T> getListByColumns(Map<String, Object> nameValuePairs); /** * * * @return List<T> */ public List<T> getAll(); /** * * * @param t * @return Serializable id */ public Serializable save(T t); /** * * * @param t */ public void update(T t); /** * * * @param t */ public void delete(T t); /** * QBC * @return */ public Criteria createCriteria(); /** * @param <E> * @param <D> * @param criteria * @param pageNo * @param pageSize * @param dtoClazz * @return */ public <E, D extends Dto> DtoResultWithPageInfo<D> queryPageListByCriteria( Criteria criteria, int pageNo, int pageSize, Class<D> dtoClazz); /** * @param <E> * @param <D> * @param criteria * @param qo * @param class1 * @return */ public <E, D extends Dto> DtoResultWithPageInfo<D> queryPageListByCriteriaWithQo(PageQo qo, Class<D> dtoClazz); }
其中定義了一些對數據庫的抽象公共操作方法,代碼中有注釋,可以對照理解。
4.2 看下HibernateTemplateDao.java對BaseDao.java的抽象實現
package com.fxmms.common.dao.hib; import com.fxmms.common.dao.BaseDao; import com.fxmms.common.ro.Dto; import com.fxmms.common.ro.DtoResultWithPageInfo; import com.fxmms.common.ro.PageInfo; import com.fxmms.common.ro.PageQo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.criterion.Order; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Repository; import org.springframework.util.StringUtils; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * * @param <T> * @usage 應用數據訪問的靈魂,抽象出各種模型類進行數據庫訪問的公共操作。 * 主要使用到QBC動態查詢。主要思想是利用反射。 */ @Repository public abstract class HibernateTemplateDao<T> implements BaseDao<T> { protected static final Log log = LogFactory .getLog(HibernateTemplateDao.class); //通過反射,可以實現對不同類對應的數據表的操作 protected abstract Class<?> getEntityClass(); protected SessionFactory sessionFactory; @Autowired @Qualifier("sessionFactory") public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public Session getSession() { return sessionFactory.getCurrentSession(); } public Session openNewSession() { return sessionFactory.openSession(); } @Override @SuppressWarnings("unchecked") public T getById(Serializable id) { return (T) getSession().get(getEntityClass(), id); } @Override @SuppressWarnings("unchecked") public T getByUniqueKey(String columnName, Object value) { return (T) getSession().createCriteria(getEntityClass()) .add(Restrictions.eq(columnName, value)).uniqueResult(); } @Override @SuppressWarnings("unchecked") public List<T> getListByColumn(String columnName, Object value,String sort,String order) { Criteria criteria = getSession().createCriteria(getEntityClass()); criteria.add(Restrictions.eq(columnName, value)); if(StringUtils.hasText(sort) && StringUtils.hasText(order)){ if("asc".equals(order)){ criteria.addOrder(Order.asc(sort)); }else if("desc".equals(order)){ criteria.addOrder(Order.desc(sort)); } } List<T> list = criteria.list(); return list; } @Override @SuppressWarnings("unchecked") public List<T> getListByColumn(String columnName, Object value) { Criteria criteria = getSession().createCriteria(getEntityClass()); criteria.add(Restrictions.eq(columnName, value)); List<T> list = criteria.list(); return list; } @Override @SuppressWarnings("unchecked") public List<T> getListByColumns(Map<String, Object> nameValuePairs,String sort,String order){ Criteria criteria = getSession().createCriteria(getEntityClass()); for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) { criteria.add(Restrictions.eq(entry.getKey(), entry.getValue())); } if(StringUtils.hasText(sort) && StringUtils.hasText(order)){ if("asc".equals(order)){ criteria.addOrder(Order.asc(sort)); }else if("desc".equals(order)){ criteria.addOrder(Order.desc(sort)); } } List<T> list = criteria.list(); return list; } @Override @SuppressWarnings("unchecked") public List<T> getListByColumns(Map<String, Object> nameValuePairs){ Criteria criteria = getSession().createCriteria(getEntityClass()); for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) { criteria.add(Restrictions.eq(entry.getKey(), entry.getValue())); } List<T> list = criteria.list(); return list; } @Override @SuppressWarnings("unchecked") public List<T> getAll() { return getSession().createCriteria(getEntityClass()).list(); } @Override @SuppressWarnings("unchecked") public T getUniqueResult(Map<String, Object> nameValuePairs) { Criteria criteria = getSession().createCriteria(getEntityClass()); for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) { criteria.add(Restrictions.eq(entry.getKey(), entry.getValue())); } return (T) criteria.uniqueResult(); } @Override @SuppressWarnings("unchecked") public T load(Serializable id){ return (T) getSession().load(getEntityClass(), id); } @Override public Serializable save(T t) { return getSession().save(t); } @Override public void update(T t) { Session session = this.getSession(); session.update(t); //強制刷新緩存中數據至數據庫中,防止大批量數據更新之后出現臟數據 session.flush(); } @Override public void delete(T t) { this.getSession().delete(t); } /** * QO DtoResultWithPageInfo<dtoClazz>list+ҳϢ * * @param page * @param pageSize * @param qo * @param dtoClazz * @return */ /* public <Q extends QueryObject, D extends Dto> DtoResultWithPageInfo<D> queryPageListByQueryObject( int page, int pageSize,Q qo, Class<D> dtoClazz){ Criteria criteria = QueryObjectHelper.buildCriteria(qo, getSession()); return queryPageListByCriteria(criteria, page, pageSize, dtoClazz); }*/ /** * QO List<dtoClazz> * @param qo * @param dtoClazz * @return */ /*public <Q extends QueryObject,E, D extends Dto> List<D> queryListByQueryObject( Q qo, Class<D> dtoClazz){ Criteria criteria = QueryObjectHelper.buildCriteria(qo, getSession()); @SuppressWarnings("unchecked") List<E> list = criteria.list(); List<D> resultsDtoList = new ArrayList<D>(); for(E entity:list){ try { D dto = dtoClazz.newInstance(); BeanUtils.copyProperties(entity, dto); resultsDtoList.add(dto); } catch (InstantiationException e) { log.error("dtoʵ쳣ExMsg==>"+e.getMessage()); } catch (IllegalAccessException e) { log.error("dtoʵ쳣ExMsg==>"+e.getMessage()); } } return resultsDtoList; }*/ /** * queryPageListByCriteria * * ͨcriteria DtoResultWithPageInfo<dtoClazz>list+ҳϢ * * @param criteria * ѯ * @param pageNo * ǰҳ * @param pageSize * ÿҳʾ * @param dtoClass * ݴݶclass * */ /*public <E, D extends Dto> DtoResultWithPageInfo<D> queryPageListByCriteria( Criteria criteria, int pageNo, int pageSize, Class<D> dtoClazz) { PageInfo pageInfo = getInstancePageInfoWithCriteria(criteria, pageNo, pageSize); criteria.setProjection(null);// ͶӰ criteria.setFirstResult(pageInfo.getFirstResultNum()); criteria.setMaxResults(pageInfo.getPageSize()); @SuppressWarnings("unchecked") List<E> resultsList = criteria.list(); List<D> resultsDtoList = new ArrayList<D>(); for (E result : resultsList) { D dto; try { dto = dtoClazz.newInstance(); try { BeanUtils.copyProperties(result, dto); } catch (Exception e) { log.error("ҳѯ쳣bean쳣"); e.printStackTrace(); } } catch (InstantiationException e) { log.error("ҳѯ쳣dtoʼ쳣"); e.printStackTrace(); dto = null; } catch (IllegalAccessException e) { log.error("ҳѯ쳣dtoʼ쳣"); e.printStackTrace(); dto = null; } resultsDtoList.add(dto); } DtoResultWithPageInfo<D> resultWithPageInfo = new DtoResultWithPageInfo<D>( resultsDtoList, pageInfo); return resultWithPageInfo; }*/ /** * ͨcriteria List<dtoClazz> * * @param criteria * @param dtoClazz * @return */ /*public <E, D extends Dto> List<D> queryListByCriteria( Criteria criteria,Class<D> dtoClazz) { @SuppressWarnings("unchecked") List<E> resultsList = criteria.list(); List<D> resultsDtoList = new ArrayList<D>(); for (E result : resultsList) { D dto; try { dto = dtoClazz.newInstance(); try { BeanUtils.copyProperties(result, dto); } catch (Exception e) { log.error("ҳѯ쳣bean쳣"); e.printStackTrace(); } } catch (InstantiationException e) { log.error("ҳѯ쳣dtoʼ쳣"); e.printStackTrace(); dto = null; } catch (IllegalAccessException e) { log.error("ҳѯ쳣dtoʼ쳣"); e.printStackTrace(); dto = null; } resultsDtoList.add(dto); } return resultsDtoList; }*/ /*public DataTablePageList queryDataTablePageListByCriteria( Criteria criteria, String displayStart, String displayLength) { // ܼ¼ long totalRecords = 0L; criteria.setProjection(Projections.rowCount()); totalRecords = (Long) criteria.uniqueResult(); // criteria.setProjection(null); criteria.setFirstResult(Integer.parseInt(displayStart)); criteria.setMaxResults(Integer.parseInt(displayLength)); @SuppressWarnings("rawtypes") List resultsList = criteria.list(); DataTablePageList dtpl = new DataTablePageList( String.valueOf((int) totalRecords), resultsList); return dtpl; } */ /** * ͨѯʼҳϢ * * @param criteria * @param pageNo * @param pageSize * @return *//* private PageInfo getInstancePageInfoWithCriteria(Criteria criteria, int pageNo, int pageSize) { long totalQuantity = 0L; criteria.setProjection(Projections.rowCount()); totalQuantity = (Long) criteria.uniqueResult(); PageInfo pageInfo = PageInfo.getInstance(pageNo, pageSize, totalQuantity); return pageInfo; }*/ @Override public Criteria createCriteria() { // TODO Auto-generated method stub return getSession().createCriteria(getEntityClass()); } /** * queryPageListByCriteria * * ͨcriteria DtoResultWithPageInfo<dtoClazz>list+ҳϢ * * @param criteria * ѯ * @param pageNo * ǰҳ * @param pageSize * ÿҳʾ * @param dtoClass * ݴݶclass * ص DtoResultWithPageInfo * * Ϊ queryPageListByCriteria */ @Override public <E, D extends Dto> DtoResultWithPageInfo<D> queryPageListByCriteria( Criteria criteria, int pageNo, int pageSize, Class<D> dtoClazz) { //˷ĵãpageinfoѾfirstResult maxresult PageInfo pageInfo = getInstancePageInfoWithCriteria(criteria, pageNo, pageSize); criteria.setProjection(null);// ͶӰ criteria.setFirstResult(pageInfo.getFirstResultNum()); criteria.setMaxResults(pageInfo.getPageSize()); @SuppressWarnings("unchecked") List<E> resultsList = criteria.list(); List<D> resultsDtoList = new ArrayList<D>(); for (E result : resultsList) { D dto; try { dto = dtoClazz.newInstance(); try { BeanUtils.copyProperties(result, dto); } catch (Exception e) { log.error("ҳѯ쳣bean쳣"); e.printStackTrace(); } } catch (InstantiationException e) { log.error("ҳѯ쳣dtoʼ쳣"); e.printStackTrace(); dto = null; } catch (IllegalAccessException e) { log.error("ҳѯ쳣dtoʼ쳣"); e.printStackTrace(); dto = null; } resultsDtoList.add(dto); } DtoResultWithPageInfo<D> resultWithPageInfo = new DtoResultWithPageInfo<D>( resultsDtoList, pageInfo); return resultWithPageInfo; } /** * queryPageListByCriteriaWithQo * * ͨcriteria DtoResultWithPageInfo<dtoClazz>list+ҳϢ * * @param criteria * ѯ * @param pageNo * ǰҳ * @param pageSize * ÿҳʾ * @param dtoClass * ݴݶclass * ص DtoResultWithPageInfo * * Ϊ queryPageListByCriteria */ @Override public <E, D extends Dto> DtoResultWithPageInfo<D>