IDEA + maven + spring boot + scala + oracle + mybatis + druid scala java混合开发环境搭建
demo地址
clyoudu/spring-boot-scala-demo
为什么要用scala
- 为什么要用
scala
?是Java
不好用还是不够难?可能仅仅是想装逼? - 其实是项目中要用
scala
写spark
程序,所以有scala
和java
混合开发的需求,干脆研究一下纯scala
能不能搭建这样的开发环境。 - 最后放弃了完全使用
scala
的方式,因为scala
的环境下无法完美使用mybatis + druid
,当然也可以实现,但是映射、配置、事务等代码不是很优雅,mybatis-scala
在maven
仓库中只更新到scala 2.11
,github
上也不是很活跃,应该是需求量不大,说不定有很多坑,既然是java scala
混合使用,不妨用java
来实现ORM
相关代码。 scala
一般使用java Persistence API
来实现数据库操作的。mybatis-scala
相关连接:github mybatis/scala;mvnrepository;mybatis-scala-core
,这里有很多示例代码,看了基本能用scala
实现ORM
,包括事务等。
环境
IDE
:IntelliJ IDEA 2017
JDK
:1.8
OS
:Win10
BT
:Maven
scala
:2.12.4
spring boot
:2.0.1.RELEASE
maven
:3
oracle
:11.2.0.4
初始化spring boot项目
可以直接从IDEA
创建,也可以从https://start.spring.io/创建一个基础的项目,这里使用IDEA
直接创建。
首先确保有Spring boot
插件:
然后创建一个简单的spring boot
项目:
这里根据自己的需求选择,也可以不选后面自己写。
如果已有maven
环境,可以删除mvn
相关的文件和文件夹。
添加依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RC1</spring-cloud.version>
<scala.version>2.12.4</scala.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- scala -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<!-- database -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.3</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
添加插件
<build>
<plugins>
<!-- spring boot -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- scala compiler -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.3.2</version>
<executions>
<execution>
<id>compile-scala</id>
<phase>compile</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile-scala</id>
<phase>test-compile</phase>
<goals>
<goal>add-source</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<recompileMode>incremental</recompileMode>
<scalaVersion>${scala.version}</scalaVersion>
<args>
<arg>-deprecation</arg>
</args>
<jvmArgs>
<jvmArg>-Xms64m</jvmArg>
<jvmArg>-Xmx1024m</jvmArg>
</jvmArgs>
</configuration>
</plugin>
<!-- mybatis generator -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/mybatis-generator-config.xml
</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.42</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
application.properties
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@192.168.0.193:1521:single
spring.datasource.username=scott
spring.datasource.password=tiger
#连接池配置
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
#连接等待超时时间
spring.datasource.maxWait=60000
#配置隔多久进行一次检测(检测可以关闭的空闲连接)
spring.datasource.timeBetweenEvictionRunsMillis=60000
#配置连接在池中的最小生存时间
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
创建两张表用来测试
CREATE TABLE "SYSTEM"."USER" (
"ID" NVARCHAR2(36) NOT NULL ENABLE,
"USERNAME" NVARCHAR2(255) NOT NULL ENABLE,
"PASSWORD" NVARCHAR2(255) NOT NULL ENABLE,
"REGISTER_TIME" DATE NOT NULL ENABLE,
PRIMARY KEY ("ID")
) NOCOMPRESS;
CREATE TABLE "SYSTEM"."USER_OPERATION_HISTORY" (
"ID" NVARCHAR2(36) NOT NULL ENABLE,
"USER_ID" NVARCHAR2(36) NOT NULL ENABLE,
"USERNAME" NVARCHAR2(255) NOT NULL ENABLE,
"OPERATION_TYPE" NVARCHAR2(255) NOT NULL ENABLE,
"OPERATE_TIME" DATE NOT NULL ENABLE,
PRIMARY KEY ("ID")
) NOCOMPRESS;
配置/resources/generator/mybatis-generator-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
<!-- 指定数据连接驱动jar地址 -->
<classPathEntry location="C:/Users/vabsh/.m2/repository/com/oracle/ojdbc6/11.2.0.4/ojdbc6-11.2.0.4.jar" />
<!-- 一个数据库一个context -->
<context id="test">
<!-- 注释 -->
<commentGenerator >
<property name="suppressAllComments" value="true"/><!-- 是否取消注释 -->
<property name="suppressDate" value="false" /> <!-- 是否生成注释代时间戳-->
</commentGenerator>
<!-- jdbc连接 -->
<jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver"
connectionURL="jdbc:oracle:thin:@192.168.0.193:1521:single"
userId="system"
password="single" />
<!-- 类型转换 -->
<javaTypeResolver>
<!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成实体类地址 -->
<javaModelGenerator targetPackage="github.chenlei.springbootscalademo.entity"
targetProject="C:\github\spring-boot-scala-demo\src\main\java" >
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<property name="enableSubPackages" value="false"/>
<!-- 是否针对string类型的字段在set的时候进行trim调用 -->
<!-- <property name="trimStrings" value="true"/> -->
</javaModelGenerator>
<!-- 生成mapxml文件 -->
<sqlMapGenerator targetPackage="mapper"
targetProject="C:\github\spring-boot-scala-demo\src\main\resources" >
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- 生成mapxml对应client,也就是接口dao -->
<javaClientGenerator targetPackage="github.chenlei.springbootscalademo.dao"
targetProject="C:\github\spring-boot-scala-demo\src\main\java" type="XMLMAPPER" >
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 配置表信息 -->
<table schema="SYSTEM"
tableName="USER_OPERATION_HISTORY"
enableCountByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
enableUpdateByExample="false"/>
<table schema="SYSTEM"
tableName="USER"
enableCountByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
enableUpdateByExample="false"/>
</context>
</generatorConfiguration>
执行mvn mybatis-generator:generate
或点击右侧工具栏Maven Projects > spring-boot-scala-demo > Plugins > mybatis-generator > mybatis-generator:generate
,mapper mapperxml entity
会自动创建在对应的包里。
后续的一些小改动:
因为USER
是oracle
保留字,需要在mapperxml
将USER
替换为"USER"
。
在XxxMapper
类上添加@Mapper
注解。
DataSource和Mybatis配置
和spring boot
配置数据源类似,只不过用的scala
实现:
package github.chenlei.springbootscalademo.config
import java.sql.SQLException
import javax.sql.DataSource
import com.alibaba.druid.pool.DruidDataSource
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
import org.springframework.context.annotation.{Bean, Configuration, Primary}
/**
* Create by IntelliJ IDEA
*
* @Author chenlei
* @DateTime 2018/5/7 10:59
* @Description DruidDataSource
*/
@Configuration
@Primary
class DruidDataSourceConfig extends DataSourceProperties {
private val LOGGER = LoggerFactory.getLogger(classOf[DruidDataSourceConfig])
@Value("${spring.datasource.url}")
private val dbUrl : String = null
@Value("${spring.datasource.username}")
private val username : String = null
@Value("${spring.datasource.password}")
private val password : String = null
@Value("${spring.datasource.driverClassName}")
private val driverClassName : String = null
@Value("${spring.datasource.initialSize}")
private val initialSize : Integer = 0
@Value("${spring.datasource.minIdle}")
private val minIdle : Integer = 0
@Value("${spring.datasource.maxActive}")
private val maxActive : Integer = 0
@Value("${spring.datasource.maxWait}")
private val maxWait : Long = 0
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private val timeBetweenEvictionRunsMillis : Long = 0
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private val minEvictableIdleTimeMillis = 0
@Value("${spring.datasource.validationQuery}")
private val validationQuery : String = null
@Value("${spring.datasource.testWhileIdle}")
private val testWhileIdle : Boolean = false
@Value("${spring.datasource.testOnBorrow}")
private val testOnBorrow : Boolean = false
@Value("${spring.datasource.testOnReturn}")
private val testOnReturn : Boolean = false
@Value("${spring.datasource.poolPreparedStatements}")
private val poolPreparedStatements : Boolean = false
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
private val maxPoolPreparedStatementPerConnectionSize : Integer = 0
@Value("${spring.datasource.filters}")
private val filters : String = null
@Value("{spring.datasource.connectionProperties}")
private val connectionProperties : String = null
@Bean //声明其为Bean实例
def dataSource: DataSource = {
val datasource: DruidDataSource = new DruidDataSource
datasource.setUrl(this.dbUrl)
datasource.setUsername(username)
datasource.setPassword(password)
datasource.setDriverClassName(driverClassName)
//configuration
datasource.setInitialSize(initialSize)
datasource.setMinIdle(minIdle)
datasource.setMaxActive(maxActive)
datasource.setMaxWait(maxWait)
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis)
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis)
datasource.setValidationQuery(validationQuery)
datasource.setTestWhileIdle(testWhileIdle)
datasource.setTestOnBorrow(testOnBorrow)
datasource.setTestOnReturn(testOnReturn)
datasource.setPoolPreparedStatements(poolPreparedStatements)
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize)
try
datasource.setFilters(filters)
catch {
case e: SQLException =>
LOGGER.error("druid configuration initialization filter", e)
}
datasource.setConnectionProperties(connectionProperties)
datasource
}
}
package github.chenlei.springbootscalademo.config
import javax.servlet.{Filter, Servlet}
import com.alibaba.druid.support.http.{StatViewServlet, WebStatFilter}
import org.springframework.boot.web.servlet.{FilterRegistrationBean, ServletRegistrationBean}
import org.springframework.context.annotation.{Bean, Configuration}
/**
* Create by IntelliJ IDEA
*
* @Author chenlei
* @DateTime 2018/5/7 11:07
* @Description DruidMonitorConfig
*/
@Configuration
class DruidMonitorConfig {
/**
* 注册ServletRegistrationBean
*
* @return
*/
@Bean
def registrationBean: ServletRegistrationBean[StatViewServlet] = {
val bean : ServletRegistrationBean[StatViewServlet] = new ServletRegistrationBean(new StatViewServlet, "/druid/*")
/** 初始化参数配置,initParams **/
//白名单
bean.addInitParameter("allow", "127.0.0.1") //多个ip逗号隔开
//IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
//bean.addInitParameter("deny", "192.168.1.73");
//登录查看信息的账号密码.
bean.addInitParameter("loginUsername", "admin")
bean.addInitParameter("loginPassword", "123456")
//是否能够重置数据.
bean.addInitParameter("resetEnable", "false")
bean
}
/**
* 注册FilterRegistrationBean
*
* @return
*/
@Bean
def druidStatFilter: FilterRegistrationBean[_ <: Filter] = {
val bean = new FilterRegistrationBean(new WebStatFilter)
//添加过滤规则.
bean.addUrlPatterns("/*")
//添加不需要忽略的格式信息.
bean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*")
bean
}
}
package github.chenlei.springbootscalademo.config
import java.util.Properties
import javax.sql.DataSource
import com.github.pagehelper.PageHelper
import org.apache.ibatis.plugin.Interceptor
import org.apache.ibatis.session.SqlSessionFactory
import org.mybatis.spring.{SqlSessionFactoryBean, SqlSessionTemplate}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.{Bean, Configuration}
import org.springframework.core.io.support.PathMatchingResourcePatternResolver
import org.springframework.jdbc.datasource.DataSourceTransactionManager
import org.springframework.transaction.annotation.TransactionManagementConfigurer
/**
* Create by IntelliJ IDEA
*
* @Author chenlei
* @DateTime 2018/5/7 11:14
* @Description MybatisConfig
*/
@Configuration
class MybatisConfig extends TransactionManagementConfigurer{
@Autowired
private val dataSource : DataSource = null
@Bean(name = Array("sqlSessionFactory"))
def sqlSessionFactoryBean: SqlSessionFactory = {
val bean = new SqlSessionFactoryBean
bean.setDataSource(dataSource)
bean.setTypeAliasesPackage("github.chenlei.springbootscalademo.entity")
//分页插件,插件无非是设置mybatis的拦截器
val pageHelper = new PageHelper
val properties = new Properties
properties.setProperty("offsetAsPageNum", "true")
properties.setProperty("rowBoundsWithCount", "true")
properties.setProperty("reasonable", "true")
pageHelper.setProperties(properties)
//添加插件
bean.setPlugins(Array[Interceptor](pageHelper))
//添加XML目录
val resolver = new PathMatchingResourcePatternResolver
try { //设置xml扫描路径
bean.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"))
bean.getObject
} catch {
case e: Exception =>
throw new RuntimeException("sqlSessionFactory init fail", e)
}
}
@Bean(name = Array("sqlSessionTemplate"))
def sqlSessionTemplate(sqlSessionFactory: SqlSessionFactory) = new SqlSessionTemplate(sqlSessionFactory)
@Bean(name = Array("transactionManager"))
override def annotationDrivenTransactionManager() = new DataSourceTransactionManager(dataSource)
}
Service
很多方法可以在一个BaseService
里面定义和实现,因为scala
可以重写field
,所以结合泛型和字段重写能轻松实现模板方法,减少很多代码量,具体参考:github.chenlei.springbootscalademo.service
Controller
和spring boot
实现类似,依然改成scala
实现,具体参考:github.chenlei.springbootscalademo.controller
启动并测试
使用postman
访问创建用户接口:http://localhost:8080/user/create
访问druid monitor
:http://localhost:8080/druid
,admin/123456