Slide 1

Slide 1 text

SpringBootͱKtorΛ ࡶʹൺֱͯ͠ΈΔ ͳ͕ͷJava #1 2020.03.25 @chichi1091

Slide 2

Slide 2 text

SpringBootͱKtorΛ ࡶʹൺֱͯ͠ΈΔ ͳ͕ͷJava #1 2020.03.25 @chichi1091

Slide 3

Slide 3 text

ࣗݾ঺հ • ࣉౢઍ੖ʗͯͬ͠ʔʢ@chichi1091ʣ • גࣜձࣾHolmes • αʔόαΠυΤϯδχΞ • SpringBoot(Java,Kotlin),Groovy https://chichi1091.hatenablog.jp/ https://github.com/chichi1091

Slide 4

Slide 4 text

© Holmes,inc. All right reserved. ܖ໿ϚωδϝϯτγεςϜ
 ʮϗʔϜζΫϥ΢υʯ ܖ໿ʹɺ Ϛωδϝϯτͷ
 ࢹ఺Λɻ

Slide 5

Slide 5 text

© Holmes,inc. All right reserved. ։ൃ؀ڥ

Slide 6

Slide 6 text

։ൃʹؔΘΔશ৬छੵۃ࠾༻தͰ͢ʂ – ϓϩμΫτϚωʔδϟ – UI/UXσβΠφʔ – webϑϩϯτΤϯυΤϯδχΞ – αʔόαΠυΤϯδχΞ – SRE

Slide 7

Slide 7 text

Ktorͱ͸ʁ

Slide 8

Slide 8 text

Ktorͱ͸ʁ • KotlinΛ։ൃ͍ͯ͠ΔJetBrains͕ࣾ։ൃͨܰ͠ྔ WebϑϨʔϜϫʔΫ • featureΛ௥Ճ͢Δ͜ͱͰ֦ுػೳͷར༻͕Մೳ • ςϯϓϨʔτΤϯδϯ • ೝূػೳ • DI

Slide 9

Slide 9 text

SpringBootͱൺֱ

Slide 10

Slide 10 text

SpringBootͱൺֱ • ීஈ࢖͍ͬͯΔSpringBootͱൺֱ͢Δ͜ͱͰཧղ ΛਂΊ͔ͨͬͨ • 100%Kotlin੡ͷϑϨʔϜϫʔΫʹڵຯ͕͋ͬͨ • ӡ༻ʹ଱͑ΒΕΔ͔ௐ΂͔ͨͬͨ

Slide 11

Slide 11 text

૊ΈࠐΈAPαʔό

Slide 12

Slide 12 text

૊ΈࠐΈAPαʔόʢSpringBootʣ • Buildπʔϧʹspring-boot-starter-xxxΛ૊ΈࠐΉ ͜ͱͰ੾Γସ͕͑Մೳ • tomcat • jetty • undertow

Slide 13

Slide 13 text

૊ΈࠐΈAPαʔόʢKtorʣ • Buildπʔϧʹktor-server-xxxΛ૊ΈࠐΉ͜ͱͰ੾ Γସ͕͑Մೳ • Netty • jetty • tomcat

Slide 14

Slide 14 text

BootRun

Slide 15

Slide 15 text

BootRun @SpringBootApplication @Controller class Application { @GetMapping("/") fun index(): String = "Hello, Kotlin" } fun main(args: Array) { runApplication(*args) } class Application fun main(args: Array) { val server = embeddedServer(Netty, 8080) { routing { get("/") { call.respond(HttpStatusCode.OK,"Hello, Kotlin") } } } server.start() } 4QSJOH#PPU ,UPS

Slide 16

Slide 16 text

ςϯϓϨʔτΤϯδϯ

Slide 17

Slide 17 text

ςϯϓϨʔτΤϯδϯ • SpringBoot • Thymeleaf • Freemarker • Groovy Template • Ktor • Thymeleaf • Freemarker • Velocity • Mustache • Kotlin DSLͰHTML΍CSSΛॻ͘͜ͱ΋Մೳ

Slide 18

Slide 18 text

ςϯϓϨʔτΤϯδϯʢ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Λੜ੒ɾग़ྗ

Slide 19

Slide 19 text

ςϯϓϨʔτΤϯδϯʢ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.-Λੜ੒ɾग़ྗ

Slide 20

Slide 20 text

Controller

Slide 21

Slide 21 text

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" }

Slide 22

Slide 22 text

ControllerʢKtorʣ fun main(args: Array) { 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 ͦͷதʹϧʔςΟϯάઃఆ͠ΞΫγϣ ϯΛࢦఆ͢Δ

Slide 23

Slide 23 text

ྫ֎ϋϯυϥʔ

Slide 24

Slide 24 text

ControllerʢSpringBootʣ class ExceptionHandler: ResponseEntityExceptionHandler() { @ExceptionHandler(Exception::class) fun handleException(ex: Exception, headers: HttpHeaders, request: WebRequest): ResponseEntity { return super.handleExceptionInternal(ex, "handleException", headers , HttpStatus.INTERNAL_SERVER_ERROR, request) } }

Slide 25

Slide 25 text

ControllerʢKtorʣ fun main() { val server = embeddedServer(Netty, port = 8082) { install(StatusPages) { exception{ cause -> call.respond(HttpStatusCode.InternalServerError) } exception{ cause -> call.respond(HttpStatusCode.Forbidden) } } routing { userController() } } server.start() } class XxxException: RuntimeException() class AuthorizationException: RuntimeException() w ྫ֎ʹΑͬͯฦ͢εςʔλείʔυΛ ఆٛ

Slide 26

Slide 26 text

Session

Slide 27

Slide 27 text

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 ηογϣϯείʔϓ

Slide 28

Slide 28 text

SessionʢKtorʣ fun main() { val server = embeddedServer(Netty, port = 8082) { install(Sessions) { cookie("MY_SESSION") { cookie.extensions["SameSite"] = "lax" } } routing { get() { val session: MySession = call.sessions.get() ?: 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໊

Slide 29

Slide 29 text

DB઀ଓ

Slide 30

Slide 30 text

DB઀ଓʢSpringBootʣ @Entity data class Users ( @Id @GeneratedValue(strategy=GenerationType.IDENTITY) val id: Long, val name: String, val birthday: Date ) @Repository interface UsersRepository: JpaRepository {} @RestController class UsersController( private val usersRepository: UsersRepository ) { @GetMapping(value = ["/"]) @ResponseStatus(HttpStatus.OK) fun index(): List = usersRepository.findAll() } • ORϚούʔ͸JPA • τϥϯβΫγϣϯ͸AOPͰ੍ޚ

Slide 31

Slide 31 text

DB઀ଓʢKtorʣ • ORϚούʔ͸Exposed • ΋ͪΖΜKotlin੡ • JetBrains͕ࣾ։ൃ • BootRun࣌ʹH2΁઀ଓ fun main(args: Array) { // DB΁઀ଓ Database.connect("jdbc:h2:mem:ktor_db;DB_CLOSE_DELAY=-1", "org.h2.Driver") val server = embeddedServer(Netty, 8080) { routing { userController() } } server.start() }

Slide 32

Slide 32 text

DB઀ଓʢKtorʣ // Dao object Users : LongIdTable() { val name: Column = varchar("name", 50) val birthday: Column = date("birthday") } // Entity class User(id: EntityID): LongEntity(id) { companion object : LongEntityClass(Users) var name by Users.name var birthday by Users.birthday } fun Route.userController() { val service by inject() 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 = listOf() transaction { result = User.all().sortedByDescending{ it.birthday } } call.respondText { "users routing ${service.getName()}" } } } } w 42-ൃߦ࣌͸USBOTBDUJPOඞਢ w ݕࡧ͸ଞʹ΋ val user: SizedIterable = User.find { Users.id eq 1 } val user: User? = User.findById(1L)

Slide 33

Slide 33 text

JSON

Slide 34

Slide 34 text

JSONʢSpringBootʣ @RestController @RequestMapping("/users") class UsersApplication{ @GetMapping("/") fun list(request: HttpServletRequest): ResponseEntity { val json = Json(1,"Kotlin") return ResponseEntity.of(Optional.of(json)) } } data class Json( private val id: Int, private val name: String )

Slide 35

Slide 35 text

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/Λ੔ܗ

Slide 36

Slide 36 text

DI

Slide 37

Slide 37 text

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()}" } }

Slide 38

Slide 38 text

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() } class UserService { fun getName(): String{ return "Kotlin" } } fun Route.userController() { val service by inject() route("/users") { get() { call.respondText { "users routing ${service.getName()}" } } } } w JOTUBMM ,PJO Ͱ%*ίϯςφ΁ొ࿥ w γϯάϧτϯͰ6TFS4FSWJDFΛొ࿥ w JOKFDUͰऔಘ

Slide 39

Slide 39 text

·ͱΊ

Slide 40

Slide 40 text

·ͱΊ • SpringBootͱಉ౳ͷfeature͕ἧ͍ͬͯΔΑ͏ʹ ײͨ͡ • υΩϡϝϯτ΋Θ͔Γ΍͍͢(https://ktor.io/) • Githubͷߋ৽΋׆ൃ • feature΋ͲΜͲΜ૿͑ͦ͏ʁ • SpringBootΑΓKotlinͬΆ͍ίʔυ͕ॻ͚Δ • ຊ൪ར༻΋଱͑ΒΕͦ͏