Javalin解构

news2024/11/17 23:24:27

Javalin

Javalin是一个轻量级http框架,我们可以很容易的了解请求的处理过程及其设计,具有较高的学习意义。

从demo说起

public static void main(String[] args) {
        Javalin app = Javalin.create(config -> {
            System.out.println("用户配置");
        });
        app.get("/", ctx -> {
            System.out.println("do" + ctx.path());
            ctx.result("Hello World");
        });

        // 处理异常
        app.exception(Exception.class, (e, ctx) -> {
            ctx.result("发生异常了");
        });
        // 处理异常状态
        app.error(404, ctx -> {
            ctx.html("Generic 404 message");
        });
        // 测试异常
        app.get("/exception/{e}", ctx -> {
            String msg = ctx.pathParam("e");
            if ("1".equals(msg)) {
                throw new InvalidAlgorithmParameterException("测试异常");
            } else if ("2".equals(msg)) {
                throw new ClassNotFoundException("Invalid");
            } else if ("3".equals(msg)) {
                ctx.status(404);
            } else {
                throw new Exception("Invalid algorithm parameter");
            }
        });
        //get请求{}参数解析
        app.get("/path/<path>", ctx -> ctx.result("Hello Path2 " + ctx.pathParam("path")));
        //post请求
        app.post("/json", ctx -> {
            Map<String, String> map = new HashMap<>();
            map.put("name", "张三");
            ctx.json(map);
        });
        //get请求<>参数解析
        app.get("/name/{name}", ctx -> {
            NaiveRateLimit.requestPerTimeUnit(ctx, 5, TimeUnit.MINUTES);
            ctx.result("Hello Path " + ctx.pathParam("name"));
        });
        // webscoket
        app.ws("/websocket/{path}", ws -> {
            ws.onConnect(ctx -> System.out.println("Connected"));
            ws.onMessage(ctx -> {
                System.out.println("收到消息" + ctx.message());
                ctx.send("我收到了" + ctx.message());
            });
        });
        // 前置处理器
        app.before(ctx -> System.out.println("before" + ctx.path()));
        // 后置处理器
        app.after(ctx -> System.out.println("after" + ctx.path()));
        // 启动
        app.start(7070);
    }

创建Javalin实例

使用代码

Javalin app = Javalin.create(config -> {
            System.out.println("用户配置");
        });

实现原理

实现源码

    public static Javalin create(Consumer<JavalinConfig> config) {
        // 初始化示例对象
        Javalin app = new Javalin();
        // 加载用户配置
        JavalinConfig.applyUserConfig(app, app.cfg, config); // mutates app.config and app (adds http-handlers)
        // 延迟检测服务是否正常启动
        JettyUtil.maybeLogIfServerNotStarted(app.jettyServer);
        return app;
    }

流程
在这里插入图片描述

get/post/websocket/before/after配置

使用方式

 app.get("/", ctx -> {
            System.out.println("do" + ctx.path());
            ctx.result("Hello World");
        });

实现源码

    public Javalin get(@NotNull String path, @NotNull Handler handler) {
        return addHandler(HandlerType.GET, path, handler);
    }
    public Javalin addHandler(@NotNull HandlerType httpMethod, @NotNull String path, @NotNull Handler handler) {
        return addHandler(httpMethod, path, handler, new RouteRole[0]); // no roles set for this route (open to everyone with default access manager)
    }
   public Javalin addHandler(@NotNull HandlerType handlerType, @NotNull String path, @NotNull Handler handler, @NotNull RouteRole... roles) {
        Set<RouteRole> roleSet = new HashSet<>(Arrays.asList(roles));
        javalinServlet.getMatcher().add(new HandlerEntry(handlerType, path, cfg.routing, roleSet, handler));
        eventManager.fireHandlerAddedEvent(new HandlerMetaInfo(handlerType, Util.prefixContextPath(cfg.routing.contextPath, path), handler, roleSet));
      return this;
    }

添加流程
在这里插入图片描述
get/post/websocket/before/after处理器都是这个类型,只是请求类型不一致,
http支持的请求类型有

GET, POST, PUT, PATCH, DELETE, HEAD, TRACE, CONNECT, OPTIONS, BEFORE, AFTER, INVALID;

websocket支持的请求类型有

 WS_BEFORE, WEBSOCKET, WS_AFTER

exceptionHandler配置

使用方式

        // 处理异常
        app.exception(Exception.class, (e, ctx) -> {
            ctx.result("发生异常了");
        });

实现源码

    public <T extends Exception> Javalin exception(@NotNull Class<T> exceptionClass, @NotNull ExceptionHandler<? super T> exceptionHandler) {
        javalinServlet.getExceptionMapper().getHandlers().put(exceptionClass, (ExceptionHandler<Exception>) exceptionHandler);
        return this;
    }

添加流程
在这里插入图片描述

errorHandler配置

使用方式

        // 处理异常状态
        app.error(404, ctx -> {
            ctx.html("Generic 404 message");
        });

实现源码

    public Javalin error(int status, @NotNull String contentType, @NotNull Handler handler) {
        javalinServlet.getErrorMapper().addHandler(status, contentType, handler);
        return this;
    }

添加流程
在这里插入图片描述

权限管理配置

使用方式

// Set the access-manager that Javalin should use
config.accessManager((handler, ctx, routeRoles) -> {
    MyRole userRole = getUserRole(ctx);
    if (routeRoles.contains(userRole)) {
        handler.handle(ctx);
    } else {
        ctx.status(401).result("Unauthorized");
    }
});

Role getUserRole(Context ctx) {
    // determine user role based on request.
    // typically done by inspecting headers, cookies, or user session
}

enum Role implements RouteRole {
    ANYONE, ROLE_ONE, ROLE_TWO, ROLE_THREE;
}

app.get("/un-secured",   ctx -> ctx.result("Hello"),   Role.ANYONE);
app.get("/secured",      ctx -> ctx.result("Hello"),   Role.ROLE_ONE);

实现源码

    fun accessManager(accessManager: AccessManager) { pvt.accessManager = accessManager }

设置流程
在这里插入图片描述

启动流程

使用方式

// 启动
app.start(7070);

源码

    public Javalin start(int port) {
        // 设置端口号
        jettyServer.setServerPort(port);
        // 启动服务
        return start();
    }

start()

public Javalin start() {
        // 记录启动开始时间
        long startupTimer = System.currentTimeMillis();
        // 如果已经启动了就报错
        if (jettyServer.started) {
            String message = "Server already started. If you are trying to call start() on an instance " +
                "of Javalin that was stopped using stop(), please create a new instance instead.";
            throw new IllegalStateException(message);
        }
        // 标识服务已经启动
        jettyServer.started = true;
        // 检测日志组件是否引入
        Util.printHelpfulMessageIfLoggerIsMissing();
        // 触发服务启动中事件
        eventManager.fireEvent(JavalinEvent.SERVER_STARTING);
        try {
            // 打印服务启动中
            JavalinLogger.startup("Starting Javalin ...");
            // 启动jetty服务
            jettyServer.start(javalinJettyServlet);
            // 打印javlin和java版本
            Util.logJavalinVersion();
            // 打印服务已经启动和耗时
            JavalinLogger.startup("Javalin started in " + (System.currentTimeMillis() - startupTimer) + "ms \\o/");
            // 发布服务已启动事件
            eventManager.fireEvent(JavalinEvent.SERVER_STARTED);
        } catch (Exception e) {
            // 打印服务启动异常
            JavalinLogger.error("Failed to start Javalin");
            // 发布服务启动失败事件
            eventManager.fireEvent(JavalinEvent.SERVER_START_FAILED);
            // 如果jetty已启动成功了,则停止服务
            if (Boolean.TRUE.equals(jettyServer.server().getAttribute("is-default-server"))) {
                stop();// stop if server is default server; otherwise, the caller is responsible to stop
            }
            if (e.getMessage() != null && e.getMessage().contains("Failed to bind to")) {
                // 端口冲突
                throw new JavalinBindException("Port already in use. Make sure no other process is using port " + Util.getPort(e) + " and try again.", e);
            } else if (e.getMessage() != null && e.getMessage().contains("Permission denied")) {
                // 权限不足
                throw new JavalinBindException("Port 1-1023 require elevated privileges (process must be started by admin).", e);
            }
            // 其他异常
            throw new JavalinException(e);
        }
        return this;
    }

其中核心逻辑在jettyServer.start(javalinJettyServlet);中
jettyServer.start(javalinJettyServlet);

   fun start(wsAndHttpServlet: JavalinJettyServlet) {
        // 如果未设置端口则设置为8080端口
        if (serverPort == -1 && cfg.pvt.server == null) {
            serverPort = 8080
            JavalinLogger.startup("No port specified, starting on port $serverPort. Call start(port) to change ports.")
        }
        // 初始化默认sessionHandler管理session
        cfg.pvt.sessionHandler = cfg.pvt.sessionHandler ?: defaultSessionHandler()
        val nullParent = null // javalin handlers are orphans
        // 定义jetty请求处理器
        val wsAndHttpHandler = object : ServletContextHandler(nullParent, Util.normalizeContextPath(cfg.routing.contextPath), SESSIONS) {
            override fun doHandle(target: String, jettyRequest: Request, request: HttpServletRequest, response: HttpServletResponse) {
                request.setAttribute("jetty-target-and-request", Pair(target, jettyRequest)) // used in JettyResourceHandler
                nextHandle(target, jettyRequest, request, response)
            }
        }.apply {
            this.sessionHandler = cfg.pvt.sessionHandler
            cfg.pvt.servletContextHandlerConsumer?.accept(this)
            // 设置所有路径处理器
            addServlet(ServletHolder(wsAndHttpServlet), "/*")
            // 初始化websocket处理器
            JettyWebSocketServletContainerInitializer.configure(this) { _, _ ->
                /* we don't want to configure WebSocketMappings during ServletContext initialization phase */
            }
        }
        // 初始化jetty服务,并设置处理器
        server().apply {
            handler = if (handler == null) wsAndHttpHandler else handler.attachHandler(wsAndHttpHandler)
            if (connectors.isEmpty()) { // user has not added their own connectors, we add a single HTTP connector
                connectors = arrayOf(defaultConnector(this))
            }
        }.start()
        // 打印javalin logo
        logJavalinBanner(cfg.showJavalinBanner)
        // 打印是否使用Loom(Java虚拟线程)
        LoomUtil.logIfLoom(server())

        // 初始化资源处理器
        (cfg.pvt.resourceHandler as? JettyResourceHandler)?.init() // we want to init this here to get logs in order

        // 打印服务使用的ip和端口
        server().connectors.filterIsInstance<ServerConnector>().forEach {
            JavalinLogger.startup("Listening on ${it.protocol}://${it.host ?: "localhost"}:${it.localPort}${cfg.routing.contextPath}")
        }
        // 非http服务打印绑定的端口
        server().connectors.filter { it !is ServerConnector }.forEach {
            JavalinLogger.startup("Binding to: $it")
        }
        // 设置服务启动的端口号
        serverPort = (server().connectors[0] as? ServerConnector)?.localPort ?: -1
    }

启动流程
在这里插入图片描述

请求处理流程

处理请求的入口
JavalinJettyServlet.service
这个类既处理http也处理websocket

override fun service(req: HttpServletRequest, res: HttpServletResponse) { // this handles both http and websocket
        // 判断是否有websocket请求标识
        if (req.getHeader(Header.SEC_WEBSOCKET_KEY) == null) { // this isn't a websocket request
            // http请求处理
            return httpServlet.service(req, res) // treat as normal HTTP request
        }
        // 去除项目路径前缀
        val requestUri = req.requestURI.removePrefix(req.contextPath)
        // 查找url对应后端处理器
        val entry = wsPathMatcher.findEndpointHandlerEntry(requestUri) ?: return res.sendError(404, "WebSocket handler not found")
        // 构建请求处理的上下文
        val upgradeContext = JavalinServletContext(
            req = req,
            res = res,
            cfg = cfg,
            matchedPath = entry.path,
            pathParamMap = entry.extractPathParams(requestUri),
        )
        // 校验权限
        if (!allowedByAccessManager(entry, upgradeContext)) return res.sendError(HttpStatus.UNAUTHORIZED.code, HttpStatus.UNAUTHORIZED.message)
        // 设置上下文
        req.setAttribute(upgradeContextKey, upgradeContext)
        // 设置协议头
        setWsProtocolHeader(req, res)
        // 处理websocket请求
        super.service(req, res) // everything is okay, perform websocket upgrade
    }

从源码可以知道http请求又调了JavalinServlet.service进行处理,websocket
掉jetty进行处理,会回调这个类型configure方法,因为这类继承了JettyWebSocketServlet类。
接下来先介绍http请求处理部分
JavalinServlet.service

override fun service(request: HttpServletRequest, response: HttpServletResponse) {
        try {
            // 构建请求处理的上下文
            val ctx = JavalinServletContext(req = request, res = response, cfg = cfg)
            // 定义请求处理的任务列表添加函数,添加到头部还是尾部
            val submitTask: (SubmitOrder, Task) -> Unit = { order, task ->
                when (order) {
                    FIRST -> ctx.tasks.offerFirst(task)
                    LAST -> ctx.tasks.add(task)
                }
            }
            // 去除项目的上下文路径
            val requestUri = ctx.path().removePrefix(ctx.contextPath())
            // 生成请求处理的任务列表(生成任务的最终顺序如下表)
            cfg.pvt.servletRequestLifecycle.forEach { it.createTasks(submitTask, this, ctx, requestUri) }
            // 处理请求
            ctx.handleSync()
        } catch (throwable: Throwable) {
            // 兜底异常处理
            exceptionMapper.handleUnexpectedThrowable(response, throwable)
        }
    }
处理器类型是否跳过异常
BEFORE
HTTP
ERROR
AFTER

再看下处理请求部分

    private fun JavalinServletContext.handleSync() {
        while (userFutureSupplier == null && tasks.isNotEmpty()) {
            // 取出第一个任务
            val task = tasks.poll()
            // 判断是否发生过异常且是否跳过异常
            if (exceptionOccurred && task.skipIfExceptionOccurred) {
                continue
            }
            // 处理任务
            handleTask(task.handler)
        }
        when {
            // 异步处理的请求
            userFutureSupplier != null -> handleUserFuture()
            // 非异步处理的请求,写入结果并打印日志
            else -> writeResponseAndLog()
        }
    }
      private fun <R> JavalinServletContext.handleTask(handler: TaskHandler<R>): R? =
        try {
            handler.handle()
        } catch (throwable: Throwable) {
            exceptionOccurred = true
            userFutureSupplier = null
            tasks.offerFirst(Task(skipIfExceptionOccurred = false) { exceptionMapper.handle(this, throwable) })
            null
        }

然后在看下websocket的处理过程
首先调用configure完成连接初始化
JavalinJettyServlet.configure

    // websocket初始化连接
    override fun configure(factory: JettyWebSocketServletFactory) { // this is called once, before everything
        cfg.pvt.wsFactoryConfig?.accept(factory)
        factory.setCreator(JettyWebSocketCreator { req, _ -> // this is called when a websocket is created (after [service])
            val preUpgradeContext = req.httpServletRequest.getAttribute(upgradeContextKey) as JavalinServletContext
            req.httpServletRequest.setAttribute(upgradeContextKey, preUpgradeContext.changeBaseRequest(req.httpServletRequest))
            val session = req.session as? Session?
            req.httpServletRequest.setAttribute(upgradeSessionAttrsKey, session?.attributeNames?.asSequence()?.associateWith { session.getAttribute(it) })
            // 初始化连接
            return@JettyWebSocketCreator WsConnection(wsPathMatcher, wsExceptionMapper, cfg.pvt.wsLogger)
        })
    }

重点看下WsConnection类

 @OnWebSocketConnect
    fun onConnect(session: Session) {
        // websocket连接初始化
        val ctx = WsConnectContext(sessionId, session)
        tryBeforeAndEndpointHandlers(ctx) { it.wsConfig.wsConnectHandler?.handleConnect(ctx) }
        tryAfterHandlers(ctx) { it.wsConfig.wsConnectHandler?.handleConnect(ctx) }
        wsLogger?.wsConnectHandler?.handleConnect(ctx)
    }

    @OnWebSocketMessage
    fun onMessage(session: Session, message: String) {
        // 收到文本消息
        val ctx = WsMessageContext(sessionId, session, message)
        tryBeforeAndEndpointHandlers(ctx) { it.wsConfig.wsMessageHandler?.handleMessage(ctx) }
        tryAfterHandlers(ctx) { it.wsConfig.wsMessageHandler?.handleMessage(ctx) }
        wsLogger?.wsMessageHandler?.handleMessage(ctx)
    }

    @OnWebSocketMessage
    fun onMessage(session: Session, buffer: ByteArray, offset: Int, length: Int) {
        // 收到二进制消息
        val ctx = WsBinaryMessageContext(sessionId, session, buffer, offset, length)
        tryBeforeAndEndpointHandlers(ctx) { it.wsConfig.wsBinaryMessageHandler?.handleBinaryMessage(ctx) }
        tryAfterHandlers(ctx) { it.wsConfig.wsBinaryMessageHandler?.handleBinaryMessage(ctx) }
        wsLogger?.wsBinaryMessageHandler?.handleBinaryMessage(ctx)
    }

    @OnWebSocketClose
    fun onClose(session: Session, statusCode: Int, reason: String?) {
        // 连接关闭
        val ctx = WsCloseContext(sessionId, session, statusCode, reason)
        tryBeforeAndEndpointHandlers(ctx) { it.wsConfig.wsCloseHandler?.handleClose(ctx) }
        tryAfterHandlers(ctx) { it.wsConfig.wsCloseHandler?.handleClose(ctx) }
        wsLogger?.wsCloseHandler?.handleClose(ctx)
        ctx.disableAutomaticPings()
    }

    @OnWebSocketError
    fun onError(session: Session, throwable: Throwable?) {
        // 发生异常
        val ctx = WsErrorContext(sessionId, session, throwable)
        tryBeforeAndEndpointHandlers(ctx) { it.wsConfig.wsErrorHandler?.handleError(ctx) }
        tryAfterHandlers(ctx) { it.wsConfig.wsErrorHandler?.handleError(ctx) }
        wsLogger?.wsErrorHandler?.handleError(ctx)
    }

采用注解形式定义一系列websocket操作
请求处理流程
在这里插入图片描述

总结

至此,主要处理流程都介绍完毕,还有部分异步请求的处理下次再更新。最后附上Jetty核心组件结构图

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java——N叉树的层序遍历

题目链接 leetcode在线oj题——N叉树的层序遍历 题目描述 给定一个 N 叉树&#xff0c;返回其节点值的层序遍历。&#xff08;即从左到右&#xff0c;逐层遍历&#xff09;。 树的序列化输入是用层序遍历&#xff0c;每组子节点都由 null 值分隔&#xff08;参见示例&…

网络基础(三)

目录 网络层与数据链路层 ​编辑 网络层 IP协议 IP的构成 TCP和IP各自解决什么问题&#xff1f; 基本概念 协议头格式 协议头分析 如何分离与封装&#xff1f; 如何分用(向上交付)&#xff1f; 16位首部校验和 32位源IP和目的IP 4位版本 8位服务类型(Type Of…

【计算机】单位制前缀的歧义-KB、kb、MB混用

引言 经常遇到容量、带宽的单位&#xff0c;MB&#xff0c;GB在进行单位换算时&#xff0c;总是傻傻分不清&#xff0c;查些资料浅记录一下。 公制&#xff08;metric system&#xff09; 又译米制&#xff0c;是一个国际化十进位量度系统。法国在1799年开始使用公制&#xf…

【微信小程序】-- 页面导航 -- 声明式导航(二十二)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

maven生命周期、阶段与默认绑定插件梳理

maven生命周期、阶段与默认绑定插件梳理 CSDN博客 码云源码 1.maven生命周期、阶段与默认绑定插件 序号生命周期lifecycle阶段phase默认绑定插件(链接官网)默认绑定插件(链接maven库)说明1cleancleanmaven-clean-pluginmaven-clean-plugin清理2.1buildvalidate——验证2.2b…

Unity记录1.1-入门-下载与创建项目

文章首发及后续更新&#xff1a;https://mwhls.top/4439.html&#xff0c;无图/无目录/格式错误/更多相关请至首发页查看。 新的更新内容请到mwhls.top查看。 欢迎提出任何疑问及批评&#xff0c;非常感谢&#xff01; 汇总&#xff1a;Unity 记录 写的很简略&#xff0c;因为不…

【数据挖掘与商务智能决策】第一章 数据分析与三重工具

numpy基础 numpy与数组 import numpy as np # 用np代替numpy,让代码更简洁 a [1, 2, 3, 4] # 创建列表a b np.array([1, 2, 3, 4]) #从列表ach print(a) print(b) print(type(a)) #打印a类型 print(type(b)) #打印b类型[1, 2, 3, 4] [1 2 3 4] <class ‘list’>…

目标检测: 数据增强代码详解

1. 常见的数据增强 1.1 翻转图像 左右水平翻转 假设图片的宽高为w,h,bdbox左上角A坐标为(x1,y1), 右下角B为(x2,y2)。经过左右水平翻转后,bdbox的左上角A1坐标(w-x2,y1) ,右下角B1坐标为(w-x1,y2)左右水平翻转的代码实现如下:from PIL import Image image = Image.open(i…

xmu 离散数学 卢杨班作业详解【4-7章】

文章目录第四章 二元关系和函数4.6.2911121618.120.222.1232834第五章 代数系统的一般概念2判断二元运算是否封闭348111214第六章 几个典型的代数系统1.5.6.7.11.12151618第七章 图的基本概念12479111215第四章 二元关系和函数 4. A{1,2,3} 恒等关系 IA{<1,1>,<2,2…

微服务到云原生

微服务到云原生 微服务 微服务架构&#xff08;Microservice Architecture&#xff09;是一种架构概念&#xff0c;旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦。 微服务是一种架构风格&#xff0c;一个大型复杂软件应用由一个或多个微服务组成。系统中的各…

为什么Gateway网关引入了LoadBalancer组件就拥有了负载均衡能力?

1、思考&#xff1a;一般而言&#xff0c;当我们在项目中引入了 LoadBalancer 负载均衡启动器组件&#xff0c;那么SpringBoot自动配置的ClassPath类路径加载机制会扫描到 LoadBalancer 类路径下的 spring.factories 配置文件&#xff0c;会注册一些Bean &#xff0c;但为什么网…

Java开发环境搭配

#Java开发环境搭建 oracle官网下载java https://www.oracle.com/cn/ 下载匹配电脑系统的版本 注意&#xff1a;安装路径不要包含中文 #JDK环境变量配置&#xff08;win10&#xff09; path 是一个常见的环境变量&#xff0c;它告诉系统除了在当前目录下寻找此程序外&#…

kafka3.0安装使用

一&#xff1a;定义 Kafka传 统定义&#xff1a;Kafka是一个分布式的基于发布/订阅模式的消息队列&#xff08;Message Queue&#xff09;&#xff0c;主要应用于大数据实时处理领域。 Kafka最 新定义 &#xff1a; Kafka是 一个开源的 分 布式事件流平台 &#xff08;Event St…

安卓反编译入门01-apktool反编译使用流程

apktool反编译使用流程1.获取工具apktool反编译 APK&#xff0c;首先要有工具apktool.jar apktool下载地址&#xff1a;https://bitbucket.org/iBotPeaches/apktool/downloads作者github 地址&#xff1a;https://github.com/iBotPeaches/Apktool无脑下最新版就行了。将下载好的…

计算机网络协议详解(一)

文章目录&#x1f525;计算机网络通信&#x1f525;TCP/IP协议群&#x1f525;TCP协议传输特点&#x1f525;服务端口&#x1f525;数据包与处理流程&#x1f525;计算机网络通信 什么是通信协议 简单来说&#xff0c;通信协议就是计算机之间通过网络实现通信时事先达成的一种…

陀螺仪小车(Forerake-Car)

项目简介&#xff1a;搭建一辆有arduino UNO 与rnf24l01组成的小车&#xff1b;手部安装由arduino nano开发板、nrf24l01、imu构成的手势控制器&#xff0c;利用手势控制器检测手部状态、发送信号对小车进行前进&#xff0c;实现基于卡尔曼滤波的MPU6050姿态结算。 准备工作&am…

蓝桥杯2023/3/2

1. 小蓝正在学习一门神奇的语言&#xff0c;这门语言中的单词都是由小写英文字母组 成&#xff0c;有些单词很长&#xff0c;远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词&#xff0c;他准备不再完全记忆这些单词&#xff0c;而是根据单词中哪个字母出现得最…

格密码学习笔记(一):格的定义、基本区域和行列式

文章目录格的基本定义格的基本区域格的行列式致谢格的基本定义 定义1 给定nnn维实数空间Rn\mathbb{R}^nRn中的一组线性无关向量B{b1,…,bn}⊂Rn\bm{B} \{ \bm{b}_1, \dots, \bm{b}_n \} \subset \mathbb{R}^nB{b1​,…,bn​}⊂Rn&#xff0c;其整数系数线性组合构成的集合被称…

列表(list)、数组(numpy)、张量(tensor)、元组各自怎样查看形状

列表&#xff08;list&#xff09;、数组&#xff08;numpy&#xff09;、张量&#xff08;tensor&#xff09;、元组各自怎样查看形状 一、查看列表&#xff08;list&#xff09;的形状 1.shape import numpy as npL [[1,2],[3,4],[5,6],[7,8]] L np.array(L)print(L.sha…

大数据周会-本周学习内容总结04

目录 1、mysql数据同步到es 1.1、通过logstash同步数据 1.2、canal数据同步 1.3、通过logstash将本地文件导入es 2、git 1、mysql数据同步到es 1.1、通过logstash同步数据 elastic官方文档&#xff1a;如何使用Logstash和JDBC确保 Elasticsearch与关系型数据库保持同步&a…