Kotlin后端开发-IntelliJ IDEA搭建

开篇扯犊子:

最近在学kotlin,有些懵啊,学了基本也忘了点,工作很忙最近才好点,这句话是今天加上的,写这个博客写了好几天,一天只能写一点,没时间啊,我不是那种可以睡很少觉的人,我要是熬夜就不能保证第二天的工作质量了,烦啊。而且无奈业余时间又有限,真是很矛盾啊很尴尬啊,为了和大学同学住一个房子,每天上班要一个半小时,下班一个半小时。还好我女朋友送了我一个kindle(秀一下),可以在路上学习,不然我要疯啊。

不禁想起刘帅微信群里的一些大佬们,天天都在学习,一问他们在干吗,都在说公司最近闲得很,要跳槽之类的。。。。。。

他们怎么那么闲啊,有一位大佬,天天去打游戏,游戏打腻了,就去学学习,md这几天他又宣布了,公司成为了国企,o( ̄︶ ̄)o我说怎么那么闲呢。

kotlin可以写Android,IOS,也可以开发后端,利用kotlin成为一个全栈工程师,是十分简单的。于是就试着用kotlin搭建了一下后台服务,能搭起来,还不错哈哈哈哈。

正文:kotlin开发后端的优点:

  • 快,构建起来是挺快的。也可以配置一下kotlin的热部署AutoReload,使项目在开发的时候再尼玛快点。
  • 一些其他特性:看官网自己吹就行了,比我吹得要好一些。
  • 可以拿来装13。

一、保证jdk和idea都安好了。

二、利用ktor插件创建ktor项目:

idea安装ktor插件:
这里写图片描述
安装完了之后,开始利用插件创建项目:
File->new Project 就会看到这个画面:
这里写图片描述
1:你的jdk。
2:选择ktor插件。
3:选择你需要的一些特性。在这里不选择也行,到项目中可以利用gradle配置,等以后学到这再说这些都是干啥的。
4:同3。
点击next之后一路next+finish。

三、创建项目完毕。

如果创建项目时没有选择3处的一些框架,创建项目完毕后,可以在gradle中添加,例如添加netty和logback:

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
    compile "io.ktor:ktor-server-netty:$ktor_version"
    compile "ch.qos.logback:logback-classic:1.2.1"
}

创建项目完毕后,看到如图所示结构:widget是我自己写的,忽略掉即可,正常创建之后没有。
这里写图片描述
application.conf文件:顾名思义,是一个配置文件,配置的modules既是application.kt中的module,如下:
这里写图片描述
如果新建的包含main的kt文件命名不是application.kt也没关系,只要和application.conf中的modules后面的名字一样即可。

在idea中,我们创建好的项目,会自动识别包含main方法的配置,可以直接运行起来。有的时候这个配置会报红,通常是module找不到的原因。我们如下图所示把module配置上即可。
这里写图片描述
1. 点击配置
2. 点击倒三角找到要运行的module
3. 点击他。配置完毕。

四、敲代码:

一、路由:

如果gradle中没有配置netty,那就配一下子:

compile "io.ktor:ktor-server-netty:$ktor_version"
compile "io.ktor:ktor-server-core:$ktor_version"

一些必不可少的,创建项目之后就会自己有的东西,检查一下:

compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version"
compile "org.jetbrains.kotlinx:kotlinx-coroutines-io:$kotlinx_coroutines_version"
compile "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinx_coroutines_version"

以上配置通过之后,路由这个东东贼鸡儿简单。

在我们的fun Application.module() {}中写一个routing{},在routin中写一个普通的get方法:

routing {
        get("/") {
            call.respondText("HELLO WORLD!Ktor", contentType = ContentType.Text.Plain)
        }
}

然后浏览器打开:http://0.0.0.0:8080/
(这里注意,如果你是自己利用插件建立的项目,建立好之后main方法是这样的:

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

此时应该打开localhost的8080端口,才能看到结果。
如果你是和我一样,吧main改成了:

fun main(args: Array<String>) {
    embeddedServer(Netty, 8080, watchPaths = listOf("applicationKt"), module = Application::module).start()
}

那就打http://0.0.0.0:8080/。原因是embeddedServer中指定的host是0.0.0.0。
这里写图片描述

还可以在项目编译的时候,打印的日志中,找到Responding at xxxx 。这个xxxx就是你要打开的连接。
这里写图片描述
)
打开后看到结果:
这里写图片描述
改一下这部分文字:
这里写图片描述
注意左下,改了代码之后点击这个Rerun,不要点击项目右上角的run。不然则会告诉你端口已经被占用了哈哈哈。自己想想怎么回事。

rerun后结果:
这里写图片描述

二、gson返回json串:

好多教程都是用jackson。作为一个Android开发者,两个公司都用的gson。我自然对jackson没有好感。

1、配置gson:
配置这个gson有坑啊,这个gradle正确的连接找不到,不管用,后来在github的ktor官网上发现,应该是这个连接:

compile "io.ktor:ktor-gson:$ktor_version"

对应的github中的地址:
这里写图片描述
学习方法:所有ktor项目的特性,在ktor的github中都能找到。找到之后,看他的test怎么写的,你就怎么写。牛逼不?

2、gson返回map对象和接收map对象:
代码:还是在module里面写:

install(ContentNegotiation) {//引入我们需要的gson以及注册gsonconverter
        register(ContentType.Application.Json, GsonConverter())
    }
routing {
        val model = mapOf("id" to 1, "title" to "Hello, World!", "unicode" to uc)
        get("/gson") {
            call.respond(model)
        }
        post("/gson") {
            val map = call.receive<Map<*, *>>()
            val text = map.entries.joinToString { "${it.key}=${it.value}" }
            call.respond(text)
        }
    }

这里有个uc是:

val uc = "\u0422"

经过base64编码之后是个T。

写好代码之后rerun,浏览器中输入http://0.0.0.0:8080/gson
或者localhost的这个:8080/gson就会看到:
这里写图片描述

接收gson代码也简单,call.receive<Map<*, *>>()接受一个map对象。

然后val text = map.entries.joinToString { "${it.key}=${it.value}" }
对其进行遍历并转换为string。

然后call.respond(text)返回结果。

3、gson返回实体类对象。
定义实体类,kotlin就两行代码就搞定两个类,牛逼不?:

data class MyEntity(val id: Int, val name: String, val children: List<ChildEntity>)
data class ChildEntity(val item: String, val quantity: Int)

返回实体类:

routing {
        val model = MyEntity(777, "Cargo", listOf(ChildEntity("Qube", 1), ChildEntity("Sphere", 2), ChildEntity(uc, 3)))

        get("/gsonEntity") {
            call.respond(model)
        }
        post("/gsonEntity") {
            val entity = call.receive<MyEntity>()
            call.respond(entity.toString())
        }

    }

打开:http://0.0.0.0:8080/gsonEntity 查看返回结果:
这里写图片描述

三、freemarker写html页面:

freemarker就是用来。。。拷贝一下官方文档:

Apache FreeMarker™是一个模板引擎:一个Java库,用于根据模板和更改数据生成文本输出(HTML网页,电子邮件,配置文件,源代码等)。 模板是用FreeMarker模板语言(FTL)编写的,这是一种简单的专用语言(不像PHP这样的完整编程语言)。 通常,使用通用编程语言(如Java)来准备数据(发布数据库查询,进行业务计算)。 然后,Apache FreeMarker使用模板显示准备好的数据。 在模板中,您将关注如何呈现数据,而在模板之外,您将关注于要呈现的数据。

嗯,果然正经多了。

1、构建freemarker:

compile "io.ktor:ktor-freemarker:$ktor_version"

新建ftl文件:
这里写图片描述

这个ftl文件就和我们用过html一样。idea里支持ftl的格式,可以直接格式化代码。

2、编写页面:

<#-- @ftlvariable name="data" type="com.example.IndexData" -->
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
hahaha
<ul>
        <#list data.items as item>
            <li>${item}</li>
        </#list>
</ul>
</body>
</html>

3、返回页面

在module里面写:

install(FreeMarker) {//引入freemark并指定加载的文件夹
        templateLoader = ClassTemplateLoader(this::class.java.classLoader, "templates")
    }
routing {//返回index.ftl的内容,并
        get("/freemarker") {
            call.respond(FreeMarkerContent("index.ftl", mapOf("data" to IndexData(listOf(1, 2, 3))), ""))
        }
    }
data class IndexData(val items: List<Int>)

以上代码就是,我们先引入freemarker框架,然后返回index.ftl。并且传个参数data。
打开:http://0.0.0.0:8080/freemarker 查看结果:
这里写图片描述

开发html的时候,写完html可以直接浏览器预览,很方便,那ftl文件可以吗?
ftl文件也是可以写完之后马上看到结果的:
这里写图片描述
我们在ftl页面右击(mac双击),然后选择Recompile,就行了。

freemarker内部是利用管道原理和buffwriter实现的:我又得复习了:

package io.ktor.freemarker

import freemarker.template.*
import io.ktor.application.*
import io.ktor.cio.*
import io.ktor.content.*
import io.ktor.http.*
import io.ktor.response.*
import io.ktor.util.*
import kotlinx.coroutines.experimental.io.*

class FreeMarkerContent(val template: String,
                        val model: Any?,
                        val etag: String? = null,
                        val contentType: ContentType = ContentType.Text.Html.withCharset(Charsets.UTF_8))

class FreeMarker(val config: Configuration) {
    companion object Feature : ApplicationFeature<ApplicationCallPipeline, Configuration, FreeMarker> {
        override val key = AttributeKey<FreeMarker>("freemarker")

        override fun install(pipeline: ApplicationCallPipeline, configure: Configuration.() -> Unit): FreeMarker {
            val config = Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).apply(configure)
            val feature = FreeMarker(config)
            pipeline.sendPipeline.intercept(ApplicationSendPipeline.Transform) { value ->
                if (value is FreeMarkerContent) {
                    val response = feature.process(value)
                    proceedWith(response)
                }
            }
            return feature
        }
    }

    private fun process(content: FreeMarkerContent): FreeMarkerOutgoingContent {
        return FreeMarkerOutgoingContent(config.getTemplate(content.template), content.model, content.etag, content.contentType)
    }

    private class FreeMarkerOutgoingContent(val template: Template,
                                            val model: Any?,
                                            etag: String?,
                                            override val contentType: ContentType) : OutgoingContent.WriteChannelContent() {
        override suspend fun writeTo(channel: ByteWriteChannel) {
            channel.bufferedWriter(contentType.charset() ?: Charsets.UTF_8).use {
                template.process(model, it)
            }
        }

        init {
            if (etag != null)
                versions += EntityTagVersion(etag)
        }
    }
}

四、html-dsl写html页面:

1、还是老样子,配置gradle:其实这个可以在构建项目的时候,直接勾选的。

compile "io.ktor:ktor-html-builder:$ktor_version"
compile "org.jetbrains:kotlin-css-jvm:1.0.0-pre.31-kotlin-1.2.41"

2、敲代码,还是那个module:写个 routing {}

get("/html-dsl") {
            call.respondHtml {
                head { link(rel = "stylesheet", href = "/styles.css") }
                body {
                    h1 { +"HTML" }
                    ul {
                        for (n in 1..10) {
                            li { +"$n" }
                        }
                    }
                    p { +"唉呀妈呀" }
                }
            }
        }

        get("/styles.css") {
            call.respondCss {
                body {
                    backgroundColor = Color("#aaccff")
                }
                p {
                    fontSize = 2.em
                    fontStyle = FontStyle("italic")
                }
                rule("p.myclass") {
                    color = Color.blue
                }
            }
        }

以上代码就是i写一个html并且连接自己写的css。返回css方法:

suspend inline fun ApplicationCall.respondCss(builder: CSSBuilder.() -> Unit) {
    this.respondText(CSSBuilder().apply(builder).toString(), ContentType.Text.CSS)
}

查看结果:
这里写图片描述
dsl的好处就是一旦运行起来之后,效率比html快。但是再快还能快到哪里去?我对官方给出的这个说法提出鄙视。

而且每次修改改完都要Rerun。还好官方给出了可以配置项目快速编译的方法,可以缓解一小下尴尬。

通常,重新启动服务器可能需要一些时间,因此Ktor提供了一个基本的自动重载工具,可以重新加载Application类。

ktor说的:

Autoreload在Java 9中不起作用。如果您想使用它,请立即坚持使用JDK 8。
使用自动重新加载时会有性能损失。 所以请记住,您不应该在生产中或在进行基准测试时使用它。

AutoReload的文档:
https://ktor.kotlincn.net/servers/autoreload.html#java9
看不懂我再来个翻译帖。明后天发。

五、下期预告:

  1. kotlin连接数据库。
  2. 可能会有AutoReload。
  3. 会有小姐姐。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值