Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SpringBootとKtorを雑に比較してみる

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 SpringBootとKtorを雑に比較してみる

Avatar for chiharu terashima

chiharu terashima

March 25, 2020
Tweet

More Decks by chiharu terashima

Other Decks in Programming

Transcript

  1. BootRun @SpringBootApplication @Controller class Application { @GetMapping("/") fun index(): String

    = "Hello, Kotlin" } fun main(args: Array<String>) { runApplication<BlogApplication>(*args) } class Application fun main(args: Array<String>) { val server = embeddedServer(Netty, 8080) { routing { get("/") { call.respond(HttpStatusCode.OK,"Hello, Kotlin") } } } server.start() } 4QSJOH#PPU ,UPS
  2. ςϯϓϨʔτΤϯδϯ • SpringBoot • Thymeleaf • Freemarker • Groovy Template

    • Ktor • Thymeleaf • Freemarker • Velocity • Mustache • Kotlin DSLͰHTML΍CSSΛॻ͘͜ͱ΋Մೳ
  3. ςϯϓϨʔτΤϯδϯʢKotlin DSLʣ get("/styles.css") { call.respondCss { body { backgroundColor =

    Color.red } p { fontSize = 2.em } rule("p.myclass") { color = Color.blue } } } suspend inline fun ApplicationCall.respondCss(builder: CSSBuilder.() -> Unit) { this.respondText(CSSBuilder().apply(builder).toString(), ContentType.Text.CSS) } w ,PUMJOίʔυͰ$44Λੜ੒ɾग़ྗ
  4. ςϯϓϨʔτΤϯδϯʢKotlin DSLʣ get("/") { call.respondHtml { head { link(rel =

    "stylesheet", href = "/styles.css", type = "text/css") } body{ h1 { id = "title" +"ͳ͕ͷJava" } p("myclass") { +"myclass" } ul { for(n in 1..10) { li { onClick = "alert($n)" +"$n" } } } } } } w ,PUMJOίʔυͰ)5.-Λੜ੒ɾग़ྗ
  5. ControllerʢSpringBootʣ @Controller //@RestController @RequestMapping("/users") class UsersApplication{ @GetMapping("/") fun list(): String

    = "users routing ok" @GetMapping("/{id}") fun index(@PathVariable(“id") id: String): String = "user $id routing ok" }
  6. ControllerʢKtorʣ fun main(args: Array<String>) { val server = embeddedServer(Netty, 8080)

    { routing { userController() } } server.start() } fun Route.userController() { route("/users") { get() { call.respondText { "users routing ok" } } get("/{id}") { val id = call.parameters["id"] call.respond(HttpStatusCode.OK, "user $id routing ok") } } } w SPVUFͰΤϯυϙΠϯτΛࢦఆ w ͦͷதʹϧʔςΟϯάઃఆ͠ΞΫγϣ ϯΛࢦఆ͢Δ
  7. ControllerʢSpringBootʣ class ExceptionHandler: ResponseEntityExceptionHandler() { @ExceptionHandler(Exception::class) fun handleException(ex: Exception, headers:

    HttpHeaders, request: WebRequest): ResponseEntity<Any> { return super.handleExceptionInternal(ex, "handleException", headers , HttpStatus.INTERNAL_SERVER_ERROR, request) } }
  8. ControllerʢKtorʣ fun main() { val server = embeddedServer(Netty, port =

    8082) { install(StatusPages) { exception<XxxException>{ cause -> call.respond(HttpStatusCode.InternalServerError) } exception<AuthorizationException>{ cause -> call.respond(HttpStatusCode.Forbidden) } } routing { userController() } } server.start() } class XxxException: RuntimeException() class AuthorizationException: RuntimeException() w ྫ֎ʹΑͬͯฦ͢εςʔλείʔυΛ ఆٛ
  9. SessionʢSpringBootʣ @Controller //@RestController @RequestMapping("/users") class UsersApplication{ @GetMapping("/") fun list(request: HttpServletRequest):

    String { val session = request.session session.setAttribute("key", "name") val name = session.getAttribute("key") return "users routing ok" } } w Լهͷྫ͸௚઀4FTTJPOΛར༻͢Δํ๏ w ଞʹ΋ w !4FTTJPO"UUSJCVUFT w !4DPQF ηογϣϯείʔϓ
  10. SessionʢKtorʣ fun main() { val server = embeddedServer(Netty, port =

    8082) { install(Sessions) { cookie<MySession>("MY_SESSION") { cookie.extensions["SameSite"] = "lax" } } routing { get() { val session: MySession = call.sessions.get<MySession>() ?: MySession("1") call.sessions.set("MY_SESSION", session.copy("2")) call.respondText { "users routing ${session.id}" } } } } server.start() } data class MySession ( val id: String ) w ʮ.:@4&44*0/ʯ͕$PPLJF໊
  11. DB઀ଓʢSpringBootʣ @Entity data class Users ( @Id @GeneratedValue(strategy=GenerationType.IDENTITY) val id:

    Long, val name: String, val birthday: Date ) @Repository interface UsersRepository: JpaRepository<Users, Long> {} @RestController class UsersController( private val usersRepository: UsersRepository ) { @GetMapping(value = ["/"]) @ResponseStatus(HttpStatus.OK) fun index(): List<Users> = usersRepository.findAll() } • ORϚούʔ͸JPA • τϥϯβΫγϣϯ͸AOPͰ੍ޚ
  12. DB઀ଓʢKtorʣ • ORϚούʔ͸Exposed • ΋ͪΖΜKotlin੡ • JetBrains͕ࣾ։ൃ • BootRun࣌ʹH2΁઀ଓ fun

    main(args: Array<String>) { // DB΁઀ଓ Database.connect("jdbc:h2:mem:ktor_db;DB_CLOSE_DELAY=-1", "org.h2.Driver") val server = embeddedServer(Netty, 8080) { routing { userController() } } server.start() }
  13. DB઀ଓʢKtorʣ // Dao object Users : LongIdTable() { val name:

    Column<String> = varchar("name", 50) val birthday: Column<DateTime> = date("birthday") } // Entity class User(id: EntityID<Long>): LongEntity(id) { companion object : LongEntityClass<User>(Users) var name by Users.name var birthday by Users.birthday } fun Route.userController() { val service by inject<UserService>() route("/users") { post() { SchemaUtils.create(Users) // ϚΠάϨʔγϣϯ val cal = Calendar.getInstance() cal.set(Calendar.YEAR, 2020) cal.set(Calendar.MONTH, 3 -1) cal.set(Calendar.DAY_OF_MONTH, 25) val today = DateTime(Calendar.getInstance().timeInMillis) transaction { User.new { name = "kotlin ktor" birthday = DateTime(today) } } call.respondText { "users insert" } } put() { transaction { Users.update ({ Users.id eq 1 }) { it[Users.name] = "kotlin OExposed" } } call.respondText { "users update" } } delete() { transaction { Users.deleteWhere { Users.id eq 1 } } call.respondText { "users delete" } } get() { var result: List<User> = listOf() transaction { result = User.all().sortedByDescending{ it.birthday } } call.respondText { "users routing ${service.getName()}" } } } } w 42-ൃߦ࣌͸USBOTBDUJPOඞਢ w ݕࡧ͸ଞʹ΋ val user: SizedIterable<User> = User.find { Users.id eq 1 } val user: User? = User.findById(1L)
  14. JSONʢSpringBootʣ @RestController @RequestMapping("/users") class UsersApplication{ @GetMapping("/") fun list(request: HttpServletRequest): ResponseEntity<Json>

    { val json = Json(1,"Kotlin") return ResponseEntity.of(Optional.of(json)) } } data class Json( private val id: Int, private val name: String )
  15. JSONʢKtorʣ fun main() { val server = embeddedServer(Netty, port =

    8082) { install(ContentNegotiation) { jackson { configure(SerializationFeature.INDENT_OUTPUT, true) } } routing { get() { call.respond(Json(1, "Ktor")) } } } server.start() } data class Json( private val id: Int, private val name: String ) w JOTUBMMͰ+BDLTPOͷઃఆ w ฦ٫͞ΕΔ+40/Λ੔ܗ
  16. DI

  17. DIʢSpringBootʣ @Service class UserService { fun getName(): String { return

    "Kotlin" } } @RestController class UserController( private val userService: UserService ) { @GetMapping("/") fun index(): String { return "Hello, ${userService.getName()}" } }
  18. DIʢKtorʣ • KtorͰDI͢Δʹ͸ʮKodeinʯ͔ʮKoinʯΛ࢖͏ • ࠓճ͸Koin fun main() { val server

    = embeddedServer(Netty, port = 8082) { install(Koin) { modules(module) } routing { userController() } } server.start() } val module = module(createdAtStart = true) { singleBy<UserService, UserService>() } class UserService { fun getName(): String{ return "Kotlin" } } fun Route.userController() { val service by inject<UserService>() route("/users") { get() { call.respondText { "users routing ${service.getName()}" } } } } w JOTUBMM ,PJO Ͱ%*ίϯςφ΁ొ࿥ w γϯάϧτϯͰ6TFS4FSWJDFΛొ࿥ w JOKFDUͰऔಘ