使用 Kotlin 将 Vertx 和 Springboot 整合

本篇文章目的是将 Springboot 和 Vertx 进行简单整合。整合目的仅仅是为了整活,因为两个不同的东西整合在一起提升的性能并没有只使用 Vertx 性能高,因此追求高性能的话这是在我来说不推荐。而且他们不仅没有提高很多性能甚至增加了学习成本

一、整合流程

首先呢目标是将Vertx 最终整合成和使用Springboot web 一样简单的 httpserver。
步骤:

  1. 获取Springboot 所有的Bean
  2. 注册路由: 检查Bean 中是否是存在实现了 Router 的方法,并交给 router
  3. 开启服务器,等待请求

二、扫描 Bean

最终目标呢,是实现和使用Springboot 一样简便,所以就需要注解来对需要的方法进行标注

最终效果预览

@RouterController
class HelloRouter(
    val test :PlayerUnlockTechService
) {
    /**
     * 注册路由
     * 正则路由以 ^ 开始
     *
     * 方法参数可以是 routingContext 或者 router 或者 routingContext 内的任何东西。以及其他的任何东西,或者 bean
     *
     */
    @Rout("/hello")
    fun hello(response: HttpServerResponse, request: HttpServerRequest) {
        request.bodyHandler {
            response.end(test.getPlayerUnlockTechsByBuilding("BD12DC34624208045CCA1ECE32071F20").toString())
        }
    }
  1. 创建注解

主要注解有:

  • RouterController 标注类中有 Router 需要的路由实现
  • Rout 标注方法是个路由实现
  • AutoClose 标注方法执行完成后自动关闭连接
/**
 *
 * @author : zimo
 * @date : 2025/01/03
 */
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Component
annotation class RouterController


/**
 *
 * @author : zimo
 * @date : 2025/01/03
 */
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Router(
    val path: String,
    val method: String = ""
)

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class Rout(
    val path: String,
    val method: String = ""
)

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class RouterGet(
    val path: String,
    val method: String = "GET"
)

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class RouterPost(
    val path: String,
    val method: String = "POST"
)

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class RouterPut(
    val path: String,
    val method: String = "PUT"
)

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class RouterDelete(
    val path: String,
    val method: String = "DELETE"
)

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class RouterPatch(
    val path: String,
    val method: String = "PATCH"
)

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class RouterHead(
    val path: String,
    val method: String = "HEAD"
)

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class RouterOptions(
    val path: String,
    val method: String = "OPTIONS"
)

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class AutoClose
  1. 获取 Beans
    在当前类中注入 applicationContext 并通过 applicationContext.beanDefinitionNames 获取所有的 Bean
@Component
class RouterProcessor(val applicationContext: ApplicationContext) {
	/**
     * 初始化完成后的 bean 列表
     */
    private val initializedBeanInstances by lazy {
        applicationContext.beanDefinitionNames.filter {
            it != this.javaClass.simpleName && it != Connection::class.simpleName
        }.mapNotNull {
            applicationContext.getBean(it)
        }
    }
}
  1. 检测出所有的Router 方法
    检测出是否被标注为了一个 Router 方法,并注册到 router
for (method in clazz.methods) {
	if (method.isAnnotationPresent(io.github.zimoyin.ra3.annotations.Router::class.java)) {
	     val path = method.getAnnotation(io.github.zimoyin.ra3.annotations.Router::class.java).path
	     router.let {
	         if (path.startsWith("^")) it.routeWithRegex(path.replaceFirst("^", ""))
	         else it.route(path)
	         // order 可以放到注解里,这样可以动态设置了
	     }.order(0).handler {
	     	// 执行方法的封装
	         invoke(method, bean, it)
	     }
	     return
	 }
	 // ... 其他注解处理
}

三、执行Router方法

这里只有两个重点,一个是自动关闭,一个是执行方法传入的参数实例

  • 自动关闭,如果方法上存在 AutoClose 注解就在执行方法结束后尝试关闭连接
  • 方法参数,从Bean、Context 中获取。如果没有则通过上下文创建 Bean
fun invoke(method: Method, bean: Any, routingContext: RoutingContext) {
     val args = arrayListOf<Any>()
     val isHasAutoClose = method.isAnnotationPresent(AutoClose::class.java)
	// 获取方法需要的参数
     method.parameters.forEach {
         val bean0 = kotlin.runCatching { applicationContext.getBean(it.name, it.type) }.getOrNull()
             ?: kotlin.runCatching { applicationContext.getBean(it.type) }.getOrNull()

         if (bean0 != null) {
             args.add(bean0)
         } else {
             args.add(createParameter(it, routingContext))
         }
     }

     //执行方法
     try {
         routingContext.request().paramsCharset = "UTF-8"
         val result = method.invoke(bean, *args.toTypedArray())
         kotlin.runCatching {
	         // 自动关闭,如果方法上存在 `AutoClose` 注解就在执行方法结束后尝试关闭连接
	         // 获取方法的返回值,并以方法的返回值作为自动关闭的参数
             if (isHasAutoClose) {
                 val response = routingContext.response()
                 response.putHeader("content-type", "application/json")
                 if (method.returnType == Unit::class.java) {
                     response.end()
                 }
                 if (result == null) {
                     response.end()
                 }
                 if (result is String) {
                     response.end(result)
                 } else if (result is Number || result is Comparable<*>) {
                     response.end(result.toString())
                 } else {
                     kotlin.runCatching {
                         response.end(result.toJsonObject().toString())
                     }.onFailure {
                         response.end()
                         logger.debug("自动关闭连接失败", it)
                     }
                 }
             }
         }
     } catch (e: InvocationTargetException) {
         kotlin.runCatching { routingContext.response().end("Server Error!!!!") }
         logger.error("路由执行失败, $method 方法内部存在错误逻辑导致方法执行失败", e)
     } catch (e: Exception) {
         kotlin.runCatching { routingContext.response().end("Server Error!!!!") }
         logger.error("路由执行失败", e)
     }
 }

获取 routingContext 中的参数,或者创建一个参数


 private fun createParameter(value: Parameter, routingContext: RoutingContext): Any {
     val name = value.name
     val type = value.type

     when (name) {
         "res", "response", "resp" -> return routingContext.response()
         "req", "request", "requ" -> return routingContext.request()
         "body", "reqBody", "requestBody" -> return routingContext.body()
         "headers", "header", "reqHeader", "requestHeader", "reqHeaders", "requestHeaders" -> return routingContext
             .request()
             .headers()

         "query", "reqQuery", "requestQuery", "reqQueries", "requestQueries" -> return routingContext.queryParams()
         "data", "reqData", "requestData" -> return routingContext.data()
         "params", "reqParams", "requestParams" -> return routingContext.pathParams()
         "cookie", "reqCookie", "requestCookie" -> return routingContext.cookieMap()
         "session", "reqSession", "requestSession" -> return routingContext.session()
         "user", "reqUser", "requestUser" -> return routingContext.user()
         "bodyAsString", "reqBodyAsString", "requestBodyAsString" -> return routingContext.bodyAsString
         "bodyAsJson", "reqBodyAsJson", "requestBodyAsJson" -> return routingContext.bodyAsJson
         "bodyAsBuffer", "reqBodyAsBuffer", "requestBodyAsBuffer" -> return routingContext.body().buffer()
         "routingContext", "context", "routerContext", "routContext" -> return routingContext
         "rout", "router" -> return routingContext.currentRoute()
         "vertx", "vertxContext" -> return routingContext.vertx()
         "responseHeaders", "responseHeader" -> return routingContext.response().headers()
         "uri" -> return routingContext.request().uri()
         "absoluteURI" -> return routingContext.request().absoluteURI()
         "authority" -> return routingContext.request().authority()
         "isSSL", "ssl", "isSsl", "isSSl", "isssl", "SSL", "Ssl" -> return routingContext.request().isSSL
     }
	
	// 如果都不是以上的参数则创建一个
     kotlin.runCatching {
         applicationContext.autowireCapableBeanFactory.createBean(type)
     }.onSuccess {
         return it
     }
     throw IllegalArgumentException("Unable to parse parameters:$name")
 }

四、全部代码

通过 @EventListener(ApplicationReadyEvent::class) 注解来确保,该初始化方法可以在Springboot 启动完成后执行

注意: 需要提前将 Router 注册到Springboot

@Component
class RouterProcessor(val applicationContext: ApplicationContext) {

    private lateinit var router: io.vertx.ext.web.Router
    private val logger = LoggerFactory.getLogger(RouterProcessor::class.java)

    @EventListener(ApplicationReadyEvent::class)
    fun init(event: ApplicationReadyEvent) {
        kotlin.runCatching {
            router = applicationContext.getBeanByName("router")
            for (bean in initializedBeanInstances) {
                registerBean(bean)
            }
        }.onFailure {
            logger.error(" Vertx WebRouter 初始化失败: ${it.message}", it)
        }
    }

    /**
     * 初始化完成后的 bean 列表
     */
    private val initializedBeanInstances by lazy {
        applicationContext.beanDefinitionNames.filter {
            it != this.javaClass.simpleName &&
                    it != Connection::class.simpleName
        }.mapNotNull {
            applicationContext.getBean(it)
        }
    }

    fun registerBean(bean: Any) {
        val clazz = bean.javaClass

        for (method in clazz.methods) {
            runCatch {
                registerMethod(method, bean)
            }
        }
    }

    fun registerMethod(method: Method, bean: Any) {
        if (method.isAnnotationPresent(io.github.zimoyin.ra3.annotations.Router::class.java)) {
            val path = method.getAnnotation(io.github.zimoyin.ra3.annotations.Router::class.java).path
            router.let {
                if (path.startsWith("^")) it.routeWithRegex(path.replaceFirst("^", ""))
                else it.route(path)
            }.order(0).handler {
                invoke(method, bean, it)
            }
            return
        }
        if (method.isAnnotationPresent(Rout::class.java)) {
            val path = method.getAnnotation(Rout::class.java).path
            router.let {
                if (path.startsWith("^")) it.routeWithRegex(path.replaceFirst("^", ""))
                else it.route(path)
            }.order(0).handler {
                invoke(method, bean, it)
            }
            return
        }

        if (method.isAnnotationPresent(RouterPost::class.java)) {
            val path = method.getAnnotation(RouterPost::class.java).path
            router.let {
                if (path.startsWith("^")) it.postWithRegex(path.replaceFirst("^", ""))
                else it.post(path)
            }.order(0).handler {
                invoke(method, bean, it)
            }
            return
        }

        if (method.isAnnotationPresent(RouterGet::class.java)) {
            val path = method.getAnnotation(RouterGet::class.java).path
            router.let {
                if (path.startsWith("^")) it.getWithRegex(path.replaceFirst("^", ""))
                else it.get(path)
            }.order(0).handler {
                invoke(method, bean, it)
            }
            return
        }

        if (method.isAnnotationPresent(RouterPut::class.java)) {
            val path = method.getAnnotation(RouterPut::class.java).path
            router.let {
                if (path.startsWith("^")) it.putWithRegex(path.replaceFirst("^", ""))
                else it.put(path)
            }.order(0).handler {
                invoke(method, bean, it)
            }
            return
        }

        if (method.isAnnotationPresent(RouterPatch::class.java)) {
            val path = method.getAnnotation(RouterPatch::class.java).path
            router.let {
                if (path.startsWith("^")) it.patchWithRegex(path.replaceFirst("^", ""))
                else it.patch(path)
            }.order(0).handler {
                invoke(method, bean, it)
            }
            return
        }
        if (method.isAnnotationPresent(RouterPatch::class.java)) {
            val path = method.getAnnotation(RouterDelete::class.java).path
            router.let {
                if (path.startsWith("^")) it.deleteWithRegex(path.replaceFirst("^", ""))
                else it.delete(path)
            }.order(0).handler {
                invoke(method, bean, it)
            }
            return
        }
        if (method.isAnnotationPresent(RouterHead::class.java)) {
            val path = method.getAnnotation(RouterHead::class.java).path
            router.let {
                if (path.startsWith("^")) it.headWithRegex(path.replaceFirst("^", ""))
                else it.head(path)
            }.order(0).handler {
                invoke(method, bean, it)
            }
            return
        }
        if (method.isAnnotationPresent(RouterOptions::class.java)) {
            val path = method.getAnnotation(RouterOptions::class.java).path
            router.let {
                if (path.startsWith("^")) it.optionsWithRegex(path.replaceFirst("^", ""))
                else it.options(path)
            }.order(0).handler {
                invoke(method, bean, it)
            }
            return
        }
    }

    fun invoke(method: Method, bean: Any, routingContext: RoutingContext) {
        val args = arrayListOf<Any>()
        val isHasAutoClose = method.isAnnotationPresent(AutoClose::class.java)

        method.parameters.forEach {
            val bean0 = kotlin.runCatching { applicationContext.getBean(it.name, it.type) }.getOrNull()
                ?: kotlin.runCatching { applicationContext.getBean(it.type) }.getOrNull()

            if (bean0 != null) {
                args.add(bean0)
            } else {
                args.add(createParameter(it, routingContext))
            }
        }

        //执行方法
        try {
            routingContext.request().paramsCharset = "UTF-8"
            val result = method.invoke(bean, *args.toTypedArray())
            kotlin.runCatching {
                if (isHasAutoClose) {
                    val response = routingContext.response()
                    response.putHeader("content-type", "application/json")
                    if (method.returnType == Unit::class.java) {
                        response.end()
                    }
                    if (result == null) {
                        response.end()
                    }
                    if (result is String) {
                        response.end(result)
                    } else if (result is Number || result is Comparable<*>) {
                        response.end(result.toString())
                    } else {
                        kotlin.runCatching {
                            response.end(result.toJsonObject().toString())
                        }.onFailure {
                            response.end()
                            logger.debug("自动关闭连接失败", it)
                        }
                    }
                }
            }
        } catch (e: InvocationTargetException) {
            kotlin.runCatching { routingContext.response().end("Server Error!!!!") }
            logger.error("路由执行失败, $method 方法内部存在错误逻辑导致方法执行失败", e)
        } catch (e: Exception) {
            kotlin.runCatching { routingContext.response().end("Server Error!!!!") }
            logger.error("路由执行失败", e)
        }
    }

    private fun createParameter(value: Parameter, routingContext: RoutingContext): Any {
        val name = value.name
        val type = value.type

        when (name) {
            "res", "response", "resp" -> return routingContext.response()
            "req", "request", "requ" -> return routingContext.request()
            "body", "reqBody", "requestBody" -> return routingContext.body()
            "headers", "header", "reqHeader", "requestHeader", "reqHeaders", "requestHeaders" -> return routingContext
                .request()
                .headers()

            "query", "reqQuery", "requestQuery", "reqQueries", "requestQueries" -> return routingContext.queryParams()
            "data", "reqData", "requestData" -> return routingContext.data()
            "params", "reqParams", "requestParams" -> return routingContext.pathParams()
            "cookie", "reqCookie", "requestCookie" -> return routingContext.cookieMap()
            "session", "reqSession", "requestSession" -> return routingContext.session()
            "user", "reqUser", "requestUser" -> return routingContext.user()
            "bodyAsString", "reqBodyAsString", "requestBodyAsString" -> return routingContext.bodyAsString
            "bodyAsJson", "reqBodyAsJson", "requestBodyAsJson" -> return routingContext.bodyAsJson
            "bodyAsBuffer", "reqBodyAsBuffer", "requestBodyAsBuffer" -> return routingContext.body().buffer()
            "routingContext", "context", "routerContext", "routContext" -> return routingContext
            "rout", "router" -> return routingContext.currentRoute()
            "vertx", "vertxContext" -> return routingContext.vertx()
            "responseHeaders", "responseHeader" -> return routingContext.response().headers()
            "uri" -> return routingContext.request().uri()
            "absoluteURI" -> return routingContext.request().absoluteURI()
            "authority" -> return routingContext.request().authority()
            "isSSL", "ssl", "isSsl", "isSSl", "isssl", "SSL", "Ssl" -> return routingContext.request().isSSL
        }

        kotlin.runCatching {
            applicationContext.autowireCapableBeanFactory.createBean(type)
        }.onSuccess {
            return it
        }

        throw IllegalArgumentException("Unable to parse parameters:$name")
    }

    fun <T : Any> runCatch(block: () -> T): T? {
        try {
            return block()
        } catch (e: Exception) {
            logger.error("路由捕获到异常", e)
        }
        return null
    }
}

使用示例

/**
 *
 * @author : zimo
 * @date : 2025/01/04
 */
@RouterController
class HelloRouter(
    val test :PlayerUnlockTechService
) {


    /**
     * 注册路由
     * 正则路由以 ^ 开始
     * 请求处理方法: 所有
     * 方法参数可以是 routingContext 或者 router 或者 routingContext 内的任何东西。以及其他的任何东西,或者 bean
     *
     */
    @Rout("/hello")
//    @RouterGet
    fun hello(response: HttpServerResponse, request: HttpServerRequest) {
        request.bodyHandler {
            response.end(test.getPlayerUnlockTechsByBuilding("BD12DC34624208045CCA1ECE32071F20").toString())
        }
    }

    /**
     * 注册路由(并自动关闭,将返回值发送会前端)
     * 正则路由以 ^ 开始
     * 请求处理方法: GET
     * 方法参数可以是 routingContext 或者 router 或者 routingContext 内的任何东西。以及其他的任何东西,或者 bean
     *
     */
    @RouterGet("/test/send_message/:message")
     @AutoClose
    fun send(response: HttpServerResponse, request: HttpServerRequest):String {
        return "你好"
      }
    }
}

Main 方法

/**
 *
 * @author : zimo
 * @date : 2025/01/03
 */
@SpringBootApplication
@EnableCaching
@MapperScan(basePackages = ["io.github.zimoyin.ra3.mapper"])
class ApplicationStart2(
    val vertx: Vertx,
    val router: Router
) {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            runApplication<ApplicationStart2>(*args)
        }
    }

    @PostConstruct
    fun onStartVertxWeb() {
        vertx.createHttpServer().requestHandler(router).listen(8090).onSuccess {
            println("启动成功")
        }
    }
}

@Configuration
class VertxConfig {
    @Bean("vertx")
    fun vertx(): Vertx {
        return Vertx.vertx()
    }

    @Bean("router")
    fun router(vertx: Vertx): Router? {
        return Router.router(vertx)
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/964533.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Springboot框架的学术期刊遴选服务-项目演示

项目介绍 本课程演示的是一款 基于Javaweb的水果超市管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 3.该项目附…

【C++篇】位图与布隆过滤器

目录 一&#xff0c;位图 1.1&#xff0c;位图的概念 1.2&#xff0c;位图的设计与实现 1.5&#xff0c;位图的应用举例 1.4&#xff0c;位图常用应用场景 二&#xff0c;布隆过滤器 2.1&#xff0c;定义&#xff1a; 2.2&#xff0c;布隆过滤器的实现 2.3&#xff0c; 应…

GESP2023年12月认证C++六级( 第三部分编程题(1)闯关游戏)

参考程序代码&#xff1a; #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <string> #include <map> #include <iostream> #include <cmath> using namespace std;const int N 10…

list容器(详解)

list的介绍及使用&#xff08;了解&#xff0c;后边细讲&#xff09; 1.1 list的介绍&#xff08;双向循环链表&#xff09; https://cplusplus.com/reference/list/list/?kwlist&#xff08;list文档介绍&#xff09; 1. list是可以在常数范围内在任意位置进行插入和删除的序…

RGB565转BITMAP[C#---2]

这是楼主在开发C#上位机的时候遇到的另一个问题&#xff0c;怎么把RGB565转为BITMAP&#xff0c;在CSDN上搜索&#xff0c;要么是安卓平台的&#xff0c;要么是2011年的古早代码&#xff08;还没排版&#xff09;&#xff0c;还是靠自己和DEEPSEEK的智慧解决了(●’◡’●) 当然…

pytorch实现门控循环单元 (GRU)

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 特性GRULSTM计算效率更快&#xff0c;参数更少相对较慢&#xff0c;参数更多结构复杂度只有两个门&#xff08;更新门和重置门&#xff09;三个门&#xff08;输入门、遗忘门、输出门&#xff09;处理长时依赖一般适…

【赵渝强老师】Spark RDD的依赖关系和任务阶段

Spark RDD彼此之间会存在一定的依赖关系。依赖关系有两种不同的类型&#xff1a;窄依赖和宽依赖。 窄依赖&#xff1a;如果父RDD的每一个分区最多只被一个子RDD的分区使用&#xff0c;这样的依赖关系就是窄依赖&#xff1b;宽依赖&#xff1a;如果父RDD的每一个分区被多个子RD…

为何在Kubernetes容器中以root身份运行存在风险?

作者:马辛瓦西奥内克(Marcin Wasiucionek) 引言 在Kubernetes安全领域,一个常见的建议是让容器以非root用户身份运行。但是,在容器中以root身份运行,实际会带来哪些安全隐患呢?在Docker镜像和Kubernetes配置中,这一最佳实践常常被重点强调。在Kubernetes清单文件中,…

Docker 安装详细教程(适用于CentOS 7 系统)

目录 步骤如下&#xff1a; 1. 卸载旧版 Docker 2. 配置 Docker 的 YUM 仓库 3. 安装 Docker 4. 启动 Docker 并验证安装 5. 配置 Docker 镜像加速 总结 前言 Docker 分为 CE 和 EE 两大版本。CE即社区版&#xff08;免费&#xff0c;支持周期7个月&#xff09;&#xf…

[MRCTF2020]Ez_bypass1(md5绕过)

[MRCTF2020]Ez_bypass1(md5绕过) ​​ 这道题就是要绕过md5强类型比较&#xff0c;但是本身又不相等&#xff1a; md5无法处理数组&#xff0c;如果传入的是数组进行md5加密&#xff0c;会直接放回NULL&#xff0c;两个NuLL相比较会等于true&#xff1b; 所以?id[]1&gg…

Deep Crossing:深度交叉网络在推荐系统中的应用

实验和完整代码 完整代码实现和jupyter运行&#xff1a;https://github.com/Myolive-Lin/RecSys--deep-learning-recommendation-system/tree/main 引言 在机器学习和深度学习领域&#xff0c;特征工程一直是一个关键步骤&#xff0c;尤其是对于大规模的推荐系统和广告点击率预…

C++多线程编程——基于策略模式、单例模式和简单工厂模式的可扩展智能析构线程

1. thread对象的析构问题 在 C 多线程标准库中&#xff0c;创建 thread 对象后&#xff0c;必须在对象析构前决定是 detach 还是 join。若在 thread 对象销毁时仍未做出决策&#xff0c;程序将会终止。 然而&#xff0c;在创建 thread 对象后、调用 join 前的代码中&#xff…

Rust中使用ORM框架diesel报错问题

1 起初环境没有问题&#xff1a;在Rust开发的时候起初使用的是mingw64平台加stable-x86_64-pc-windows-gnu编译链&#xff0c;当使用到diesel时会报错&#xff0c;如下&#xff1a; x86_64-w64-mingw32/bin/ld.exe: cannot find -lmysql具体信息很长这是主要信息是rust找不到链…

Fastdds学习分享_xtpes_发布订阅模式及rpc模式

在之前的博客中我们介绍了dds的大致功能&#xff0c;与组成结构。本篇博文主要介绍的是xtypes.分为理论和实际运用两部分.理论主要用于梳理hzy大佬的知识&#xff0c;对于某些一带而过的部分作出更为详细的阐释&#xff0c;并在之后通过实际案例便于理解。案例分为普通发布订阅…

Windows:AList+RaiDrive挂载阿里云盘至本地磁盘

零、前言 电脑存储的文件多了&#xff0c;出现存储空间不够用的情况。又没前买新的硬盘或者笔记本电脑没有额外的插槽提供给新的硬盘。遇到这种情况&#xff0c;我想到可以使用网盘&#xff0c;但单纯的网盘又要上传下载&#xff0c;极其麻烦。看到WPS云盘可以直接挂载本地&…

Unity游戏(Assault空对地打击)开发(3) 摄像机的控制

详细步骤 打开My Assets或者Package Manager。 选择Unity Registry。 搜索Cinemachine&#xff0c;找到 Cinemachine包&#xff0c;点击 Install按钮进行安装。 关闭窗口&#xff0c;新建一个FreeLook Camera&#xff0c;如下。 接着新建一个对象Pos&#xff0c;拖到Player下面…

保姆级教程Docker部署Zookeeper官方镜像

目录 1、安装Docker及可视化工具 2、创建挂载目录 3、运行Zookeeper容器 4、Compose运行Zookeeper容器 5、查看Zookeeper运行状态 6、验证Zookeeper是否正常运行 1、安装Docker及可视化工具 Docker及可视化工具的安装可参考&#xff1a;Ubuntu上安装 Docker及可视化管理…

力扣73矩阵置零

给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 输入&#xff1a;matrix [[0,1,2,0],[3,4,5,2],[…

【ArcGIS_Python】使用arcpy脚本将shape数据转换为三维白膜数据

说明&#xff1a; 该专栏之前的文章中python脚本使用的是ArcMap10.6自带的arcpy&#xff08;好几年前的文章&#xff09;&#xff0c;从本篇开始使用的是ArcGIS Pro 3.3版本自带的arcpy&#xff0c;需要注意不同版本对应的arcpy函数是存在差异的 数据准备&#xff1a;准备一个…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.19 线性代数核武器:BLAS/LAPACK深度集成

2.19 线性代数核武器&#xff1a;BLAS/LAPACK深度集成 目录 #mermaid-svg-yVixkwXWUEZuu02L {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-yVixkwXWUEZuu02L .error-icon{fill:#552222;}#mermaid-svg-yVixkwXWUEZ…