NATS

NATS-Server 基于docker compose部署 1 2 3 4 5 6 7 8 services: nats-main: image: nats:latest ports: - "4222:4222" - "6222:6222" - "8222:8222" restart: unless-stopped Go-NATS 引入依赖 1 go get github.com/nats-io/nats.go 发布订阅模式 在此模式下,发送者发送消息后,所有在线订阅者都能接收到消息 sub.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package main import "github.com/nats-io/nats.go" func main() { conn, err := nats.Connect("nats://ip:4222") if err != nil { return } for i := 1; i <= 2; i++ { dummy := i conn.Subscribe("hello", func(msg *nats.Msg) { fmt.Printf("消费者[%d]收到:%s\n", dummy, string(msg.Data)) }) } select {} } pub.go ...

2024-09-26 · 4 分钟 · Nebula

Kotlin协程

本文参考自Jetbrains Kotlin官方文档 引 在我看来,Kotlin可以作为Java的强化版,在引入现代化语法的同时,还完美兼容了Java丰富的生态 而协程作为Kotlin最重要的语言特性,自然不可忽视,他进一步完善了异步模型,让异步编程更加简单,优雅 由于项目需要,重新复习一下Kotlin协程并查缺补漏,并在此记录一下 协程基础 基本协程程序 1 2 3 4 5 6 7 8 fun main() { GlobalScope.launch { // 在后台启动一个新协程,并继续执行之后的代码 delay(1000L) // 非阻塞式地延迟一秒 println("World!") // 延迟结束后打印 } println("Hello,") //主线程继续执行,不受协程 delay 所影响 Thread.sleep(2000L) // 主线程阻塞式睡眠2秒,以此来保证JVM存活 } 在本段代码中,GlocalScope.launch代码块中的协程作用域为全局作用域,只要程序还在运行该协程就可以一直运行 开启协程后线程不会堵塞,即使协程没有执行完毕县城也会结束,因此要在协程结束后阻塞主线程等待协程执行完毕 delay()是一个挂起函数,挂起函数会暂停当前协程,并等待一段时间后恢复,不阻塞线程 Thread.sleep()是阻塞式函数,会阻塞当前线程,并等待一段时间后继续执行 一个线程上可以运行多个协程,挂起函数不会阻塞线程,只会将当前线程调整为执行另外一个协程,所以线程不会因为协程延时而阻塞 桥接阻塞与非阻塞 1 2 3 4 5 6 7 8 9 10 fun main() { GlobalScope.launch { // 启动一个新协程 delay(1000L) println("World!") } println("Hello,") runBlocking { delay(2000L) } } runBlocking()可以将一个协程转换为阻塞式,阻塞式代码会阻塞当前线程,直到协程执行完毕 1 2 3 4 5 6 7 8 fun main() = runBlocking<Unit> { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,") delay(2000L) } 也可以将整个函数体转换为阻塞式,阻塞式代码会阻塞当前协程,直到协程执行完毕 ...

2024-09-07 · 13 分钟 · Nebula

Kotlin & Springboot

开发技巧 代码结构 常用代码范例 工具类 统一响应结构 响应结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class ScResult<T> private constructor( private val code: Int, private val message: String, private val data: T? ) { private constructor(enum: ScResultEnum, data: T? = null) : this( enum.code, enum.message, data ) companion object { fun <T> ok(data: T? = null): ScResult<T> { return ScResult(ScResultEnum.OK, data) } fun <T> error(data: T? = null): ScResult<T> { return ScResult(ScResultEnum.INTERNAL_SERVER_ERROR, data) } fun <T> make(enum: ScResultEnum, data: T? = null): ScResult<T> { return ScResult(enum, data) } fun <T> make(code: Int, message: String, data: T? = null): ScResult<T> { return ScResult(code, message, data) } } override fun toString(): String { return "ScResult(code=$code, message='$message', data=$data)" } } 响应枚举 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 enum class ScResultEnum(val code: Int, val message: String) { OK(200, "Success"), // 请求成功 CREATED(201, "Created"), // 请求成功并且创建了新的资源 ACCEPTED(202, "Accepted"), // 请求已接受,但尚未处理 NO_CONTENT(204, "No Content"), // 请求成功,但没有返回内容 MOVED_PERMANENTLY(301, "Moved Permanently"), // 资源已永久移动到新位置 FOUND(302, "Found"), // 资源临时移动到新位置 SEE_OTHER(303, "See Other"), // 重定向到另一个 URI NOT_MODIFIED(304, "Not Modified"), // 资源未被修改 BAD_REQUEST(400, "Bad Request"), // 请求无效或格式错误 UNAUTHORIZED(401, "Unauthorized"), // 需要身份验证 FORBIDDEN(403, "Forbidden"), // 服务器拒绝请求 NOT_FOUND(404, "Not Found"), // 资源未找到 METHOD_NOT_ALLOWED(405, "Method Not Allowed"), // 请求方法不允许 NOT_ACCEPTABLE(406, "Not Acceptable"), // 服务器无法生成请求的内容 PROXY_AUTHENTICATION_REQUIRED(407, "Proxy Authentication Required"), // 需要代理身份验证 REQUEST_TIMEOUT(408, "Request Timeout"), // 请求超时 CONFLICT(409, "Conflict"), // 请求冲突 GONE(410, "Gone"), // 资源已永久删除 LENGTH_REQUIRED(411, "Length Required"), // 需要 Content-Length 头 PRECONDITION_FAILED(412, "Precondition Failed"), // 预条件失败 PAYLOAD_TOO_LARGE(413, "Payload Too Large"), // 请求体过大 URI_TOO_LONG(414, "URI Too Long"), // URI 过长 UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"), // 媒体类型不受支持 RANGE_NOT_SATISFIABLE(416, "Range Not Satisfiable"), // 请求范围不可满足 EXPECTATION_FAILED(417, "Expectation Failed"), // 期望值失败 IM_A_TEAPOT(418, "I'm a teapot"), // 只为趣味性,表示服务器是茶壶 UPGRADE_REQUIRED(426, "Upgrade Required"), // 需要升级协议 INTERNAL_SERVER_ERROR(500, "Internal Server Error"), // 服务器内部错误 NOT_IMPLEMENTED(501, "Not Implemented"), // 服务器不支持请求的方法 BAD_GATEWAY(502, "Bad Gateway"), // 网关或代理服务器收到无效响应 SERVICE_UNAVAILABLE(503, "Service Unavailable"), // 服务不可用 GATEWAY_TIMEOUT(504, "Gateway Timeout"), // 网关或代理服务器超时 HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version Not Supported"), // HTTP 版本不受支持 NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required"); // 需要网络认证 }

2024-08-17 · 2 分钟 · Nebula

Kotlin

类型 赋值 1 2 3 var <propertyName>[: <PropertyType>] [= <property_initializer>] [<getter>] [<setter>] 常规类型定义 1 2 3 4 5 6 7 8 var a1: Int = 1 //显式定义类型 var a2 = 1//默认赋值机制:若值类型等于目标类型,可省略类型 val b: String //也可以先定义后赋值 b = "1" val c: Byte = 2 var d = c.toInt()//基本类型没有子集用法 println(a.toString() + b)//不可直接进行运算,需要调用to类型方法 数字/无符号类型定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 val one = 1 // Int val threeBillion = 3000000000 // Long val oneLong = 1L // 我们也可以在数字后面添加大写字母L来表示这是一个Long类型的数值 val oneByte: Byte = 1 //Int类型数据也可以在符合其他类型范围时自动转换 val a = 1_000_000_000//通过下划线分割长数字使其更直观 val a = 0xAF//0x表示十六进制 val a = 0b1001 //0b前缀表示二进制数据,后面的1010对应着十进制的9 val b: UByte = 1u // UByte类型, 由变量提供的类型 val s: UShort = 1u // UShort类型, 由变量提供的类型 val l: ULong = 1u // ULong类型, 由变量提供的类型 val a1 = 42u // UInt类型,根据数字大小自动推断得到 val a2 = 0xFFFF_FFFF_FFFFu // ULong类型,根据数字大小自动推断得到 val a = 1UL // ULong类型,直接使用后缀标记 getter和setter定义 field表示变量的属性,可以使用getter和setter来访问 ...

2024-08-09 · 33 分钟 · Nebula

Ktor

基础入门 更改默认端口 代码配置 Application.kt 1 2 3 4 5 6 7 8 9 10 11 12 fun main() { embeddedServer( Netty, port = 8080, //更改端口 host = "0.0.0.0", module = Application::module ).start(wait = true) } fun Application.module() { configureRouting() } yaml配置 Application.kt 1 2 3 4 5 6 7 fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args) @Suppress("unused") fun Application.module() { configureRouting() } application.yaml 1 2 3 4 5 6 ktor: application: modules: - com.example.ApplicationKt.module deployment: port: 8080 添加新端点 plugins/Routing.kt ...

2024-08-09 · 4 分钟 · Nebula