使用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>