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

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

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

てっしー

March 25, 2020
Tweet

More Decks by てっしー

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Ͱऔಘ