Spring+mybatis+gradle 项目搭建实战-一步步搭建应用

本人博客:http://chen-shang.github.io
原文地址

saas 项目是一个给其他应用提供接口的项目,更偏重业务一点,主要是负责员工提交申请的信息的记录和状态的流转

使用到的工具

  1. 框架 -- 以 Spring 为主, Spring MVC 思想为辅
  2. 编程语言 -- 以 java 为主
  3. 项目构建工具 -- gradle
  4. 持久层框架 -- mybatis
  5. 版本控制工具 -- git
  6. 数据库 -- postgresql
  7. 脚本编程 -- shell
  8. IDE -- Intellij IDEA
  9. 容器 -- tomcat

搭建项目的前提是保证你的 jdk、gradle、git、postgresql 等都已经安装和配置完成,如下是我工具所对应的版本

chenshang@MrRobot-3:~$ java -version
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
chenshang@MrRobot-3:~$ git --version 
git version 2.8.1
chenshang@MrRobot-3:~$ postgres --version
postgres (PostgreSQL) 9.6.2
chenshang@MrRobot-3:~$ gradle -v
------------------------------------------------------------
Gradle 3.2.1
------------------------------------------------------------
Build time:   2016-11-22 15:19:54 UTC
Revision:     83b485b914fd4f335ad0e66af9d14aad458d2cc5
Groovy:       2.4.7
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_121 (Oracle Corporation 25.121-b13)
OS:           Mac OS X 10.12.4 x86_64

由于是一个以 spring 框架为基础的项目,我们需要先集成 spring ,然后以此为基础一点一点盖楼。

新建 Gradle Java Web 项目

首先搭建一个 gradle 的 java web项目,然后添加 spring 依赖

打开 idea 在首页选择 Create New Project



点击 Next



如上图选择 Gradle 然后在右侧的窗口中勾选 Java 和 Web。这代表我将用 Gradle 新建一个 Java Web 项目。

点击 Next,在下一页为自己的应用起一个响亮而且文雅的名字(主要是写 GroupId、ArtifactId、Version)

GroupId:组 id,可以理解为你所属的项目组或公司的名称
ArtifactId:项目 id,可以理解为你项目的名称,Artifact是手工艺品的意思,引申为作品,代表你做的项目是你的作品

点击 Next


这里上面三个复选框可以选择性的勾选,第一个是自动 import(具体不知道是做什么的),第二个是创建项目的缺省目录,勾选后就可以在新建的项目中看到你熟悉的项目目录的结构如下

chenshang@bogon:~/Learn/spring/saas$ tree -L 3 src
src
├── main
│   ├── java
│   ├── resources
│   └── webapp
│       └── index.jsp
└── test
    ├── java
    └── resources

7 directories, 1 file

点击 Next 到下面这个页面



这里有个 Project name 让你填写工程名称,这个一般和你的项目名称也就是前面你定义的ArtifactId是相同的。其实这个 Project name 默认就是ArtifactId的名字,不用你做任何修改,只需在配置 Project Location 也就是你工程所在的目录即可,如果项目目录不存在 IEDA 会给你新建这个目录,之后你的项目目录结构和内容都应该在该目录下完成。

点击 Finish

等待 IDEA 的 Gradle 插件加载并解析完成项目后我们的 Gradle Java Web 项目就建好了。

还记得我们开始勾选了 Java 和 Web 两个选项吧,我们在 gradle.setting 文件中可以看到项目自动为我们添加了两个 gradle 插件 java 和 war。如果开始不勾选的话,这个配置文件就需要我们自己手动填写了。


建项目的方式多种多样,这里只是使用 IEDA 工具纯界面操作建立了一个简单的项目,其实最简单最理想的方式就是用工具只用点击就可以配置好项目,这样能省去繁琐的手工配置节省很多时间。
如果在第四步的时候没有勾选自动新建目录,那么新建的目录就是一个裸露的项目

chenshang@MrRobot-3:~/learn/spring/saas/src$ tree -L 3
.
└── main
    └── webapp
        └── index.jsp

2 directories, 1 file

这里推荐一款 Gradle 插件 gradle_templet,这是一款生成项目标准目录结构和类的插件,支持多种语言
只需要在 build.gradle 中添加下面

apply from: 'http://www.tellurianring.com/projects/gradle-plugins/gradle-templates/1.3/apply.groovy'

自己去发现其中的乐趣吧!

集成 spring

其实就是引用 spring 的 jar 包的过程

很简单在dependencies{}中添加

compile 'org.springframework:spring-webmvc:4.3.7.RELEASE'

该项目就会自动引入 spring 的依赖。至于怎么选择需要的 jar 包,这个真的就需要你去各种谷歌各种查资料了,因为第三方工具这种东西,只有你知道你才会去用,就像我搭建项目的时候我还不知道有 springboot 这种东西一些样我只能按照我以前的经验来搭建项目, 当我知道有 springboot这个工具的时候我就会发现其实集成第三方框架是多么的容易。

推荐一个搜索 jar 包的网站
http://search.maven.org/
以上项目就继承了 spring + spring MVC 了,我们写一个传统的项目来验证一下

首先在 src/java 目录中新建包,按照约定我们一般是公司域名的反写,我们这里就随便起名为 com.finhub.saas 吧

在com.finhub.saas这个包下,新建 controller/RootCtrl.class 文件

package com.finhub.saas.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Created by chenshang on 2017/4/8.
 */
@Controller
public class RootCtrl {
    @ResponseBody
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String test() {
        return "Hello world";
    }
}

在 web.xml 中添加 spring 的配置

  1. 一个是 contextConfigLocation
  2. 一个是 dispatcherServlet
    这里直接贴出我的配置项,其实 spring 的配置组合还有很多
 <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/applicationContext.xml</param-value>
 </context-param>
 <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:spring/dispatcherServlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
 </servlet-mapping>

spring 的配置文件统一放在 resources 目录下的 spring 目录中,resource 这个资源文件中主要放置各种配置文件以及自定义属性等文件的集合
webapp 则主要放置于 web 项目相关的东西如 css、js、html 等

这里要新建两个文件一个叫 applicationContext.xml,从名字上也可以看出来,这个是应用上下文的配置文件,主要用来存储 spring用到的 bean 配置,如果有些配置需要从其他 xml 文件中引入,可以用 import 来实现

新建resources/applicationContext

<?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/>
    <context:component-scan base-package="com.finhub.saas.controller"/>
</beans>

新建resources/dispatcherServlet

<?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: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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--默认的注解映射支持:有了它,才能自动扫描各个包并注册到appplicationcontex的应用上下文中 -->
    <mvc:default-servlet-handler/>
    <mvc:resources location="/WEB-INF/fonts/" mapping="/fonts/**"/>
    <mvc:resources location="/WEB-INF/css/" mapping="/css/**"/>
    <mvc:resources location="/WEB-INF/img/" mapping="/img/**"/>
    <mvc:resources location="/WEB-INF/js/" mapping="/js/**"/>

    <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    </bean>
</beans>

启动项目
访问 http://localhost:8080/hello

集成mybtais

这下要与数据库继承了,根据你选择的数据库应用相应数据库的驱动 jar 包。这里以 postgrsq 为例子,我引入相关依赖

    //=================>database jar<=============
    compile 'org.mongodb:bson:3.4.2'
    compile 'com.alibaba:druid:1.0.23'
    compile 'org.mybatis:mybatis:3.4.2'
    compile 'org.mybatis:mybatis-spring:1.3.1'
    compile 'org.postgresql:postgresql:9.4.1212.jre7'
    compile 'redis.clients:jedis:2.9.0'
    compile 'org.springframework.data:spring-data-redis:1.8.0.RELEASE'
    compile 'org.springframework:spring-orm:4.3.6.RELEASE'
    //=================>json jar<=================
    compile 'com.alibaba:fastjson:1.2.24'
    compile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
    compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.7.3'
    //=================>others<===================
    compile 'javax.servlet:javax.servlet-api:3.1.0'
    compile 'jstl:jstl:1.2'
    compile 'joda-time:joda-time:2.9.7'
    compile 'org.apache.commons:commons-lang3:3.5'

新建 resources/jdbc/jdbc.properties

jdbc_driver=org.postgresql.Driver
jdbc_url=jdbc:postgresql://localhost:5432/saas
jdbc_username=postgres
jdbc_password=

新建 resources/spring-mybatis/spring-mybatis.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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <value>classpath:jdbc/jdbc.properties</value>
        </property>
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
    </bean>
    <!-- ========================================针对spring-myBatis的配置项============================== -->
    <!-- 配置数据源,使用的是alibaba的Druid(德鲁伊)数据源 -->
    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="${jdbc_driver}"/>
        <property name="url" value="${jdbc_url}"/>
        <property name="username" value="${jdbc_username}"/>
        <property name="password" value="${jdbc_password}"/>
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="0"/>
        <!-- 连接池最大使用连接数量 -->
        <property name="maxActive" value="20"/>
        <!-- 连接池最大空闲 -->
        <!--<property name="maxIdle" value="20"/>-->
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="0"/>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="60000"/>
        <!--
        <property name="poolPreparedStatements" value="true" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="33" />
        -->
        <property name="testOnBorrow" value="false"/>
        <property name="testOnReturn" value="false"/>
        <property name="testWhileIdle" value="true"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="25200000"/>
        <!-- 打开removeAbandoned功能 -->
        <property name="removeAbandoned" value="true"/>
        <!-- 1800秒,也就是30分钟 -->
        <property name="removeAbandonedTimeout" value="1800"/>
        <!-- 关闭abanded连接时输出错误日志 -->
        <property name="logAbandoned" value="true"/>
        <!-- 监控数据库 -->
        <!-- <property name="filters" value="stat" /> -->
        <property name="filters" value="mergeStat"/>
    </bean>
    <!-- ========================================针对myBatis的配置项============================== -->
    <!-- ==============================配置sqlSessionFactory============================== -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 实例化sqlSessionFactory时需要使用上述配置好的数据源以及SQL映射文件 -->
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath:mapper/*Mapper.xml"/>
    </bean>
    <!-- ==============================配置扫描器============================== -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
        <property name="basePackage" value="com.finhub.saas.dao"/>
    </bean>
    <!-- ==============================配置Spring的事务管理器============================== -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- ==============================拦截器方式配置事物============================== -->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED"/>
            <tx:method name="append*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="modify*" propagation="REQUIRED"/>
            <tx:method name="edit*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="remove*" propagation="REQUIRED"/>
            <tx:method name="repair" propagation="REQUIRED"/>
            <tx:method name="delAndRepair" propagation="REQUIRED"/>

            <tx:method name="get*" propagation="SUPPORTS"/>
            <tx:method name="find*" propagation="SUPPORTS"/>
            <tx:method name="load*" propagation="SUPPORTS"/>
            <tx:method name="search*" propagation="SUPPORTS"/>
            <tx:method name="datagrid*" propagation="SUPPORTS"/>

            <tx:method name="*" propagation="SUPPORTS"/>
        </tx:attributes>
    </tx:advice>

</beans>

这样 mybatis 和数据库也就集成好了
这样就可以愉快的开始写代码了

集成logback

上面已经添加好了依赖

新建 resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="LOG_PATH" value="/logs/saas"/>
    <property name="LOG_FILE" value="saas"/>

    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[%d{yyyy-MM-dd'T'HH:mm:ss.SSS}] [%level] %logger:%line [%X{RID}] - %message%n%xException%n
            </pattern>
        </encoder>
    </appender>

    <!-- 文件输出 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${LOG_FILE}.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${LOG_FILE}-%d{yyyy-MM-dd}.log.zip</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>[%d{yyyy-MM-dd'T'HH:mm:ss.SSS}] [%level] %logger:%line [%X{RID}] - %message%n%xException%n
            </pattern>
        </encoder>
    </appender>

    <!-- 文件输出_error -->
    <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${LOG_FILE}-error.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${LOG_FILE}-error-%d{yyyy-MM-dd}.log.zip</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>[%d{yyyy-MM-dd'T'HH:mm:ss.SSS}] [%level] %logger:%line [%X{RID}] - %message%n%xException%n
            </pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="FILE"/>
        <appender-ref ref="FILE_ERROR"/>
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

MDC

统一的异常处理体系

over 可以愉快的玩耍了

彩蛋--敬请期待

  1. 后期会更新成多数据源的配置
  2. 还会讲解这个传统项目转战 springboot 项目
  3. 项目的版本控制策略
  4. 项目的部署控制策略

推荐阅读更多精彩内容