
kotlin是由IntelliJ IDEA的開(kāi)發(fā)商Jetbrain推出的一種基于JVM的開(kāi)發(fā)語(yǔ)言,目標(biāo)是簡(jiǎn)化Java中很多繁瑣的設(shè)計(jì),可以和Java無(wú)縫的集成,之前一直在單元測(cè)試的時(shí)候試著使用,最近正好由契機(jī),試著用來(lái)寫(xiě)一下Spring Boot腳手架。
官方定義: Statically typed programming language for the JVM, Android and the browser
項(xiàng)目介紹
長(zhǎng)期目標(biāo)是使用kotlin開(kāi)發(fā)一個(gè)完整的spring boot應(yīng)用,目前搭建了最小量的腳手架。
在本次實(shí)踐中增加了gradle docker插件的使用,使用gradle一站式的完成從開(kāi)發(fā)、測(cè)試、打包到發(fā)布docker鏡像的整個(gè)過(guò)程。
項(xiàng)目結(jié)構(gòu)

SpringBootKotlon
│
├─── build.gradle
└─── src
├───main
│ ├─── docker
│ ├─── java
│ ├─── kotlin
│ └─── resources
│ └─── config/application.properties
└───test
├─── java
├─── kotlin
└─── resources
在main目錄的java、kotlin、resources下面,包名是一樣的。也就是說(shuō)在kotlin/com/app和java/com/app下的類(lèi),在classpath引用的時(shí)候是同一個(gè)包。
創(chuàng)建Spring Boot項(xiàng)目
Spring Boot項(xiàng)目的創(chuàng)建,可以參考《用Gradle和SpringBoot實(shí)現(xiàn)簡(jiǎn)單的RESTful框架應(yīng)用》。
為了支持kotlin本項(xiàng)目的build.gradle中需要增加kotlin的支持,并且配置docker插件。
buildscript {
ext.kotlin_version = '1.1.0'
ext.spting_boot_version = '1.5.2.RELEASE'
... ...
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath("org.springframework.boot:spring-boot-gradle-plugin:$spting_boot_version")
}
}
... ...
apply plugin: "kotlin"
apply plugin: 'org.springframework.boot'
dependencies {
... ...
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
}
sourceSets{
main{
... ...
kotlin {srcDir "src/main/kotlin"}
}
test{
... ...
kotlin {srcDir "src/test/kotlin"}
}
}
配置完之后,運(yùn)行gradle idea,下載相應(yīng)的gradle依賴(lài)包。在repositories中使用國(guó)內(nèi)鏡像和自建的本地nexus,可以加快依賴(lài)包的下載速度maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
配置sourceSets增加kotlin的包之后,可以自己創(chuàng)建一個(gè)gradle task,自動(dòng)創(chuàng)建sourceSets對(duì)應(yīng)的目錄;gradle createJavaProject會(huì)根據(jù)sourceSets中配置的路徑,創(chuàng)建指定set對(duì)應(yīng)的目錄。
task createJavaProject << {
sourceSets*.java.srcDirs*.each { it.mkdirs() }
sourceSets*.kotlin.srcDirs*.each { it.mkdirs() }
sourceSets*.resources.srcDirs*.each { it.mkdirs()}
}
運(yùn)行spring boot程序
項(xiàng)目的application入口類(lèi),使用kotlin語(yǔ)言實(shí)現(xiàn),在kotlin中是沒(méi)有靜態(tài)方法的,所以如果要實(shí)現(xiàn)main函數(shù),有兩種方法,一種是將main函數(shù)寫(xiě)在class的外面;或者使用companion object {},將需要靜態(tài)調(diào)用的方法寫(xiě)在{}中。
@SpringBootApplication
open class SpringBootKotlinApplication
fun main(args: Array<String>){
SpringApplication.run(SpringBootKotlinApplication::class.java,*args)
}
相比spring mvc,spring boot給人最大的感觸就是,用簡(jiǎn)單的注解和application.properties配置的方式,避免了spring mvc中繁瑣而且容易出錯(cuò)的xml配置文件,極大的簡(jiǎn)化了spring boot的配置。值得一提的是,application配置文件,也可以使用yaml文件。
application配置文件說(shuō)明
端口
通過(guò)在配置文件中設(shè)置server.port屬性,可以指定spring boot運(yùn)行時(shí)綁定的端口。
freemarker
spring.freemarker.*是spring boot提供的freemarker相關(guān)配置,可以配置的屬性,和注解或者xml文件是一樣的,要使用spring.freemarker配置,需要在gradle中,引入org.springframework.boot:spring-boot-starter-freemarker這個(gè)包。
此外,spring boot的application配置文件,還可以配置包括數(shù)據(jù)庫(kù)在內(nèi)的各種常見(jiàn)第三方工具或者庫(kù),應(yīng)該是將提供了一系列starter包,將注解和配置過(guò)程包裝起來(lái)了。
配置完成之后,就可以在Application類(lèi)的子目錄中編寫(xiě)Spring MVC的控制器代碼。
編寫(xiě)restful controller
一個(gè)最基本的RestController代碼如下:
@RestController
@RequestMapping(value = "/api/data")
class DataController {
@RequestMapping(value = "",method = arrayOf(RequestMethod.GET,RequestMethod.PUT))
fun index():Map<String,Any>{
val resultMap = HashMap<String,Any>()
resultMap["status"] = true
resultMap["msg"] = "success"
return resultMap
}
@RequestMapping(value = "show",method = arrayOf(RequestMethod.PUT),consumes = arrayOf(MediaType.APPLICATION_JSON_UTF8_VALUE))
fun test(@RequestBody reqMap:Map<Any,Any>):Map<Any,Any>{
return reqMap
}
}
代碼解讀:
- kotlin中使用arrayof來(lái)初始化數(shù)組;
- 對(duì)于不指定類(lèi)型或者Obejct型的變量,kotlin使用Any類(lèi)型
- method方法中可以指定對(duì)種請(qǐng)求頭,很靈活
- 在consumes中,可以指定接受的contentType為JSON格式
- 如果請(qǐng)求是json格式,用ResponseBody就可以接收J(rèn)SON對(duì)象
完成所有代碼之后,運(yùn)行gradle bootRun就可以啟動(dòng)服務(wù)。
curl 'http://localhost:8080/api/data/show' \
-X 'PUT' \
-H 'content-type: application/json' \
-H 'accept: application/json' \
--data-binary '{"data":"hello","who":"echo"}' --compressed
測(cè)試spring boot程序
spring boot和kotlin都提供了強(qiáng)大的測(cè)試套件,能夠很好的和JUnit集成,進(jìn)行集成測(cè)試和單元測(cè)試。編寫(xiě)一些基本的集成測(cè)試,檢查接口是否正常。
spring boot starter test集成了JUnit?、Mockito、AssertJ?、Hamcrest?、Spring Test & Spring Boot Test可以方便的開(kāi)始測(cè)試
@RunWith(SpringJUnit4ClassRunner::class)
@WebMvcTest(HomeController::class)
class HomeControllerStandaloneTest {
@Autowired
private var mvc: MockMvc? = null
@Test
@Throws(Exception::class)
fun indexTest() {
mvc!!.perform(MockMvcRequestBuilders.get("/").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk)
.andExpect(model().attributeExists("data"))
.andExpect { content().string(containsString("<title>Spring Boot Kotlin</title>")) }
}
}
MockMvc可以依賴(lài)注入綁定通過(guò)WebMvcTest注解的HomeController控制器,然后針對(duì)指定的controller模擬請(qǐng)求。andExpect方法,檢查response的header,body是否符合測(cè)試的期望。