<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          簡單、有趣的Kotlin異步微服務(wù)框架(一)

          共 25049字,需瀏覽 51分鐘

           ·

          2021-04-27 23:15

          1. 寫在前面

          「Flutter異步編程相關(guān)的系列文章」已經(jīng)講解完畢后,大概已經(jīng)兩周沒有發(fā)布文章,因?yàn)槲矣珠_始在籌劃了另一個Kotlin相關(guān)的專題: 「Kotlin微服務(wù)框架Ktor」。這次專題主要是介紹Kotlin在服務(wù)端應(yīng)用的一個微服務(wù)異步web框架。

          「為什么又開始Kotlin服務(wù)端Ktor專題呢?」

          ?

          因?yàn)橹霸?020年度總結(jié)文章也說過,后續(xù)會主要focus在Kotlin、Flutter、面試三大主題展開一系列文章總結(jié),所以開始「Kotlin服務(wù)端Ktor專題」也是在規(guī)劃路線之中。不僅會涉及到Kotlin服務(wù)端專題后續(xù)還會在Kotlin jetpack Compose方面、Flutter系列都會展開。

          ?

          「原來Flutter專題會繼續(xù)嗎?此次Kotlin服務(wù)端Ktor專題文章,F(xiàn)lutter學(xué)習(xí)者有必要看嗎?」

          ?

          「Flutter專題當(dāng)然會繼續(xù)」,此次開始「Kotlin服務(wù)端Ktor專題」是希望最后會通過「Ktor作為API服務(wù)后端框架+Flutter作為頁面前臺」搭建一套完整的從前到后的全棧應(yīng)用。我們都知道作為一名客戶端或前端開發(fā)者,上手后端門檻是比較高的。比如Java語言的Spring、SpringBoot框架,Go、python相關(guān)的后端框架等等。而現(xiàn)在的「Ktor」就是一套非常非常簡單、輕量級的異步Kotlin后端框架, 它比SpringBoot更加輕量級,僅僅只需少量代碼就能快速搭建一套API后端服務(wù)。

          ?

          個人還是強(qiáng)烈推薦Flutter學(xué)習(xí)者學(xué)習(xí)下 , 「特別是有了Kotlin基礎(chǔ)的Android開發(fā)者」 。對于我們大前端開發(fā)者很多的能力思維還僅僅停留在大前端,但是如果你能有一項(xiàng)后端開發(fā)的技能,那么你思考問題和解決問題角度就會不一樣的。當(dāng)然我們不需要像后端開發(fā)者那樣很精通后端開發(fā)領(lǐng)域,但是如果能掌握后端基本的開發(fā)和使用,還是有很大的幫助的。至少之前作為一名Flutter開發(fā)者,學(xué)習(xí)完后可以自己從前端UI頁面搭建到后端API設(shè)計(jì)、數(shù)據(jù)表設(shè)計(jì)擼一整套的應(yīng)用。為什么不推薦客戶端開發(fā)者去直接學(xué)Spring或SpringBoot,說真的因?yàn)榭蚣軚|西比較多,成本比較高,所以這次Ktor這個微服務(wù)框架簡單且易用,學(xué)習(xí)成本較低,所以還是值得試試的。以下這張圖就是后續(xù)Ktor專題路線的規(guī)劃,下面就直接進(jìn)入正題~

          2. 什么是Ktor

          2.1 Ktor基本介紹

          用Ktor官方(https://ktor.io/)一句話來介紹: 「Ktor是一個用于創(chuàng)建微服務(wù)、web應(yīng)用程序等異步框架,它很簡單、有趣并且免費(fèi)開源」。它是由jetbrains官方開源,目前已經(jīng)有8.2K+ star (https://github.com/ktorio/ktor),該框架在國內(nèi)大家可能比較陌生但是在國外還是很受歡迎的,Ktor可以說是為Kotlin中異步而生的框架,它最底層基于Kotlin Coroutine協(xié)程框架,支持了Client、Server雙端異步特性并且在Client、Server雙端上對WebSocket、Socket有了很好的支持。此外它整體具有以下幾種特性:

          • 「輕量級」

          Ktor框架可以說是非常輕量級,僅僅有一些Ktor基礎(chǔ)引擎內(nèi)容,并沒有冗雜一些其他的功能,甚至日志功能都沒有,但是你可以任意選擇定制你僅僅需要的功能,以構(gòu)件形式可插拔地集成到Ktor框架中。

          • 「可擴(kuò)展性強(qiáng)」

          可擴(kuò)展性可以說是Ktor框架又一大亮點(diǎn)之一,Ktor框架的本質(zhì)就Pipeline管道,任何的功能構(gòu)件都可以可插拔方式集成在Pipeline中。比如Ktor官方提供一系列構(gòu)件用于構(gòu)建所需的功能,使用起來非常簡單方便。

          • 「多平臺」

          借助「Kotlin Multiplatform」技術(shù)構(gòu)建,可以在任何地方部署Ktor應(yīng)用程序.

          • 「異步」

          Ktor底層是基于Kotlin協(xié)程構(gòu)建的,Ktor的異步具有很高的可伸縮性,并且利用其非阻塞式特性,從此擺脫了異步回調(diào)地獄。

          2.2 Ktor的架構(gòu)組成

          Ktor Framework主要分為以下幾層,最底層核心是Kotlin協(xié)程和基本SDK,然后往上是Ktor核心基礎(chǔ)層,包括了引擎、管道、構(gòu)件、路由、監(jiān)控等;再往上就是四大主要功能模塊分別是Client模塊、Server模塊、Socket模塊、WebSocket模塊。那么該專題主要是focus在Server模塊,主要利用Server模塊來構(gòu)件web后端服務(wù)。關(guān)于WebSocket實(shí)際上Ktor分別在Client WebSocket和Server WebSocket兩個層面都給了很大的支持。后續(xù)會基于WebSocket使用構(gòu)建一個實(shí)時IM應(yīng)用的例子。所以整體上來看Ktor框架還是比較簡單和輕量級的,最為功能豐富在于它的功能構(gòu)件(Feature), 幾乎后續(xù)所有web后端服務(wù)功能都可以看成作為它的一個功能構(gòu)件(Feature)集成到Ktor中,比如序列化(gson、jackson)、日志、auth認(rèn)證、template模版(freemarker、velocity)、CORS(解決跨域問題配置)、Session等功能

          3. 如何構(gòu)建一個簡單的Ktor Server應(yīng)用

          構(gòu)建一個Ktor Server應(yīng)用可以說是非常非常簡單,僅僅只需簡單十幾行代碼就構(gòu)建一個Server服務(wù)。而構(gòu)建Ktor Server應(yīng)用主要分為兩種 「: 一種是通過embeddedServer方式構(gòu)建,另一種則是通過EngineMain方式構(gòu)建。」

          3.1 通過「embeddedServer方式構(gòu)建」

          通過embeddedServer函數(shù)構(gòu)建Ktor Server應(yīng)用是一種最為簡單的方式也是官方默認(rèn)推薦使用的一種方式。embeddedServer函數(shù)是通過在代碼中配置服務(wù)器參數(shù)并快速運(yùn)行應(yīng)用程序的簡單方法,不需要額外配置文件。比如在下面的代碼段中,它接收服務(wù)器容器引擎類型和端口參作為參數(shù),傳入Netty服務(wù)器容器引擎和端口8080,啟動應(yīng)用后就會在8080端口監(jiān)聽。

          • Application.kt
          package com.mikyou.ktor.samplecom.mikyou.ktor.sample

          import io.ktor.application.*
          import io.ktor.http.*
          import io.ktor.response.*
          import io.ktor.routing.*
          import io.ktor.server.engine.*
          import io.ktor.server.netty.*

          fun main(args: Array<String>) {
              embeddedServer(Netty, port = 8080) {//除了支持Netty還支持Jetty、Tomcat、CIO(Coroutine-based I/O)
                  routing {
                      get("/") {
                          call.respondText("Hello Ktor")
                      }
                  }
              }.start(wait = true)
          }

          3.2 通過EngineMain方式構(gòu)建

          EngineMain方式則是選定的引擎啟動服務(wù)器,并加載外部一個 application.conf 文件中指定的應(yīng)用程序模塊. 然后在 application.conf 配置文件中配置應(yīng)用啟動參數(shù),比如服務(wù)監(jiān)聽端口等

          • Application.kt
          package com.mikyou.ktor.sample

          import io.ktor.application.*
          import io.ktor.response.*
          import io.ktor.routing.*

          fun main(args: Array<String>)Unit = io.ktor.server.netty.EngineMain.main(args)

          fun Application.module(testing: Boolean = false) {//該module函數(shù)實(shí)際上是Application的擴(kuò)展函數(shù),要想該函數(shù)運(yùn)行需要通過application.conf中配置該函數(shù)
              routing {
                  get("/") {
                       call.respondText("Hello Ktor")
                  }
              }
          }
          • application.conf
          ktor {
              deployment {
                  port = 8080 //配置端口
              }
              application {
                  modules = [ com.mikyou.ktor.sample.ApplicationKt.module ] //配置加載需要加載的module函數(shù)
              }
          }

          4. 如何架構(gòu)一個成熟的Ktor應(yīng)用

          由上面可知構(gòu)建一個簡單的Ktor Server可以說是非常簡單,然而要構(gòu)建一個成熟的Ktor Server應(yīng)用也是類似,主要是多了一些如何模塊化組織業(yè)務(wù)模塊和更清晰化去架構(gòu)業(yè)務(wù)。主要分為以下7個步驟:

          4.1 選擇構(gòu)建Server的方式

          構(gòu)建Ktor Server應(yīng)用主要分為兩種: 「一種是通過embeddedServer方式構(gòu)建,另一種則是通過EngineMain方式構(gòu)建。」 具體的選擇使用方式參考上面第3節(jié)

          4.2 選擇Server Engine

          要想運(yùn)行Ktor服務(wù)器應(yīng)用程序,就需要首先創(chuàng)建和配置服務(wù)器。服務(wù)器配置其中就包括服務(wù)器引擎配置,各種引擎特定的參數(shù)比如主機(jī)地址和啟動端口等等。Ktor支持大多數(shù)目前主流的Server Engine,其中包括:

          • Tomcat
          • Netty
          • Jetty
          • CIO(Coroutine-based I/O)

          此外Ktor框架還提供一種類型引擎TestEngine專門供測試時使用。要想使用上述指定的Server Engine,就需要添加Server Engine相關(guān)的依賴,Ktor是既支持Gradle來管理庫的依賴也支持Maven來管理。

          4.3 配置服務(wù)參數(shù)

          配置服務(wù)引擎參數(shù),由于構(gòu)建Server方式不同,所以配置引擎參數(shù)也不一樣。對于embeddedServer函數(shù)方式構(gòu)建的Ktor應(yīng)用可以直接通過代碼函數(shù)參數(shù)方式指定,對于EngineMain方式則通過修改配置文件 application.conf 。

          4.3.1 embeddedServer函數(shù)方式
          fun main(args: Array<String>) {
              embeddedServer(Tomcat, port = 8080) {//配置了服務(wù)器引擎類型和啟動端口
                  routing {
                      get("/") {
                          call.respondText("Hello Ktor")
                      }
                  }
              }.start(wait = true)
          }

          //除了服務(wù)器引擎類型和啟動端口的配置,還支持一些參數(shù)的配置

          fun main() {
              embeddedServer(Netty, port = 8080, configure = {
                  connectionGroupSize = 2 //指定用于接收連接的Event Group的大小
                  workerGroupSize = 5 //指定用于處理連接,解析消息和執(zhí)行引擎的內(nèi)部工作的Event Group的大小,
                  callGroupSize = 10 //指定用于運(yùn)行應(yīng)用程序代碼的Event Group的大小
              }) {
                  routing {
                      get("/") {
                          call.respondText("Hello Ktor")
                      }
                  }
              }.start(wait = true)
          }
          //設(shè)置可以定制一個EngineEnvironment用于替代默認(rèn)的ApplicationEngineEnvironment,我們可以通過源碼可知,embeddedServer函數(shù)內(nèi)部默認(rèn)構(gòu)建一個ApplicationEngineEnvironment。
          fun main() {
               embeddedServer(Netty, environment = applicationEngineEnvironment {
                  log = LoggerFactory.getLogger("ktor.application")
                  config = HoconApplicationConfig(ConfigFactory.load())
                  
                  module {
                      main()
                  }
                  
                  connector {
                      port = 8080
                      host = "127.0.0.1"
                  }
              }).start(true)
          }
          4.3.2 EngineMain方式
          • 如果是選擇EngineMain方式構(gòu)建Server, 那么就需要通過修改 applicaton.conf
          ktor {
              application {
                  modules = [ com.mikyou.ktor.sample.ApplicationKt.module ] //配置加載需要加載的module模塊,這里配置實(shí)際上就是Application中module擴(kuò)展函數(shù)
              }
          }

          //除了可以配置需要加載module模塊,還可以配置端口或主機(jī),SSL等
          ktor {
              deployment {
                  port = 8080 //配置端口
                  sslPort = 8443 //配置SSL端口
                  watch = [ http2 ]
              }
              application {
                  modules = [ com.mikyou.ktor.sample.ApplicationKt.module ] //配置加載需要加載的module模塊
              }
              security {//配置SSL簽名和密鑰
                  ssl {
                      keyStore = build/test.jks
                      keyAlias = testkey
                      keyStorePassword = test
                      privateKeyPassword = test
                  }
              }
          }
          //application.conf文件包含一個自定義jwt(Json Web Token)組,用于存儲JWT設(shè)置。
          ktor {
              deployment {
                  port = 8080 //配置端口
                  sslPort = 8443 //配置SSL端口
                  watch = [ http2 ]
              }
              application {
                  modules = [ com.mikyou.ktor.sample.ApplicationKt.module ] //配置加載需要加載的module模塊
              }
              security {//配置SSL簽名和密鑰
                  ssl {
                      keyStore = build/test.jks
                      keyAlias = testkey
                      keyStorePassword = test
                      privateKeyPassword = test
                  }
              }
              jwt {//JWT配置
                 domain = "https://jwt-provider-domain/"
                 audience = "jwt-audience"
                 realm = "ktor sample app"
              }
          }
          • 預(yù)定義屬性
          • 命令行運(yùn)行

          可以使用command運(yùn)行ktor的jar,并且指定端口

          java -jar sample-app.jar -port=8080

          可以通過config參數(shù)指定xxx.conf的路徑

          java -jar sample-app.jar -config=xxx.conf

          還可以通過-P指定運(yùn)行應(yīng)用程序代碼的Event Group的大小

          java -jar sample-app.jar -P:ktor.deployment.callGroupSize=7
          • 代碼中讀取application.conf中的配置

          代碼中讀取application.conf中配置是一件很實(shí)用的操作,比如連接數(shù)據(jù)庫時配置都可以通過自定義屬性來實(shí)現(xiàn)。比如下面這個例子:

          ktor {
              deployment {//預(yù)定義屬性
                  port = 8889
                  host = www.youkmi.cn
              }

              application {
                  modules = [ com.mikyou.ApplicationKt.module ]
              }
              
              #LOCAL(本地環(huán)境)、PRE(預(yù)發(fā)環(huán)境)、ONLINE(線上環(huán)境)
              env = LOCAL//自定義屬性
              security {//把db相關(guān)配置放入security,日志輸出會對該部分內(nèi)容用*進(jìn)行隱藏處理
                localDb {//自定義屬性localDb
                   url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"
                   driver = "com.mysql.cj.jdbc.Driver"
                   user = "xxx"
                   password = "xxx"
                }
                remoteDb {//自定義屬性remoteDb
                   url = "jdbc:mysql://192.168.0.101:3306/mydb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"
                   driver = "com.mysql.cj.jdbc.Driver"
                   user = "xxx"
                   password = "xxx"
                }
              }
          }

          在appliction.conf自定義了屬性配置后,如何在Ktor代碼獲取呢?請看如下代碼:

          const val KEY_ENV = "ktor.env"

          //自定義屬性的key,就是根據(jù)配置中層級通過.連接,有點(diǎn)類似JSON的取值調(diào)用
          const val KEY_LOCAL_DB_URL = "ktor.security.localDb.url"
          const val KEY_REMOTE_DB_URL = "ktor.security.remoteDb.url"

          const val KEY_LOCAL_DB_DRIVER = "ktor.security.localDb.driver"
          const val KEY_REMOTE_DB_DRIVER = "ktor.security.remoteDb.driver"

          const val KEY_LOCAL_DB_USER = "ktor.security.localDb.user"
          const val KEY_REMOTE_DB_USER = "ktor.security.remoteDb.user"

          const val KEY_LOCAL_DB_PWD = "ktor.security.localDb.password"
          const val KEY_REMOTE_DB_PWD = "ktor.security.remoteDb.password"


          fun Application.configureDb(vararg tables: Table) {
              //獲取當(dāng)前Env環(huán)境
              //通過Application中environment實(shí)例對象拿到其config對象,通過config以key-value形式獲取配置中的值,不過只支持獲取String和List
              val env = environment.config.propertyOrNull(KEY_ENV)?.getString() ?: "LOCAL"
              
              val url = environment
                  .config
                  .property(if (env == "LOCAL") KEY_LOCAL_DB_URL else KEY_REMOTE_DB_URL)//如果是LOCAL環(huán)境就切換到本地?cái)?shù)據(jù)庫連接方式
                  .getString()

              val driver = environment
                  .config
                  .property(if (env == "LOCAL") KEY_LOCAL_DB_DRIVER else KEY_REMOTE_DB_DRIVER)
                  .getString()

              val user = environment
                  .config
                  .property(if (env == "LOCAL") KEY_LOCAL_DB_USER else KEY_REMOTE_DB_USER)
                  .getString()

              val pwd =environment
                  .config
                  .property(if (env == "LOCAL") KEY_LOCAL_DB_PWD else KEY_REMOTE_DB_PWD)
                  .getString()

              //連接數(shù)據(jù)庫
              Database.connect(url = url, driver = driver, user = user, password = pwd)

              //創(chuàng)建數(shù)據(jù)庫表
              transaction {
                  tables.forEach {
                      SchemaUtils.create(it)
                  }
              }
          }

          4.4 通過Features添加必要功能構(gòu)件

          在Ktor中一個最典型的請求(Request)-響應(yīng)(Response)管道模型大致是這樣的: 它從一個請求開始,該請求會被路由到特定的程序處理,并經(jīng)由我們的應(yīng)用程序邏輯處理,最后做出響應(yīng)。然而在實(shí)際的應(yīng)用開發(fā)中,并不會這么簡單的,但是本質(zhì)上Pipeline是不變的。那么在Ktor如何更加將這個簡單管道模型給豐富起來呢?那就是向管道模式添加各種各樣的Feature(功能構(gòu)件或者功能插件)。

          4.4.1 向管道模型添加功能構(gòu)件

          在許多應(yīng)用開發(fā)中經(jīng)常會用到一些基礎(chǔ)通用的功能,比如內(nèi)容編碼、序列化、cookie、session等,這些基礎(chǔ)通用的功能在Ktor中統(tǒng)稱為**Features(功能構(gòu)件)。「所有的Features構(gòu)件都類似一個插件,插入在Request、application Logic和Response切面之間。由上圖可知,當(dāng)一個請求Request進(jìn)來后,首先會通過Routing路由機(jī)制路由給一個特定的Handler進(jìn)行處理;然而在把Request交由Handler處理之前可能會經(jīng)過若干個Feature處理;然后Handler處理完這個Request請求,就會將Response響應(yīng)返回給客戶端,然而在將響應(yīng)發(fā)送給客戶端之前,它還是可能會經(jīng)過若干個Feature處理,最終Response響應(yīng)返回到客戶端。可以看出整條從Request到Response鏈路就類似一個工廠流水線,每個Feature各司其職。

          4.4.2 Routing本質(zhì)上也是一個Feature

          Feature的靈活性和可插拔性非常強(qiáng)大,它可以出現(xiàn)在Request/Response管道模型中任何一個節(jié)點(diǎn)部分。Routing雖然我們稱為路由,但其本質(zhì)也是一個Feature

          4.4.3 如何安裝Feature

          一般都是在應(yīng)用初始化的時候去安裝Feature即可,安裝Feature非常簡單。僅僅幾行 install 即可搞定,如果是非內(nèi)置的 Feature 還需要自己引入相關(guān)lib依賴.  除了使用現(xiàn)有的Feature, 還可以自定義Feature,關(guān)于如何自定義Feature屬于Ktor高階命題,后續(xù)再展開。

          import io.ktor.features.*
          fun Application.main() {
              install(Routing)
              install(Gson)
              //...
          }

          //除了在main函數(shù)中安裝,還可以在module入口函數(shù)中安裝
          fun Application.module() {
              install(Routing)
              install(Gson)
              //...
          }

          4.5 通過Routing處理請求

          Routing本質(zhì)上也是一個Feature,所以Routing也需要進(jìn)行install,然后就可以定義Route Handler處理請求了。

          4.5.1 安裝Routing路由
          import io.ktor.routing.*

          install(Routing) {
              // ...
          }

          //或者直接調(diào)用Application的routing擴(kuò)展函數(shù)
          import io.ktor.routing.*

          routing {
              // ...
          }

          //因?yàn)锳pplication的routing擴(kuò)展函數(shù)內(nèi)部做了處理,對于未安裝Routing會自動安裝Routing的容錯,可以稍微瞅下源碼
          @ContextDsl
          public fun Application.routing(configuration: Routing.() -> Unit): Routing =
              featureOrNull(Routing)?.apply(configuration) ?: install(Routing, configuration)
              
          //通過源碼可以發(fā)現(xiàn),如果configuration沒有安裝Routing就會自動安裝Routing,所以大家一般看到的Routing都沒有手動install過程,而是直接類似下面的代碼。
          fun main(args: Array<String>) {
              embeddedServer(Tomcat, port = 8080) {
                  routing {//直接調(diào)用Application的擴(kuò)展函數(shù)routing,內(nèi)部做了對于未安裝Routing會自動安裝Routing的容錯處理
                      get("/") {
                          call.respondText("Hello Ktor")
                      }
                  }
              }.start(wait = true)
          }
          4.5.2 定義路由處理的Handler

          可以看下下面最簡單的一個get服務(wù)的定義,下面用get源碼來解讀:

          fun main(args: Array<String>) {
              embeddedServer(Tomcat, port = 8080) {
                  routing {
                      get("/") {//可以看到這個處理get請求的handler,它實(shí)際上是一個Route的擴(kuò)展函數(shù),一起來看看源碼
                          call.respondText("Hello Ktor")
                      }
                  }
              }.start(wait = true)
          }

          //Route.get函數(shù)源碼,其實(shí)一個Route對象就是一個對應(yīng)的Handler,
          @ContextDsl
          public fun Route.get(path: String, body: PipelineInterceptor<Unit, ApplicationCall>): Route {
              return route(path, HttpMethod.Get) { //route函數(shù)本質(zhì)上是一個Route的擴(kuò)展函數(shù)
                  handle(body) //通過調(diào)用Route對象來處理的請求
              }
          }

          //route函數(shù)本質(zhì)上是一個Route的擴(kuò)展函數(shù)
          @ContextDsl
          public fun Route.route(path: String, method: HttpMethod, build: Route.() -> Unit): Route {
              val selector = HttpMethodRouteSelector(method)
              return createRouteFromPath(path).createChild(selector).apply(build)//最終調(diào)用apply返回Route對象,build是傳入handle(body)執(zhí)行的lambda,
              //也就是創(chuàng)建完child后返回一個Route對象,最終再調(diào)用它的handle函數(shù)
          }

          4.6 應(yīng)用模塊化

          為了使得Ktor應(yīng)用更具有可維護(hù)性、靈活性以及,Ktor提供一種思路就是將應(yīng)用按照業(yè)務(wù)維度進(jìn)行模塊化設(shè)計(jì)。注意這里模塊化概念并不是在項(xiàng)目中的一個Module,而這里module本質(zhì)上是一個 Application 的擴(kuò)展函數(shù)。并且可以在 application.conf 指定某一個或若干個module進(jìn)行可插拔式的部署和卸載。然后一個Module又包括了一條或若干條Request/Response的管道模型。應(yīng)用模塊代碼例子如下:

          //定義一個accountModule,實(shí)際上是一個Application的擴(kuò)展函數(shù)
          fun Application.accountModule() {
              routing {
                  loginRoute()
                  bindPhoneRoute()
                  getSmsCodeRoute()
                  registerRoute()
              }
          }

          //在application.conf配置加載對應(yīng)的accountModule模塊
          ktor {
              #LOCAL、PRE、ONLINE
              env = LOCAL
              deployment {
                  port = 8889
                  host = www.youkmi.cn
              }

              application {
                  //可以在modules動態(tài)配置所需加載Module,第一個com.mikyou.ApplicationKt.module默認(rèn)是主Module,用于加載一些基礎(chǔ)通用的Features,實(shí)現(xiàn)模塊的可插拔式的安裝和卸載
                  modules = [ "com.mikyou.ApplicationKt.module","com.mikyou.modules.account.AccountModuleKt.accountModule"]//配置accountModule,注意配置路徑,例如定義Account模塊的類文件是AccountModule.kt, 所以它對應(yīng)類名稱就是AccountModuleKt,所以accountModule模塊類路徑就是com.mikyou.modules.account.AccountModuleKt.accountModule。
              }
              //...
          }

          4.7 應(yīng)用結(jié)構(gòu)化

          Ktor在提供靈活性方面提供多種方式來組織和結(jié)構(gòu)化應(yīng)用。

          4.7.1 以文件來形式組織

          將單個文件中相關(guān)的路由分組管理,比如應(yīng)用處理訂單和用戶,就會單獨(dú)建立兩個文件: OrderRoutes.kt和CustomerRoutes.kt文件分別管理相關(guān)路由請求。

          • OrderRoutes.kt
          fun Route.orderByIdRoute() {
              get("/order/{id}") {

              }
          }

          fun Route.createOrderRoute() {
              post("/order") {

              }
          }
          • CustomerRoutes.kt
          fun Route.customerById() {
              get("/customer/{id}") {

              }
          }

          fun Route.createCustomer() {
              post("/customer") {

              }
          }
          4.7.2 以路由定義形式組織
          fun Application.accountModule() {
              routing {
                  loginRoute()
                  bindPhoneRoute()
                  registerRoute()
              }
          }

          //登錄
          private fun Route.loginRoute() {
              post("/api/login") {
                //...
              }
          }

          //注冊
          private fun Route.registerRoute() {
              post("/api/register") {
                  //...
              }
          }

          //綁定手機(jī)號
          private fun Route.bindPhoneRoute() {
              post("/api/bindPhone") {
                 //...
              }
          }

          5. 使用IntelliJ IDEA快速構(gòu)建Ktor Server應(yīng)用

          IntelliJ IDEA提供一個Ktor應(yīng)用插件可以快速構(gòu)建Ktor Server應(yīng)用,其中可以借助Ktor插件可視化地安裝各種Feature功能構(gòu)件。下面會一步一步引導(dǎo)快速構(gòu)建一個Ktor Server應(yīng)用。

          5.1 安裝Ktor插件

          在IDEA中的plugins模塊中,搜索ktor安裝Ktor插件。安裝完Ktor插件后,restart IDEA。

          5.2 創(chuàng)建Ktor應(yīng)用工程并安裝Features

          打開IDEA,點(diǎn)擊new Project, 選擇左邊欄中的"Ktor"應(yīng)用,然后輸入Project name,選擇項(xiàng)目路徑、選擇構(gòu)建系統(tǒng)(Groovy Gradle、Kotlin Gradle或Maven)以及選擇對應(yīng)的服務(wù)器容器的引擎(Netty、Tomcat、Jetty、CIO).點(diǎn)擊next后,就到需要選擇對應(yīng)安裝的Feature(功能構(gòu)件),Ktor插件提供了不同類型的Features, 主要有Security、Routing、HTTP、Monitoring、Templating、Serialization、Sockets、Administration幾大類的Feature, 可以按照自己應(yīng)用的需求,按需安裝即可。Security類型相關(guān)的Features:Routing類型相關(guān)的Features: 添加Routing構(gòu)件用于路由請求的處理HTTP類型相關(guān)的Features: 添加CORS解決跨域訪問問題監(jiān)控類型相關(guān)的Features: 添加監(jiān)控日志構(gòu)件CallLogging構(gòu)件樣式模板類型相關(guān)的Features: 添加HTML DSL和CSS DSL構(gòu)件序列化類型相關(guān)的Features: 添加Gson構(gòu)件Sockets類型相關(guān)的FeaturesAdministration類型相關(guān)的Features最終,下面是我們安裝的所有Features,點(diǎn)擊Finish即可創(chuàng)建Ktor Server工程

          5.3 Ktor應(yīng)用工程項(xiàng)目結(jié)構(gòu)

          可以看到所有安裝的Features都在plugins包中生成,并在Application類main啟動執(zhí)行的入口函數(shù)進(jìn)行初始化和配置,并且應(yīng)用程序默認(rèn)端口為:8080。

          • Routing Feature默認(rèn)生成的代碼:
          image.png
          • Template Feature默認(rèn)生成代碼:
          image.png
          • 序列化Gson Feature默認(rèn)生成代碼:
          image.png

          5.4 運(yùn)行Ktor應(yīng)用

          Ktor應(yīng)用運(yùn)行起來后,可以通過localhost訪問上述默認(rèn)生成的頁面:

          • Routing Feature默認(rèn)生成的頁面結(jié)果: http://localhost:8080/
          image.png
          • Template Feature默認(rèn)生成的html-dsl頁面結(jié)果: http://localhost:8080/html-dsl
          image.png
          • Template Feature默認(rèn)生成的html-dsl頁面結(jié)果: http://localhost:8080/html-css-dsl
          image.png
          • Gson Feature默認(rèn)生成的頁面結(jié)果: http://localhost:8080/json/gson
          image.png

          5.5 Debug Ktor應(yīng)用

          6. 熊貓先生的小總結(jié)

          到這里,有關(guān)Ktor系列專題的入門第一篇文章就結(jié)束了。后面會繼續(xù)深入Ktor相關(guān)的內(nèi)容,包括如何在Ktor操作數(shù)據(jù)庫,我們會用到Kotlin中的ORM框架Exposed以及如何處理請求然后包裝輸出restful api給到客戶端使用。后續(xù)安排是每周一篇文章分享,分別是Kotlin和Flutter相關(guān)文章交替進(jìn)行。

          感謝關(guān)注,熊喵先生愿和你在技術(shù)路上一起成長!


          瀏覽 137
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  熟女一区 | 免费一级A片在线播放 | 中文字幕黄色 | 操操操操操操操操操骚逼网 | 久久久久久国产精品三级玉女聊斋 |