Kotlin是对Java的一个简练的封装,提供了很多便利性的语法,熟练使用后,会大大缩减代码的行数,提高编码的速度。
具体Kotlin的优劣,网上很多评论,有兴趣的可以去看看,我们开始我们简单的demo开发。
需求:最简单的用户的CRUD,提供REST服务
开发工具:IDEA
Java框架:Springboot
数据库:Mysql
ORM:Hibernate JPA
好,下面来感受一下Kotlin的魅力,首先我们用IDEA新建一个基于Kotlin的Springboot项目,Kotlin是IntelliJ 公司推出的产品,所以IDEA原生就支持该语法。
目前的代码结构如下:可参见Github
首先我们先来看看实体的定义:
1 package com.huangyu.hellokotlin.dao 2 3 import kotlinx.serialization.Serializable 4 import java.util.* 5 import javax.persistence.GeneratedValue 6 import javax.persistence.GenerationType 7 import javax.persistence.Id 8 import javax.persistence.MappedSuperclass 9 10 @Serializable 11 @MappedSuperclass 12 open class BaseEntity(@Id @GeneratedValue(strategy = GenerationType.IDENTITY) 13 var id: Long = 0, 14 var available: Boolean = true, 15 var logicDel: Boolean = false, 16 var createdTime: Date = Date())
1 package com.huangyu.hellokotlin.dao 2 3 import com.fasterxml.jackson.annotation.JsonIgnoreProperties 4 import javax.persistence.* 5 6 @Entity @Table(name = "kotlin_users") 7 data class User( 8 var name: String = "", 9 var age: String? = null, 10 var phone: String = "", 11 @OneToMany(mappedBy = "user", cascade = [CascadeType.ALL]) @JsonIgnoreProperties("carList", "user") var carList: List<Car>? = null 12 ) : BaseEntity() 13 14 @Entity @Table(name = "kotlin_user_cars") 15 data class Car( 16 var name: String = "", 17 var brand: String = "", 18 @ManyToOne(cascade = [CascadeType.ALL]) @JoinColumn(name = "user_id") var user: User? = null 19 ) : BaseEntity()
Kotlin文件以.kt结尾,同时一个kt文件中允许多个class的定义,它会自动转换成相应的Java代码。
BaseDto中定义的 BaseEntity为基类,定义了Jpa需要的主键ID,以及一些业务需要的 available、logicDel等字段。各位可发现,其实Kotlin定义class并没有像Java那样定义一些字段,然后get set 方法。
而是在方法声明中,对变量进行定义,并且,此时可以赋初始值,节省了很多的代码量,当然,你也可以在class 的主体中进行定义。
UserDtos中定义的User和Car是一对多的关系,使用的Jpa Annotation进行标识,语法跟Java基本一致,大家注意实体定义最后的 : BaseEntity() 表示继承。
然后我们看一下其他代码,
Service:
1 package com.huangyu.hellokotlin.service 2 3 import com.huangyu.hellokotlin.dao.User 4 import org.springframework.data.domain.Page 5 6 interface UserService { 7 fun add(user: User): User 8 fun get(id: Long?): User 9 fun page(pageIndex: Int, pageSize: Int): Page<User> 10 fun del(id: Long?) 11 }
1 package com.huangyu.hellokotlin.service.impl 2 3 import com.huangyu.hellokotlin.dao.Car 4 import com.huangyu.hellokotlin.dao.User 5 import com.huangyu.hellokotlin.dao.repo.CarRepository 6 import com.huangyu.hellokotlin.dao.repo.UserRepository 7 import com.huangyu.hellokotlin.service.UserService 8 import org.springframework.beans.factory.annotation.Autowired 9 import org.springframework.data.domain.Page 10 import org.springframework.data.domain.PageRequest 11 import org.springframework.stereotype.Service 12 13 @Service 14 class UserServiceImpl : UserService { 15 @Autowired lateinit var userRepository: UserRepository 16 @Autowired lateinit var carRepository: CarRepository 17 18 override fun add(user: User): User { 19 if (user.id != 0L) { 20 val existedUser: User = userRepository.findOne(user.id) 21 for (car in existedUser.carList!!) 22 carRepository.delete(car) 23 } 24 25 for (car: Car in user.carList!!) 26 car.user = user 27 return userRepository.save(user) 28 } 29 30 override fun get(id: Long?): User { 31 return userRepository.getOne(id) 32 } 33 34 override fun page(pageIndex: Int, pageSize: Int): Page<User> { 35 val pageRequest = PageRequest(pageIndex, pageSize) 36 return userRepository.findAll(pageRequest) 37 } 38 39 override fun del(id: Long?) { 40 val user = userRepository.getOne(id) 41 for (car: Car in user.carList!!) 42 carRepository.delete(car) 43 userRepository.delete(id) 44 } 45 }
Repository:
1 package com.huangyu.hellokotlin.dao.repo 2 3 import com.huangyu.hellokotlin.dao.Car 4 import com.huangyu.hellokotlin.dao.User 5 import org.springframework.data.jpa.repository.JpaRepository 6 7 interface UserRepository : JpaRepository<User, Long> 8 interface CarRepository : JpaRepository<Car, Long>
Controller:
1 package com.huangyu.hellokotlin.web 2 3 import com.google.gson.GsonBuilder 4 import com.huangyu.common.gson.GsonDateTypeAdapter 5 import com.huangyu.common.gson.GsonLongTypeAdapter 6 import com.huangyu.common.web.ApiResponse 7 import com.huangyu.hellokotlin.dao.User 8 import com.huangyu.hellokotlin.dao.page.BootstrapPage 9 import com.huangyu.hellokotlin.service.UserService 10 import org.springframework.beans.factory.annotation.Autowired 11 import org.springframework.web.bind.annotation.RequestMapping 12 import org.springframework.web.bind.annotation.RestController 13 import java.util.* 14 15 @RestController 16 @RequestMapping("user") 17 class UserController { 18 19 @Autowired lateinit var userService: UserService 20 21 @RequestMapping("add") 22 fun addUser(userJson: String): ApiResponse { 23 val gson = GsonBuilder().serializeNulls().registerTypeAdapter(Long::class.java, GsonLongTypeAdapter()).registerTypeAdapter(Date::class.java, GsonDateTypeAdapter()).create() 24 var user = gson.fromJson(userJson, User::class.java) 25 return ApiResponse.ok(userService.add(user)) 26 } 27 28 @RequestMapping("get") 29 fun getUser(id: Long?): ApiResponse { 30 return ApiResponse.ok(userService.get(id)) 31 } 32 33 @RequestMapping("page") 34 fun getUserPage(pageIndex: Int, pageSize: Int): ApiResponse { 35 val page = userService.page(pageIndex, pageSize) 36 val bootstrapPage = BootstrapPage(Integer.parseInt(page.totalElements.toString()), page.toList()) 37 return ApiResponse.ok(bootstrapPage) 38 } 39 40 @RequestMapping("del") 41 fun delUser(id: Long?): ApiResponse { 42 userService.del(id) 43 return ApiResponse.ok() 44 } 45 }
Test:
1 package com.huangyu.hellokotlin.test 2 3 import com.google.gson.Gson 4 import com.google.gson.GsonBuilder 5 import com.huangyu.Application 6 import com.huangyu.common.gson.GsonDateTypeAdapter 7 import com.huangyu.common.gson.GsonLongTypeAdapter 8 import com.huangyu.common.web.ApiResponse 9 import com.huangyu.common.web.ReturnCodeEnum 10 import com.huangyu.hellokotlin.dao.Car 11 import com.huangyu.hellokotlin.dao.User 12 import com.huangyu.hellokotlin.dao.repo.UserRepository 13 import org.junit.Before 14 import org.junit.Test 15 import org.junit.runner.RunWith 16 import org.springframework.beans.factory.annotation.Autowired 17 import org.springframework.boot.test.context.SpringBootTest 18 import org.springframework.boot.test.web.client.TestRestTemplate 19 import org.springframework.test.context.junit4.SpringRunner 20 import java.util.* 21 22 var userId: Long = 0 23 24 @RunWith(SpringRunner::class) 25 @SpringBootTest(classes = [Application::class], webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 26 class UserTest { 27 28 @Autowired lateinit var testRestTemplate: TestRestTemplate 29 @Autowired lateinit var userRepository: UserRepository 30 31 @Before 32 fun clear() { 33 userRepository.deleteAll() 34 } 35 36 @Test fun userTest() { 37 add() 38 get() 39 } 40 41 fun add() { 42 var user = createUser() 43 44 val gson = GsonBuilder().serializeNulls().registerTypeAdapter(Long::class.java, GsonLongTypeAdapter()).registerTypeAdapter(Date::class.java, GsonDateTypeAdapter()).create() 45 val userJson = gson.toJson(user, User::class.java) 46 val result = Gson().fromJson<ApiResponse>(testRestTemplate.getForObject(TestURL.addUser + "?userJson={userJson}", String::class.java, userJson), ApiResponse::class.java) 47 assert(result.code == ReturnCodeEnum.success.ordinal) 48 user = gson.fromJson(result.data.toString(), User::class.java) 49 50 userId = user.id 51 } 52 53 private fun createUser(): User { 54 var user = User() 55 user.age = 35.toString() 56 user.name = "wangyu" 57 user.phone = "186-8949-5151" 58 59 val carList = ArrayList<Car>() 60 val car = Car() 61 car.brand = "mazda" 62 car.name = "alexa" 63 64 carList.add(car) 65 user.carList = carList 66 return user 67 } 68 69 fun get() { 70 val result = Gson().fromJson<ApiResponse>(testRestTemplate.getForObject(TestURL.getUser + "?id=" + userId, String::class.java), ApiResponse::class.java) 71 assert(result.code == ReturnCodeEnum.success.ordinal) 72 val gson = GsonBuilder().serializeNulls().registerTypeAdapter(Long::class.java, GsonLongTypeAdapter()).registerTypeAdapter(Date::class.java, GsonDateTypeAdapter()).create() 73 val user: User = gson.fromJson<User>(result.data.toString(), User::class.java) 74 assert(user.id == userId) 75 } 76 } 77 78 // 22000 + 30000 + 15000 + 10000
Test代码是基于controller层进行web restful 接口测试。
以上是基本的代码,后续会持续更改。