Kotlin:Ktor项目整合SpringBoot和Ktorm教程

开发环境

  1. idea 2019.3
  2. kotlin 1.3.41
  3. spring boot 2.1.6.RELEASE
  4. ktor 1.2.2
  5. ktorm 2.4

项目创建

使用idea创建kotlin项目,创建项目需使用gradle,如需使用maven创建项目请自行尝试,不要使用(https://start.spring.io/)创建kotlin项目除非能熟练使用kts脚本作为配置

项目配置

plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.3.41'
    id 'org.springframework.boot' version "2.1.6.RELEASE"
    // ktolin对srping支持的插件
    id "org.jetbrains.kotlin.plugin.spring" version "1.3.41"
}

apply plugin: 'io.spring.dependency-management'

dependencies {
    compileOnly "org.springframework.boot:spring-boot-configuration-processor"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    implementation "org.jetbrains.kotlin:kotlin-reflect"

    implementation "org.springframework.boot:spring-boot-starter-aop"
    implementation("org.springframework.boot:spring-boot-starter-jdbc")

    implementation("me.liuwj.ktorm:ktorm-core:2.4")
    implementation("me.liuwj.ktorm:ktorm-jackson:2.4")
    implementation("mysql:mysql-connector-java:8.0.13")
    implementation 'com.mchange:c3p0:0.9.5.4'

    // ktor 核心库
    compile "io.ktor:ktor-server-core:$ktor_version"
    // 这里ktor使用的是 netty作为web容器,如需指定其它容器请参照官网
    compile "io.ktor:ktor-server-netty:$ktor_version"
}

ktor封装

1.定义路由接口

interface KtorRouter {
    /**
     * 注册路由
     */
    fun Route.router()
}

2.定义中间件接口

interface KtorMiddleware {
    /**
     * 注册中间件
     */
    fun Application.middleware()
}

定义configuration

  • Spring Boot会检查你发布的jar中是否存在META-INF/spring.factories文件,
  • 该文件中以EnableAutoConfiguration为key的属性应该列出你的配置类,
  • 如果在pring.factories中配置后可以不用再该配置类写@Configuration
class KtormConfiguration {

	// 使用c3p0作为连接池,可自行更换
    @Bean
    @Qualifier(value = "dataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    fun dataSource(@Autowired environment: Environment): DataSource =
        DataSourceBuilder.create().type(com.mchange.v2.c3p0.ComboPooledDataSource::class.java).build()

    @Bean
    fun database(dataSource: DataSource): Database {
        return Database.connectWithSpringSupport(dataSource)
    }

    @Bean
    fun ktormModule(): Module {
        return KtormModule()
    }
}
// 此处为web框架的加载,当ktor开始启动后将陷入死循环,所以需要先让spring boot加载其他配置项
@AutoConfigureAfter(name = arrayOf("org.fyc.snow.starter.conf.KtormConfiguration"))
@EnableConfigurationProperties(KtorProperties::class)
class KtorConfiguration {

    @Resource
    private lateinit var properties: KtorProperties

    /**
     * 注册ktor web容器,可自行更改
     */
    @Bean
    @ConditionalOnMissingBean
    fun registerKtorWebContainer(): ApplicationEngineFactory<ApplicationEngine, out ApplicationEngine.Configuration> =
        Netty

    /**
     * 注册引擎
     * @param engineFactory 依赖引擎工厂
     */
    @Bean
    @ConditionalOnMissingBean
    fun applicationEngine(
        registerKtorWebContainer: ApplicationEngineFactory<ApplicationEngine, out ApplicationEngine.Configuration>,
        context: ApplicationContext
    ): ApplicationEngine {
        return embeddedServer(registerKtorWebContainer, host = properties.host, port = properties.port) {
            val middlewares = context.getBeansOfType(KtorMiddleware::class.java).values
            val routes = context.getBeansOfType(KtorRouter::class.java).values

            // 注册模块
            middlewares.forEach {
                it.apply { middleware() }
            }

            // 注册路由
            routing {
                routes.forEach {
                    it.apply { router() }
                }
            }
        }
    }

    /**
     * 注册应用
     * @param applicationEngine 依赖引擎
     * @param context            依赖spring容器
     */
    @Bean
    @ConditionalOnMissingBean
    fun application(applicationEngine: ApplicationEngine): Int {
        applicationEngine.start(true)
        return 0
    }
    
	/**
	 * ktor配置项
	 * @param host 服务器主机名
	 * @param port 绑定端口
	 */
	@ConfigurationProperties(prefix = "ktor")
	open class KtorProperties(
	    var host: String = "0.0.0.0",
	    var port: Int = 8080
	)
}

项目实例

1.控制器的使用测试

@Controller
class UserInfoController : KtorRouter {
    override fun Route.router() {
        route("/api") {
            // 访问: /api/group
            get("/group") {
                testLog(call)
            }
        }
        get("/add") {
            val id = call.request.queryParameters["id"]?.toInt() ?: 0
            val name = call.request.queryParameters["name"].toString()
            val pwd = call.request.queryParameters["pwd"].toString()

            val model = UserInfoModel {
                this.id = id
                this.name = name
                this.pwd = pwd
            }

            call.respondText(UserInfoDao.add(model).toString())
        }

        get("/") {
            call.info("@@@ ==== call log 这是测试! UserInfoController")
            call.respondText("测试1111")
        }
    }
    
    private fun testLog(call: ApplicationCall) {
        // ...实现逻辑
    }
}

2.中间件的使用测试

@Component
class KtorHttpintercept: KtorMiddleware {
    override fun Application.middleware() {
        // 拦截响应
        install(StatusPages) {
            // 配置500
            exception<Throwable> { err ->
                // 输出并写入到日志
                call.error(getMessage(err))
                call.respondText("500-${err.message}", contentType = ContentType.Text.Plain)
            }

            // 配置404
            status(HttpStatusCode.NotFound) {
                call.respondText("404-未找到指定路径", contentType = ContentType.Text.Plain)
            }
        }

        install(ContentNegotiation) {
            jackson {
                enable(SerializationFeature.INDENT_OUTPUT)
            }
        }
    }

    // 获取异常全部信息
    private fun getMessage(err: Throwable):String {
        val strBuffer = StringBuffer("${err.message}\n")
        for (se in err.stackTrace) {
            strBuffer.append("\tat ${se.className}(${se.fileName}:${se.lineNumber})\n")
        }
        strBuffer.deleteCharAt(strBuffer.length -1)
        strBuffer.append("}")
        return strBuffer.toString()
    }
}

3.启动项的使用测试

@SpringBootApplication(scanBasePackages = arrayOf("org.fyc"))
class Appclication

fun main(args: Array<String>) {
    runApplication<Appclication>(*args)
}

总结

本项目旨在提供实践思路,亦可直接使用,如需使用请参考例子,关于ktorm的使用可参考项目中的使用,亦可扩展更多使用方法,更多使用方法请参考 ktorm,由于篇幅有限只能记录大概,当然如能熟练使用spring boot框架可自行按照例子的思路提供自己的封装。

===>>> 源码点这里 <<< ===

发布了6 篇原创文章 · 获赞 2 · 访问量 5612

猜你喜欢

转载自blog.csdn.net/u010766458/article/details/96875504