著名IDE厂商JetBrains开发的基于JVM的静态类型编程语言,声称100% interoperable with Java。Kotlin是由工程师设计的,各类细节设计很是切合工程师的须要。语法近似Java和Scala,且已活跃在Android开发领域,被誉为Android平台的Swift。html
Kotlin能与Java混合使用,而且直接复用Java的生态系统(库、框架、工具)。一个已有的Java项目,只需引用Kotlin的Maven/Gradle插件,以及引用Kotlin标准库的依赖,就能够逐渐掺入Kotlin代码。你彻底能够当它是a better Java。java
Kotlin的学习曲线极其平缓,学习量至关于一个框架。有经验的程序员阅读了文档就能马上用起来了。不信你看:mysql
举几个例子来讲明Kotlin的优势吧,上代码:react
//句尾不用写分号 // 自动推导变量类型,无需声明 val a = "Hello" // 简单的println println(a.length() == 5) // 不用写new, 直接调构造函数 val b = String("Hello") // 字符串插值 "$a $b" == "Hello Hello" // if-else是表达式, 真方便! // ==至关于equals, 不再怕忘写equals了! val oneOrTwo = if (a == "Hello") 1 else 2 // ===至关于Java的== (a === b) == false // Lambda用{}包起来,如有惟一参数,参数名默认为it // 集合的函数式操做, 无需Java 8繁琐的stream.collect(Collectors.toList()) listOf(-1, 0, 1).map{it + 1}.filter{it > 0} == listOf(1, 2) // ?. (null-safe调用) // ?: (用默认值给null兜底) val numStr = getNumberOrNull()?.toString() ?: "" // 自动关闭的资源 FileInputStream("MyFile").use { stream -> // 可指定参数名为stream, 取代默认的it val firstByte = stream.read() } // 能够更简单,一行 val fileContent = File("MyFile").readText() // lazy, 延迟初始化 class CPU { val cpuCores by lazy { Runtime.getRuntime().availableProcessors() } }
Kotlin为厌烦Java而疑虑Scala的人提供了避风港,为喜欢Groovy而想要静态类型的人提供了避风港。啊!生活。ios
Spring Boot是流行的Web快速开发框架,使基于Spring的开发更便捷。
咱们已经知道Spring很好用,而Spring Boot的设计目标是:git
Kotlin能轻松集成Spring Boot,用Java怎么写,用Kotlin基本上也怎么写。程序员
Spring能在线生成项目,免去建立项目的烦恼,请猛击连接http://start.spring.io/ 。github
buildscript { ext { springBootVersion = '1.3.5.RELEASE' kotlinVersion = '1.0.4' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") } } apply plugin: 'kotlin' apply plugin: 'spring-boot' jar { baseName = 'myapp' version = '0.1-SNAPSHOT' } sourceCompatibility = 1.8 targetCompatibility = 1.8 // class文件保留参数名称 compileJava.options.compilerArgs.add '-parameters' compileTestJava.options.compilerArgs.add '-parameters' springBoot { mainClass = 'myapp.ApplicationKt' } dependencies { compile 'org.springframework.boot:spring-boot-starter-aop' compile 'org.springframework.boot:spring-boot-starter-web' compile "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}" }
@SpringBootApplication open class Application { @Bean open fun json(): MappingJackson2JsonView { return MappingJackson2JsonView(ObjectMapper()) } } fun main(args: Array<String>) { SpringApplication.run(Application::class.java, *args) }
Kotlin的函数可定义在类外面,而特殊的main函数要么放在外面,要么放在伴生对象(companion object)里面。这里就放在外面吧!web
你会发现class和fun前面有open修饰符,它的意思是非final,Kotlin默认一切都是final的,若是不想要final救要加上open。因为Spring有时要建立代理,要求类和方法不能为final,所以咱们每一处都写上open,以避免忘记。spring
这里只有一个json()方法,用来在Spring中初始化Jackson,这样咱们就能使用JSON了。
@RestController @RequestMapping("/api/users") open class UserApi { @RequestMapping("/{id}", method = arrayOf(RequestMethod.GET)) open fun get(@PathVariable id: Long) = "User(id=$id, name=admin, password=123)" }
好简单啊!如今,在IDE中运行Application.kt文件,就开始运行了!用浏览器打开http://localhost:8080/api/users/1
Spring Boot使用JPA很是简单(照着官网的getting started学吧),但我要介绍另外一种ORM框架——Ebean,它模仿了Rails的Active Record,支持经常使用的JPA注解。值得一提的是,Ebean的做者也喜欢Kotlin。
须要一个配置文件src/main/resources/ebean.properties :
# 是否生成建表SQL ebean.db.ddl.generate=true # 是否执行建表SQL ebean.db.ddl.run=false datasource.db.username=DB用户名 datasource.db.password=DB密码 datasource.db.databaseUrl=jdbc:mysql://localhost:3306/你的database名称 datasource.db.databaseDriver=com.mysql.jdbc.Driver
咱们对ebean.db.ddl.run(是否执行建表SQL)选择了false。由于Ebean会生成建表SQL,咱们能够手动执行,避免每次都从新建表,把数据丢弃了。编写实体类后再运行,SQL会生成在项目目录下,手动执行一下吧!(亦可在首次启动前把ebean.db.ddl.run改为true)
而后在Spring中初始化Ebean吧:
// 把这个方法添加到Application类 @Bean(autowire = Autowire.BY_TYPE) open fun getEbeanServer(): EbeanServer { val config = ServerConfig() config.name = "db" config.loadFromProperties() config.isDefaultServer = true return EbeanServerFactory.create(config) }
而后要修改main方法,在Spring以前先执行Ebean的agent,改写实体类的字节码:
fun main(args: Array<String>) { val packageName = "com.iostate.**" // 改为你本身的包名,实体类要放在这个包里面 if (!AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent", "debug=1;packages=$packageName")) { System.err.println( "avaje-ebeanorm-agent not found in classpath - not dynamically loaded") } SpringApplication.run(Application::class.java, *args) }
Ebean须要执行agent来改写字节码(instrumenation),而Hibernate则选择了给实体对象建立动态代理(dynamic proxy),都是为了能对实体进行AOP操做。
instrumenation使用复杂,调试简单;dynamic proxy使用简单,调试复杂。各有千秋,我更认同改写字节码。
import javax.persistence.* import com.avaje.ebean.Model import com.avaje.ebean.annotation.WhenCreated import com.avaje.ebean.annotation.WhenModified import java.sql.Timestamp import com.avaje.ebean.annotation.SoftDelete import com.fasterxml.jackson.annotation.JsonIgnore @MappedSuperclass abstract class BaseModel : Model() { @Id @GeneratedValue var id: Long = 0 @Version var version: Long = 0 @WhenCreated var whenCreated: Timestamp? = null @WhenModified var whenModified: Timestamp? = null } @Entity class User ( var name: String = "", @JsonIgnore var password: String = "" @SoftDelete var deleted: Boolean = false ) : BaseModel() { companion object find : Find<Long, User>() }
第一个类是全部实体模型的基类,提供一些通用字段。id是自增主键,version是乐观锁的标志,whenCreated是建立时间,whenModified是修改时间。有的变量类型以问号结尾,这个跟Swift语言是同样的,表示可为null(默认是非null的)。
第二类是User,行数不多,没有繁琐的getter/setter。@JsonIgnore的做用是防止敏感字段被泄露到JSON中,@SoftDelete的做用是软删除(数据不可见,但没有真的删除)。companion object find : Find<Long, User>()
提供了一组快捷查询方法,如byId(id)
all()
。
如今把UserApi修改以下:
@RestController @RequestMapping("/api/users") open class UserApi { @RequestMapping("/{id}", method = arrayOf(RequestMethod.GET)) open fun get(@PathVariable id: Long) = User.byId(id) @RequestMapping("/new", method = arrayOf(RequestMethod.POST)) open fun create(@RequestParam name: String, @RequestParam password: String): User { return User(name, password).apply { save() } } }
get方法真正向数据库作查询了!增长了create方法来建立用户!若是想用浏览器快速测试,把RequestMethod.POST改为GET,输入连接http://localhost:8080/api/users/new?name=admin&password=123 试试!
Spring Boot能把程序打包成jar直接运行,这是很方便群众的!可是JSP和Ebean在jar模式都没法工做。
那么在生产环境要怎么解决呢?能够把jar解压运行!
参考文档的exploded archives: http://docs.spring.io/spring-...
# 解压 unzip -q myapp.jar # 运行 java org.springframework.boot.loader.JarLauncher # 生产模式用如下的nohup方式,以防程序随着shell一块儿关闭 nohup java org.springframework.boot.loader.JarLauncher &
我本身用的命令不同:
unzip -q myapp.jar nohup java -cp '.:./lib/*' com.myapp.ApplicationKt &
注意当前所在的工做目录,日志目录/logs
会建立在当前工做目录下。
我提供了一个示例项目,比较粗糙,请多多包涵 https://github.com/sorra/bms
老外也有几个示例项目,可供参考:
Spring Boot Kotlin project with a REST Webservice and Spring Data: https://github.com/sdeleuze/s...
Demo Webapp using SpringBoot, Kotlin and React.js: https://github.com/winterbe/s...
顺带一提,轻境界就是用Kotlin + Spring Boot构建的!