使用Intellij Idea+Gradle 搭建Java 本地开发环境
vr277809
8年前
<h2><strong>Java 本地开发环境搭建</strong></h2> <p>项目搭建采用技术栈为:Spring+Spring MVC+Hibernate+Jsp+Gradle+tomcat+mysql5.6</p> <p>搭建环境文档目录结构说明:</p> <ol> <li>使用Intellj Idea 搭建项目过程详解</li> <li>项目各配置文件讲解及部署</li> <li>各层包功能讲解&项目搭建完毕最终效果演示图</li> <li>项目中重要代码讲解<br> 5.配置tomcat 运行环境<br> 6.webapp文件夹下分层详解</li> </ol> <h3><strong>1. 使用Intellj Idea 搭建项目过程详解</strong></h3> <p><strong>1.1 打开Intellj Idea</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/96c1e3c5847ae62b4aa86446e8cff4ce.png"></p> <p><strong>1.2 操作 Intellj Idea 工具栏 新建项目</strong></p> <p><img src="https://simg.open-open.com/show/18b6abae5de02bf04df3c82b71fb41f4.png"></p> <p style="text-align:center"> </p> <p><img src="https://simg.open-open.com/show/b09e9d972ee04677e5f4d22735dfd653.png"></p> <p style="text-align:center"> </p> <p><img src="https://simg.open-open.com/show/7b6fe26d05fbc68d5302553927d49fd5.png"></p> <p style="text-align:center"> </p> <p><img src="https://simg.open-open.com/show/487dff81ceee0a37319e97163a3839eb.png"></p> <p style="text-align:center"> </p> <p><img src="https://simg.open-open.com/show/c852326ed3d888e29692cdd6cf761c29.png"></p> <p style="text-align:center"> </p> <p style="text-align:center"><img src="https://simg.open-open.com/show/35eadd696534adda85cf2aa43641446c.png"></p> <p style="text-align:center"> </p> <p><img src="https://simg.open-open.com/show/8fb408fb48c819d6e01e1a0ff5b8d845.png"></p> <p>需要说明的是,最初创建的项目视图是不完整的,包括webapp文件夹下没有web.xml,以及src包下缺少Java文件夹(放置java源代码文件),Resources文件夹(放置项目配置文件)。</p> <p>我们继续做以下操作,使得项目的结构符合web 应用项目的层级标准。</p> <p><img src="https://simg.open-open.com/show/b9d3d9b6cca0fb6508b56cbefdbce27e.png"></p> <p>出现如下视图:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/cb7fdbe41aa80ecebd6c25c231f27e3c.png"></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/018ce0488018456f89abd08b43365429.png"></p> <p>接下来:单击main文件夹按照如下操作:</p> <p><img src="https://simg.open-open.com/show/9832c6b495765e2fbe459cd6fc63f372.png"></p> <p style="text-align:center">屏幕快照 2016-11-20 下午4.44.33.png</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/75fc2bfb6857235475f8599a61526435.png"></p> <p>点击ok,再按照上图操作操作一遍,输入文件名为 <strong>resources</strong></p> <p>最终的结构图如下图所示:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/dc823722075f6b5fa0c53dbedb30836e.png"></p> <h3><strong>2. 项目各配置文件讲解及部署</strong></h3> <p>完成了项目的初始化结构创建,接下来我们需要来创建配置文件。</p> <p>首先是resources文件夹下的配置文件</p> <p><strong>2.1resources下资源文件截图:(最终配置的结果)</strong></p> <p style="text-align:center"><img src="https://simg.open-open.com/show/5dfa49957f151c1013ec4f0f116be270.png"></p> <p><strong>2.2 data-access-applicationContext.xml</strong></p> <p>主要管理数据库访问组件</p> <pre> <code class="language-java"><?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></code></pre> <p><strong>2.3 service-applicationContext.xml</strong></p> <p>主要管理业务逻辑组件,包括对数据库访问的事务控制,以及定时任务。</p> <pre> <code class="language-java"><?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></code></pre> <p><strong>2.4default-servlet.xml</strong></p> <p>设置springmvc-applicationContext.xml,前端控制器将请求转发到相应的controller层中的处理方法上。</p> <pre> <code class="language-java"><?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></code></pre> <p><strong>2.5 spring-security.xml</strong></p> <p>设置spring-security 权限控制配置文件,项目中权限的控制统一在此配置文件中配置,包括从数据库中获取用户的相关信息,以及配置相应pattern的请求过滤规则。</p> <pre> <code class="language-java"><?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></code></pre> <p><strong>2.6 db.properties</strong></p> <p>数据库访问配置文件</p> <pre> <code class="language-java">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</code></pre> <p><strong>2.7 log4j.properties</strong></p> <p>配置项目日志文件,日志输出模式为Console</p> <pre> <code class="language-java">########################################################################### # 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 # Console output log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{mm:ss,SSS} %p [%l] - <%m>%n</code></pre> <p><strong>2.8 web.xml</strong></p> <pre> <code class="language-java"><?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></code></pre> <p><strong>2.9 build.gradle</strong></p> <p>项目构建脚本</p> <pre> <code class="language-java">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' }</code></pre> <h3><strong>3. 各层包功能讲解&项目搭建完毕最终效果演示图</strong></h3> <p><strong>3.1 项目中各层包功能讲解</strong></p> <p>项目中Java源代码层级结构如下图所示:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/28f41672259933d0a93ab5331ccdf9f3.png"></p> <p>对于www包中的各分层,我们对照上图重点说明:</p> <p>controller:用于路由各种http访问,其中可以实现对前台页面参数的对象化绑定,这个功能的实现是依赖于spring mvc中的参数绑定功能,以及返回向前端页面返回数据。也可以实现基于Restful 风格API的编写。</p> <p>dao:用于实现对数据库的操作,包中的代码继承并实现自common中的dao 层代码,采用的是类的适配器模式实现的,这里的代码值得细细品味,可以说是整个项目的灵魂所在之处。</p> <p>domain:项目的实体类都存在于这个包中,其中的类与数据库表相对应。</p> <p>dto:实现了序列化的数据传输层对象,用于接收前台参数,并封装成dto 对象传输至后台,也负责从数据库中查询数据的封装。</p> <p>qo:模糊查询对象所在的包,用于封装QBC动态查询参数。</p> <p>rowmapper:用于对应jdbcTemplate查询数据库返回对象的数据集,并将数据集依照此对象进行封装。</p> <p>schedulejob:定时任务类所在的包,其中类要加上@Service注解,因为定时任务注解配置在service-applicationContext.xml中,包扫描组件的规则是只扫描有@Service注解的组件类</p> <p>service:业务逻辑层,主要完成业务逻辑的书写,其中调用了dao实现类中的方法,并且每个有关于数据库操作的方法上都加上了@Transaction注解,@Transaction是Spring Framework对AOP 的另一种区别于拦截器的自定义注解实现。</p> <h3><strong>4.项目中重要代码讲解</strong></h3> <p>主要讲解一下Dao层中代码对适配器设计模式的应用:</p> <p><strong>4.1 首先看下commom层中 BaseDao.java</strong></p> <pre> <code class="language-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); }</code></pre> <p>其中定义了一些对数据库的抽象公共操作方法,代码中有注释,可以对照理解。</p> <p><strong>4.2 看下HibernateTemplateDao.java对BaseDao.java的抽象实现</strong></p> <pre> <code class="language-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; } }</code></pre> <p>这个方法是极为重要的 <strong>protected abstract Class<?> getEntityClass();</strong></p> <p>后续介绍,现在暂时有个印象。</p> <p>在www中的dao层有与各具体类(数据表)相对应的数据库操作实现:</p> <p><img src="https://simg.open-open.com/show/b748f3f298382e5e6a081877be2fe4f3.png"></p> <p>上图声明了三个具体类对应的接口声明:AdminDao、MacDao、TaskDao。</p> <p>对应三个接口有三个具体的实现类:AdminDaoImpl、MacDaoImpl、TaskDaoImpl。</p> <p>我们以与Admin类相关的dao层操作为例:</p> <p><strong>Admin.java</strong></p> <pre> <code class="language-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; } }</code></pre> <p>AdminDao.java</p> <pre> <code class="language-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> { }</code></pre> <p><strong>AdminDaoImpl.java</strong></p> <pre> <code class="language-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; } }</code></pre> <p>可以看到,在具体类相关的数据库操作实现类中,我们只需要实现HibernateTemplateDao<T>中抽象方法protected Class<?> getEntityClass();即可。</p> <p>给我们的感觉就是这个方法的实现是画龙点睛之笔。</p> <p>回过头去看,在HibernateTemplateDao类中所有与数据库操作有关的方法:</p> <p>例如:</p> <pre> <code class="language-java">@Override @SuppressWarnings("unchecked") public T getByUniqueKey(String columnName, Object value) { return (T) getSession().createCriteria(getEntityClass()) .add(Restrictions.eq(columnName, value)).uniqueResult(); }</code></pre> <p>getEntityClass()方法最终都会被具体的类所实现。这个设计真的是很巧妙。</p> <h3><strong>5.配置tomcat 运行环境</strong></h3> <p>项目搭建已经完毕,接下来需要做的就是配置项目的运行环境了,这里我们采用tomcat来充当应用服务器。</p> <p><strong>5.1 去官网下载</strong> <strong>tomcat 8.0</strong> :</p> <p><strong>5.2 配置 tomcat 服务器:</strong></p> <p>点击Edit Configurations</p> <p><img src="https://simg.open-open.com/show/b748f3f298382e5e6a081877be2fe4f3.png"></p> <p>点击 <strong>+</strong> ,并选择Tomcat Server中local选项</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/932d2e28080e8d69fd7cce04650bc732.png"></p> <p>添加启动任务名称,默认为unnamed</p> <p><img src="https://simg.open-open.com/show/44547e7853e5a740224dc0497dbc1722.png"></p> <p>配置Application Server</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/415ee1ed9a31204db31bcab3ab19d5d1.png"></p> <p>装载开发版(exploded)应用war包,此步骤有两种方式:</p> <p>第一种方式:选择Deploy at the server startup下方的 <strong>+</strong> ,入下图所示:</p> <p><img src="https://simg.open-open.com/show/f53c9cefd73804b4a66d0767747938ae.png"></p> <p>接下来在Select Artifacts Deploy 弹出框中 选择 exploded 属性的war包</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/1aed6254ac035eb65d6743a4e12f3e66.png"></p> <p>接下来选择apply-> ok ,最终的结果是:</p> <p><img src="https://simg.open-open.com/show/6544797e04b2f76e1568072bb7fda80f.png"></p> <p><img src="https://simg.open-open.com/show/f09f363639c805be2bad668942edf18f.png"></p> <p>最终点击启动按钮启动应用</p> <p><img src="https://simg.open-open.com/show/f2bd3a40f81360f9d31994ac076c1b0e.png"></p> <p>最终的启动效果如下所示</p> <p><img src="https://simg.open-open.com/show/bb268b94e33b165d81f0e46869e2d518.png"></p> <h3><strong>6.webapp文件夹下分层详解</strong></h3> <p>webapp下有res文件夹,用于存储静态文件,WEB-INF文件夹下有view文件夹表示</p> <p>关于项目中应用到的JNI技术,会在后面讲解,主要侧重点是在代码层面解决JNI link library的问题。</p> <p> </p> <p>来自:http://www.jianshu.com/p/25039d901ac2</p> <p> </p>