当前位置: 首页 > news >正文

13-mvc框架原理与实现方式

1、mvc原理

# mvc 与框架## 1.mvc 是什么1. m:model,模型(即数据来源),主要是针对数据库操作
2. v:view,视图,html 页面。视图由一个一个模板构成(模板是视图的一个具体展现或载体,视图是模板的一个抽象)
3. c:controller,控制器,用于mv之间的数据交互## 2.最简单的 mvc
就是一个可以显示数据库内容的模板## 3.分层后的mvc### 2.1 控制器(以下三个)1. 接受请求: 路由
2. 选择模型: CURD
3. 加载视图: 模板### 2.2 模型(功能是操作数据库)1. 查询构造器
2. 模型操作## 2.3 视图(以下两个)1. 模板赋值
2. 渲染视图

2、mvc的极简实现方式(一个页面)

<?php
//!数据库查询(model)
//第一步:连接数据库
$db = new PDO('mysql:dbname=phpedu','root','root');// 第二步:对数据库进行查询
$stmt = $db->prepare('SELECT * FROM `staff` LIMIT ?');// 第三步:数据绑定,获取指定的数据,确定获取的数据条数
$stmt->bindValue(1,5,PDO::PARAM_INT);// 第四步:执行上述操作,如果不进行数据绑定就需要在execute里面加入参数
$stmt->execute();// 第五步:把查询到的数据集保存到一个变量里备用
$staffs = $stmt->fetchAll(PDO::FETCH_ASSOC);
?><!-- 视图(view) -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>员工列表</title>
</head>
<body><!-- 第六步:foreach渲染数据 --><h3>员工列表</h3><?php foreach ($staffs as $staff) :extract($staff) ?><li><?=$id?>:<?=$name?> , <?=$sex ? '女':'男'?>(<?=$email?>)</li><?php endforeach?>
</body>
</html>

上述代码中,模型model和视图view都已经存在了,而控制器controller实际上已经有了,但是我们看不到,因为我们上面的业务逻辑太简单,直接把数据写进去了。没有通过controller让model和view进行数据交互。

3、分层的mvc 

先写控制器controller,控制器写完写模型model,模型写完最后再写视图view。

 其中,core里面包含模型类(Model.php),视图类(View.php),控制器类(controller.php)

 

 Model.php

<?php// 模型类// 命名空间遵循psr-4
// 类名与文件名同名
// 当前类的命名空间与当前类所在的路径应该是一一对应的
namespace core;use PDO;// 视图,控制器和模型不能直接使用,因为这是底层的业务逻辑
// 是框架源码的一部分,不要让用户直接用,因为框架一旦更新
// 新的框架源码会把core目录下的所有代码全部覆盖
// 所以视图,控制器和模型里面的内容和类尽量把它们转为抽象的
// 或者干脆写个接口,让用户来进行实例化
// 模型抽象化(每个用户一张表),只允许通过子类使用
abstract class Model
{// 要把连接对象写成属性,因为这个对象它会在当前的模型类中多个方法中使用protected $db = null;// 1.连接数据库// 在实例化时能够自动连接,可以写在构造函数里public function __construct($dsn,$username,$password){$this->db = new PDO($dsn,$username,$password);}// 2.内置一些基本的底层操作,供用户的自定义模型用// 自定义模型:与某一个或某一张数据表相关的类// 2.1获取全部数据public function select($num){$sql = 'SELECT *FROM `staff` LIMIT ?;';$stmt = $this->db->prepare($sql);$stmt->bindParam(1,$num,PDO::PARAM_INT); // !这种方法可以确保当出错时我们知道错误在哪里// if($stmt->execute()){//     return $stmt->fetchAll(PDO::FETCH_ASSOC);// }else{//     print_r($stmt->errorInfo());// }// !也可以用简化版,因为出错概率较低$stmt->execute();return $stmt->fetchAll(PDO::FETCH_ASSOC);}// 2.2获取某个数据(id)public function getOne($id){$sql = 'SELECT *FROM `user` WHERE `id` = ?;';$stmt = $this->db->prepare($sql);$stmt->bindParam(1,$id,PDO::PARAM_INT); $stmt->execute();return $stmt->fetch(PDO::FETCH_ASSOC);}
}

 View.php

<?php// 视图类namespace core;class view
{// 1.模板变量容器protected array $data = [];// 2.模板赋值public function assign(string $key,$value){$this->data[$key] = $value;}// 3.渲染视图// 渲染与传参可以同步完成// $path告诉数据显示在哪个页面中public function render(string $path,array $data = []){if($data){foreach($data as $key=>$value){$this->assign($key,$value);}}// 将模板变量数组展开为独立的变量,以方便传入到模板中使用extract($this->data);// 渲染/加载模板文件file_exists($path) ? include $path : die('模板不存在');}
}

Controller.php

<?php// 控制器类namespace core;abstract class Controller
{// 1.模型对象protected Model $model;// 2.视图对象protected View $view;// 3.实例化,初始化上面的模型对象,视图对象public function __construct(Model $model,View $view){$this->model = $model;$this->view = $view;}
}

autoload.php(自动加载器)

<?php// 注册类的自动加载器方法
spl_autoload_register(function($class){// require str_replace('\\','/',$class) . 'php';// 为了系统的兼容性,可以使用require str_replace('\\',DIRECTORY_SEPARATOR,$class) . '.php';// 这是一个可以代替 composer 的方法,参数是function,传入了一个类名,// 然后用str_replace这个函数,把类里面的命名空间,也就是反斜线替换成路径符,// 然后在后面加扩展名 .php 转变为类就行了// 这样就实现了了一个类的自动加载了(相当于require了一个命名空间+类名)
});

如果想要把这些类一个一个加载到项目中去,则需要针对不同的业务类型创建不同的控制器和模型,所以要创建一个controller文件夹

 

 StaffController.php(用户自定义控制器)

虽然不是控制器基类,但是要求必须继承自控制器基类(父类)

<?php// 自定义控制器,必须继承自控制器基类(超类/父类)namespace controller;use core\Controller;
use core\Model;
use core\View;
use model\StaffModel;class StaffController extends Controller
{public function __construct(Model $model,View $view){// 里面这样写就冗余了// $this->model = $model;// $this->view = $view;//子类的构造函数直接调用父类的构造方法就可以了parent::__construct($model,$view);}// 自定义方法:默认方法// index():列出所有数据public function index($num = 10){// 1.选择模型:获取数据$staff = $this->model->getAll($num);// 2.加载视图// 路径约定:view/控制器/方法名.php// key值可以理解为变量名,相当于把$staff接收到的值赋给了名为staffs的变量$this->view->render('view/staff/index.php',['staffs'=>$staff]);}
}

创建类文件夹,里面都是自定义模型类 

 

 StaffModel.php(用户自定义模型类)

<?php
// 自定义模型namespace model;use core\Model;class StaffModel extends Model
{public function __construct($dsn,$username,$password){parent::__construct($dsn,$username,$password);}// 获取全部数据public function getAll($num){return $this->select($num);}
}

创建视图文件夹,在视图里再创建文件夹,staff文件夹对应是当前的控制器,里面的文件对应当前的方法。

 

 staff>index.php

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>员工列表</title>
</head>
<body><!-- 第六步:foreach渲染数据 --><h3>员工列表</h3><?php foreach ($staffs as $staff) :extract($staff) ?><li><?=$id?>:<?=$name?> , <?=$sex ? '女':'男'?>(<?=$email?>)</li><?php endforeach?>
</body>
</html>

在mvc2文件夹下创建测试文件index.php

 mvc2>index.php

<?php
namespace mvc2;use controller\StaffController;
use model\StaffModel;
use core\view;
// 入口文件:测试// 1.类的自动加载器
// 自动加载器主要用来加载间接用到的类,但是直接用到的类还是需要用use
require __DIR__ . '/core/autoload.php';// 路由解析// 2.实例化控制器
$model = new StaffModel('mysql:dbname=phpedu','root','root');
$view = new View();
// 实例化控制器对象
$staff = new StaffController($model,$view);// 3.调用控制器中的方法
$staff->index(3);

上述运行结果:

 4、路由原理及应用

<?php// 路由的本质:是从url中解析出控制器,控制方法,以及方法的参数// 1.controller:控制器类名
// 2.method:控制器中的某个方法名
// 3.parameter:参数列表,以数组形式// 以上三种数据在url中的展示方式有两种
// 1.queryString:查询字符串
// 2.PATH_INFO:路径信息// phpedu.io/one/two/demo1.php?查询字符串,以键值对方式,和&分开
// !c:controller,m:method,p:parameter
// phpedu.io/one/two/demo1.php?c=hello&m=method&p=aaa
// 得到这个查询字符串以后,我们可以通过一些方法,将该字符串解析成数组,从而得到控制器,方法和参数//! 在我们的脚本名称 `phpedu.io/one/two/demo1.php` 和查询字符串 `c=hello&m=method&p=aaa`之间
// !如果又出现路径,我们用 PATH_INFO 表示 /user/index/100/200
// phpedu.io/one/two/demo1.php   PATH_INFO   ?c=hello&m=method&p=aaa
// phpedu.io/one/two/demo1.php/user/index/100/200?c=hello&m=method&p=aaa// /user/index/100/200:PATH_INFO
function p($data)
{echo is_array($data) ? sprintf('<pre>%s</pre>',print_r($data,true)) : $data;
}
p([1,2,3]);
p('Hello');
echo '<hr>';
// !QueryString: 查询字符串
// 超全局数组$_SERVER的QUERY_STRING键可以返回当前的查询字符串
p($_SERVER['QUERY_STRING']);
// 将查询字符串解析到数组里面
parse_str($_SERVER['QUERY_STRING'],$request);
p($request);// 人为认定
// c controller, m:method,name:parameter
$controller = array_shift($request);
$method = array_shift($request);
$params = array_shift($request);// 控制器类:测试专用
class HelloController
{public function world($name){return 'Hello ,' . $name;}
}// 生成控制器类名
$controller = ucfirst($controller) . 'Controller';
echo (new $controller)->$method($params);
// 一般用回调的方式来调用
// echo call_user_func_array([new $controller(),$method],[$params]);
echo call_user_func([new $controller(),$method],$params);
echo '<hr>';// ! 2.PATH_INFO:查询字符串与脚本之间的路径信息
//* http://phpedu.io/0824/router.php/hello/world/admin?c=hello&m=world&name=peter
//* PATH_INFO:/hello/world/admin
p($_SERVER['PATH_INFO']);
p(explode('/',$_SERVER['PATH_INFO']));
// 但这样之后发现索引0对应的值为空
// p(array_filter(explode('/',$_SERVER['PATH_INFO'])));
// 去除空字符也可以这样
$request = explode('/',trim($_SERVER['PATH_INFO'],'/'));$controller = array_shift($request);
$method = array_shift($request);
$params = array_shift($request);$controller = ucfirst($controller) . 'Controller';
echo call_user_func([new $controller(),$method],$params);
// 也可以 echo call_user_func_array([new $controller(),$method],[$params]);// !推荐使用PATH_INFO
// 通过url重写功能,可以将脚本的扩展名php隐藏,也可以在末尾自定义一个扩展名
//* 隐藏后的地址具有欺骗性:http://phpedu.io/0824/router/hello/world/admin.html/*** 总结:* 1.$_SERVER['QUERY_STRING']以键值对方式返回当前字符串,返回值是数组,需要用parse_str转换成字符串* 2.1.$_SERVER['PATH_INFO']返回带有/的字符串,返回值是字符串,需要用explode切割转换成数组*/

上述运行结果:

 

在mvc3文件夹下创建测试文件index.php 

<?php
namespace mvc3;use model\UserModel;
use core\view;
use core\Router;
// 入口文件:测试// 1.类的自动加载器
require __DIR__ . '/core/autoload.php';// 路由解析
$request = Router::parse();$controller = array_shift($request);
$method = array_shift($request);
$params = array_shift($request);// 生成控制器名称
$controller ='controller\\' . ucfirst($controller) . 'Controller';// echo $controller;
// die;// 2.实例化控制器
$model = new UserModel('mysql:dbname=phpedu','root','root');
$view = new View();
// 实例化控制器对象
$user = new $controller($model,$view);// 3.调用控制器中的方法
call_user_func_array([$user,'get'],$params);

 mvc3>core>router.php

<?phpnamespace core;// 路由器类
class Router
{public static function parse(): array{// 默认控制器,实际项目,应该来自配置文件,而不是在写死$controller = 'Index';$action = 'index';// 参数列表$params = [];// 判断是否存在pathinfoif (array_key_exists('PATH_INFO', $_SERVER) && $_SERVER['PATH_INFO'] !== '/') {// 为什么要判断 $_SERVER['PATH_INFO'] !== '/' ?// 因为: admin.php/ 时,$_SERVER['PATH_INFO'] = '/', 导致解析控制器失败$pathinfo = array_filter(explode('/', $_SERVER['PATH_INFO']));// dump($pathinfo);// 考虑到index.php/ 情况, 这时pathinfo为空数组if (count($pathinfo) >= 2) {$controller = array_shift($pathinfo);$action = array_shift($pathinfo);$params = $pathinfo;// $params = array_shift($pathinfo);} else {$controller = array_shift($pathinfo);}}// 查看控制器,方法,参数// dump($controller, $action, $params);// 将这些数据返回出去return [$controller, $action, $params];}
}

mvc3>model>UserModel

<?php
// 自定义模型namespace model;use core\Model;class UserModel extends Model
{public function __construct($dsn,$username,$password){parent::__construct($dsn,$username,$password);}// 获取全部数据public function get($id){return $this->getOne($id);}
}

mvc3>view>user>get

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>员工信息</title>
</head><body><!-- 第六步:foreach渲染数据 --><h3>员工信息</h3><?php if (is_array($user)) : ?><?php foreach ($user as $key => $value) : ?><!-- 如果不想拿 --><?php// if($value = null){//     echo '该用户不存在';// }if ($key === 'password' || $key === 'register_time') {continue;}?><li>[<?= $key ?>] => <?= $value ?></li><?php endforeach ?><?php endif ?><?php if (is_array($user) == null) : ?><h3>此用户不存在</h3><?php endif ?>
</body></html>

 上述运行结果:

 

相关文章:

13-mvc框架原理与实现方式

1、mvc原理 # mvc 与框架## 1.mvc 是什么1. m:model,模型(即数据来源),主要是针对数据库操作 2. v:view,视图,html 页面。视图由一个一个模板构成(模板是视图的一个具体展现或载体,视图是模板的一个抽象) 3. c:controller,控制器,用于mv之间的数据交互## 2.最简单的 mvc 就是一…...

弹性盒子布局

目录一、弹性盒子属性二、认识flex的坐标轴三、简单学习父级盒子属性三、属性说明3.1、flex-grow一、弹性盒子属性 说明&#xff1a; div的默认样式&#xff1a;display:block 块盒子 display:flex弹性盒子&#xff08;可以控制下级盒子的位置&#xff09; 当两种盒子单独出现…...

C# Sqlite数据库加密

sqlite官方的数据库加密是收费的&#xff0c;而且比较贵。 幸亏微软提供了一种免费的方法。 1 sqlite加密demo 这里我做了一个小的demo演示如下&#xff1a; 在界面中拖入数据库名、密码、以及保存的路径 比如我选择保存路径桌面的sqlite目录&#xff0c;数据库名guigutool…...

高压放大器在声波谐振电小天线收发测试系统中的应用

实验名称&#xff1a;高压放大器在声波谐振电小天线收发测试系统中的应用研究方向&#xff1a;信号传输测试目的&#xff1a;声波谐振电小天线颠覆了传统电小天线以电磁波谐振作为理论基础的天线发射和接收模式&#xff0c;它借助声波谐振实现电磁信号的辐射或接收。因为同频的…...

锁相环的组成和原理及应用

一.锁相环的基本组成 许多电子设备要正常工作&#xff0c;通常需要外部的输入信号与内部的振荡信号同步&#xff0c;利用锁相环路就可以实现这个目的。 锁相环路是一种反馈控制电路&#xff0c;简称锁相环(PLL)。锁相环的特点是&#xff1a;利用外部输入的参考信号控制环路内…...

[C++]string类模拟实现

目录 前言&#xff1a; 1. string框架构造 2. 默认函数 2.1 构造函数 2.2 析构函数 2.3 拷贝构造 2.4 赋值重载 3. 迭代器 4. 整体程序 前言&#xff1a; 本篇文章模拟实现了C中string的部分功能&#xff0c;有助于大家了解和熟悉string类&#xff0c;虽然这个类不难实…...

一个更适合Java初学者的轻量级开发工具:BlueJ

Java是世界上最流行的编程语言之一&#xff0c;它被广泛用于从Web开发到移动应用的各种应用程序。大部分Java工程师主要是用IDEA、Eclipse为主&#xff0c;这两个开发工具由于有强大的能力&#xff0c;所以复杂度上就更高一些。如果您刚刚开始使用Java&#xff0c;或者您更适合…...

从程序员到项目组长,要经历六重修炼

最近和粉丝朋友们交流时发现&#xff0c;有很多刚刚开始做项目组长的朋友自我认可度非常低&#xff0c;感觉做组长之后天天打杂&#xff0c;技术也荒废了。领导天天找你要成果&#xff0c;下属天天找你说困难&#xff0c;你在中间受领导和下属的夹板气。时间久了&#xff0c;你…...

我的 System Verilog 学习记录(5)

、 引言 本文简单介绍 System Verilog 语言的 控制流。 前文链接&#xff1a; 我的 System Verilog 学习记录&#xff08;1&#xff09; 我的 System Verilog 学习记录&#xff08;2&#xff09; 我的 System Verilog 学习记录&#xff08;3&#xff09; 我的 System Ver…...

多芯片设计 Designing For Multiple Die

Why a system-level approach is essential, and why its so challenging作者&#xff1a;Ann MutschlerAnn Mutschler is executive editor at Semiconductor Engineering.将多个裸片或芯粒集成到一个封装中&#xff0c;与将它们放在同一硅片上有着很大的区别。在同一硅片上&a…...

2022年全国职业院校技能大赛(中职组)网络安全竞赛试题A(10)

目录 竞赛内容 模块A 基础设施设置与安全加固 一、项目和任务描述&#xff1a; 二、服务器环境说明 三、具体任务&#xff08;每个任务得分以电子答题卡为准&#xff09; A-1任务一 登录安全加固&#xff08;Windows, Linux&#xff09; 1.密码策略&#xff08;Windows, …...

数据结构-简介

目录 1、简介 2、作用 3、分类 4、实现分类 1、简介 数据结构指的是组织和存储数据的方法。它涉及到一系列的算法和原则&#xff0c;用来设计和实现不同种类的数据类型&#xff0c;如数组、链表、树、图等等。数据结构的目的是在计算机程序中有效地管理和操作数据&#xff…...

python装饰器及其用法

python装饰器是什么? Python装饰器是一种语法结构&#xff0c;它可以让开发者在不修改原函数的基础上&#xff0c;在函数的前后运行额外的代码&#xff0c;这些代码可以达到修改函数行为的目的。Python装饰器的实质是一个可调用的对象&#xff0c;它可以接收函数作为参数…...

Appium自动化测试之启动时跳过初始化设置

Appium每次启动时都会检查和安装Appium Settings&#xff0c;这是完全没有必要的&#xff0c;在首次使用Appium连接设备是Appium Settings便已经安装好。怎样跳过安装Appium Settings呢&#xff1f;之前的做法是修改appium中的源文件中的android-helpers.js实现&#xff0c;如M…...

JavaScript DOM【快速掌握知识点】

目录 DOM简介 获取元素 修改元素 添加和移除元素 事件处理 DOM简介 JavaScript DOM 是指 JavaScript 中的文档对象模型&#xff08;Document Object Model&#xff09;&#xff1b;它允许 JavaScript 与 HTML 页面交互&#xff0c;使开发者可以通过编程方式动态地修改网页…...

不需要高深技术,只需要Python:创建一个可定制的HTTP服务器!

目录 1、编写服务端代码,命名为httpserver.py文件。 2、编写网页htmlcss文件&#xff0c;命名为index.html和style.css文件。 3、复制htmlcss到服务端py文件同一文件夹下。 4、运行服务端程序。 5、浏览器中输入localhost:8080显示如下&#xff1a; 要编写一个简单的能发布…...

渗透测试常用浏览器插件汇总

1、shodan这个插件可以自动探测当前网站所属的国家、城市&#xff0c;解析IP地址以及开放的服务和端口&#xff0c;包括但不限于FTP、DNS、SSH或者其他服务等&#xff0c;属被动信息搜集中的一种。2、hackbar&#xff08;收费之后用Max Hackerbar代替&#xff09;这个插件可用于…...

社区1月月报|OceanBase 4.1 即将发版,哪些功能将会更新?

我们每个月都会和大家展开一次社区进展的汇报沟通会&#xff0c;希望通过更多的互动交流让OceanBase 开源社区更加透明&#xff0c;实现信息共享&#xff0c;也希望能营造更加轻松的氛围&#xff0c;为大家答疑解惑&#xff0c;让大家畅所欲言。如果您对我们的社区有任何建议&a…...

Javascript的API基本内容(二)

一、事件监听 结合 DOM 使用事件时&#xff0c;需要为 DOM 对象添加事件监听&#xff0c;等待事件发生&#xff08;触发&#xff09;时&#xff0c;便立即调用一个函数。 addEventListener 是 DOM 对象专门用来添加事件监听的方法&#xff0c;它的两个参数分别为【事件类型】和…...

ChatGPT热度“狂飙”,OceanBase也去找它唠了唠

最近互联网的关键字 非 ChatGPT 莫属 就是这个小东西 集唠嗑、提问、答疑、科普、写作于一体 让我看看哪个孤独的打工人 还没和 ChatGPT 聊上一聊 有人说 ChatGPT 这么智能 或将取代人类的工作 OceanBase 的小编表示不服气 于是&#xff0c;抱着好奇之心试了一试 对 …...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...