Java 本地開發環境搭建(框架采用 Spring+Spring MVC+Hibernate+Jsp+Gradle+tomcat+mysql5.6)


 

項目搭建采用技術棧為:Spring+Spring MVC+Hibernate+Jsp+Gradle+tomcat+mysql5.6

搭建環境文檔目錄結構說明:

  1. 使用Intellj Idea 搭建項目過程詳解
  2. 項目各配置文件講解及部署
  3. 各層包功能講解&項目搭建完畢最終效果演示圖
  4. 項目中重要代碼講解
  5. webapp文件夾下分層詳解
  6. 配置tomcat 運行環境

1. 使用Intellj Idea 搭建項目過程詳解


1.1 打開Intellj Idea

 
Intellj idea 截圖

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

 
操縱idea 工具欄
 
使用Gradle創建項目
 
完善項目信息
 
設置Gradle
 
確定項目信息
 
選擇New Window
 
初始化項目結構截圖

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

 
操縱工具欄為項目添加 web.xml全局配置文件

出現如下視圖:

 
新建 web.xml文件
 
設置web.xml文件存儲位置

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


 
手動創建src中main文件夾下java目錄
 
輸入java 文件夾名稱

點擊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源代碼層級結構如下圖所示:

 
項目中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> queryPageListByCriteriaWithQo(PageQo qo, Class<D> dtoClazz) { //˷ĵãpageinfoѾfirstResult maxresult Criteria criteria = this.createCriteria(); qo.add(criteria); PageInfo pageInfo = getInstancePageInfoWithCriteria(criteria, qo.getPage(),qo.getRows()); 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; } /** * ͨѯʼҳϢ * * @param criteria * @param pageNo * @param pageSize * @return */ private PageInfo getInstancePageInfoWithCriteria(Criteria criteria, int pageNo, int pageSize) { long totalQuantity = 0L; // ܵtotalQuality criteria.setProjection(Projections.rowCount()); totalQuantity = (Long) criteria.uniqueResult(); PageInfo pageInfo = PageInfo.getInstance(pageNo, pageSize, totalQuantity); return pageInfo; } } 

這個方法是極為重要的 protected abstract Class<?> getEntityClass();
后續介紹,現在暫時有個印象。
在www中的dao層有與各具體類(數據表)相對應的數據庫操作實現:

 
屏幕快照 2016-11-20 下午11.22.30.png

上圖聲明了三個具體類對應的接口聲明:AdminDao、MacDao、TaskDao。
對應三個接口有三個具體的實現類:AdminDaoImpl、MacDaoImpl、TaskDaoImpl。
我們以與Admin類相關的dao層操作為例:
Admin.java

 

package com.fxmms.www.domain; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; /** * Created by mark on 16/11/2. * @usage 管理員實體類,與數據庫中表相對應 */ @Entity @Table(name = "mms_admin") public class Admin { @Id @GeneratedValue(generator = "increment") @GenericGenerator(name = "increment", strategy = "increment") @Column private int id; @Column private String userName; @Column private String password; @Column private String role; @Column private int enable; @Column private int isDelete; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public int getEnable() { return enable; } public void setEnable(int enable) { this.enable = enable; } public int getIsDelete() { return isDelete; } public void setIsDelete(int isDelete) { this.isDelete = isDelete; } } 

AdminDao.java

package com.fxmms.www.dao; import com.fxmms.common.dao.BaseDao; import com.fxmms.www.domain.Admin; /** * Created by mark on 16/10/31. * @usage 操作管理員數據庫訪問接口 */ public interface AdminDao extends BaseDao<Admin> { } 

AdminDaoImpl.java

package com.fxmms.www.dao.hib; import com.fxmms.common.dao.hib.HibernateTemplateDao; import com.fxmms.www.dao.AdminDao; import com.fxmms.www.domain.Admin; /** * Created by mark on 16/11/2. * @usage 使用適配器模式,將common層中定義的公共訪問數據庫方法實現嫁接到Admin類的接口中。 */ public class AdminDaoImpl extends HibernateTemplateDao<Admin> implements AdminDao { @Override protected Class<?> getEntityClass() { // TODO Auto-generated method stub return Admin.class; } } 

可以看到,在具體類相關的數據庫操作實現類中,我們只需要實現HibernateTemplateDao<T>中抽象方法protected Class<?> getEntityClass();即可。
給我們的感覺就是這個方法的實現是畫龍點睛之筆。
回過頭去看,在HibernateTemplateDao類中所有與數據庫操作有關的方法:
例如:

 @Override @SuppressWarnings("unchecked") public T getByUniqueKey(String columnName, Object value) { return (T) getSession().createCriteria(getEntityClass()) .add(Restrictions.eq(columnName, value)).uniqueResult(); } 

getEntityClass()方法最終都會被具體的類所實現。這個設計真的是很巧妙。

5.webapp文件夾下分層詳解


webapp下有res文件夾,用於存儲靜態文件,WEB-INF文件夾下有view文件夾用於放置應用中jsp頁面。
文件組織結構如下圖所示:

 
webapp下靜態資源以及前端頁面

6.配置tomcat 運行環境


項目搭建已經完畢,接下來需要做的就是配置項目的運行環境了,這里我們采用tomcat來充當應用服務器。
6.1 去官網下載tomcat 8.0http://tomcat.apache.org/download-80.cgi
6.2 配置 tomcat 服務器:
點擊Edit Configurations

 
屏幕快照 2016-11-20 下午11.48.58.png

點擊 +,並選擇Tomcat Server中local選項
 
屏幕快照 2016-11-20 下午11.51.03.png

添加啟動任務名稱,默認為unnamed
 
屏幕快照 2016-11-21 上午9.33.39.png

配置Application Server
 
屏幕快照 2016-11-21 上午9.39.06.png

裝載開發版(exploded)應用war包,此步驟有兩種方式:
第一種方式:選擇Deploy at the server startup下方的 +,入下圖所示:

 

 
屏幕快照 2016-11-21 上午9.54.16.png

接下來在Select Artifacts Deploy 彈出框中 選擇 exploded 屬性的war包


 
屏幕快照 2016-11-21 上午9.54.31.png

接下來選擇apply-> ok ,最終的結果是:

 
屏幕快照 2016-11-21 上午10.05.46.png
 
屏幕快照 2016-11-21 上午10.12.55.png

最終點擊啟動按鈕啟動應用


 
屏幕快照 2016-11-21 上午10.15.46.png

最終的啟動效果如下所示

 
 
         
         
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM