gin框架内容(二)

上一篇过于gin的内容

https://mp.csdn.net/mp_blog/creation/editor/131953861

CSDNhttps://mp.csdn.net/mp_blog/creation/editor/131953861

 一、路由组

为了管理具有相同前缀的URL, 将拥有URL共同前缀的路由划分为一组

为了代码的阅读性,使用{}包裹相同组的路由不用{}包裹并不影响效果

1.1路由组


为了管理具有相同前缀的URL, 将拥有URL共同前缀的路由划分为一组

为了代码的阅读性,使用{}包裹相同组的路由不用{}包裹并不影响效果

 

 上述的两个路由都是在shop这个组下

1.2路由组嵌套

 1.3所有代码

package mainimport ("encoding/json""fmt""github.com/gin-gonic/gin""net/http"
)// /user/search?username=zhangsan&address=北京
// urlQuery 获取 url中?后面携带的参数
func urlQueryHandle(ctx *gin.Context) {// 如果指定的key 没有对应的值就使用默认值username1 := ctx.DefaultQuery("username", "lisi")// 根据key 获取值username2 := ctx.Query("username")address := ctx.Query("address")// 返回JSON 字符串ctx.JSON(http.StatusOK, gin.H{"message":   "ok","username1": username1,"username2": username2,"address":   address,})
}// /user/search/lisi/北京。 获取请求URL路径中的参数的方式如下
// paramsPathHandle 获取url path中参数
func paramsPathHandle(ctx *gin.Context) {// 获取参数值username := ctx.Param("username")address := ctx.Param("address")// 数据返回ctx.JSON(http.StatusOK, gin.H{"message":  "ok","username": username,"address":  address,})
}//=================================// formParamsHandle 获取form表单提交数据
func formParamsHandle(ctx *gin.Context) {// 获取不到值时就是用默认值username1 := ctx.DefaultPostForm("username", "lisi")username2 := ctx.PostForm("username")address := ctx.PostForm("address")// 以Json 字符串的形式返回ctx.JSON(http.StatusOK, gin.H{"message":   "ok","username1": username1,"username2": username2,"address":   address,})
}// json参数
// paramsJsonHandle 获取json字符串相关的参数
func paramsJsonHandle(ctx *gin.Context) {// 获取request.Body() 中的数据(这里没有进行错误处理)// 返回的是字节数组dataBytes, _ := ctx.GetRawData()// 定义一个mapvar m map[string]interface{}// 反序列化 别忘了&_ = json.Unmarshal(dataBytes, &m)// 数据返回ctx.JSON(http.StatusOK, m)}//文件上传
/*单个文件上传文件上传接收的文件格式是: multipart/form-data
*/// singleFileUploadHandle 当文件上传
func singleFileUploadHandle(ctx *gin.Context) {// 获取文件// 根据上传时的参数名获取上传的文件内容 --> 返回对象为 *multipart.FileHeaderfileHeader, err := ctx.FormFile("file")if err != nil {ctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})return}// 保存文件内容// 拼接文件名, 这里直接写死了targetFileName := fmt.Sprintf("C:/Users/黑熊精/Pictures/%s", fileHeader.Filename)//targetFileName := fmt.Sprintf("%s", fileHeader.Filename)// 将文件保存到指定的目录err = ctx.SaveUploadedFile(fileHeader, targetFileName)if err != nil {ctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})} else {ctx.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("%s upload success!", fileHeader.Filename),})}
}//多文件上传/**多文件上传
*/// multiFileUploadHandle 多文件上传
func multiFileUploadHandle(ctx *gin.Context) {// form 是一个存储文件信息的结构体/**type Form struct {Value map[string][]stringFile  map[string][]*FileHeader*/form, err := ctx.MultipartForm()if err != nil {ctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})return}// 获取文件列表,并保存, 返回的是一个切片 []*FileHeaderfiles := form.File["file"]for i, file := range files {targetFileName := fmt.Sprintf("C:/Users/黑熊精/Pictures/%d_%s", i, file.Filename)err = ctx.SaveUploadedFile(file, targetFileName)if err != nil {ctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})return}}ctx.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("upload success!"),})
}// shuldbind数据的绑定的办法
// 使用 ShouldBind() 方法, 根据请求方式,自动提取 JSON, form表单 和 Query 类型的参数,放入结构体中
// 用户信息信息结构体
// 加上 binding:"required" 标签,说明该参数是必填的,如果不填就会报错
type UserInfo struct {Username string `json:"username" form:"username" binding:"required"`Address  string `json:"address" form:"address" binding:"required"`
}// 获取query参数
func queryHandle(ctx *gin.Context) {var userInfo UserInfo// 获取数据err := ctx.ShouldBind(&userInfo)if err == nil {ctx.JSON(http.StatusOK, gin.H{"message":  "ok","username": userInfo.Username,"address":  userInfo.Address,})} else {ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}
}func jsonHandle(ctx *gin.Context) {var userInfo UserInfo// 获取数据err := ctx.ShouldBind(&userInfo)if err == nil {ctx.JSON(http.StatusOK, gin.H{"message":  "ok","username": userInfo.Username,"address":  userInfo.Address,})} else {ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}
}func fromHandle(ctx *gin.Context) {var userInfo UserInfo// 获取数据err := ctx.ShouldBind(&userInfo)if err == nil {ctx.JSON(http.StatusOK, gin.H{"message":  "ok","username": userInfo.Username,"address":  userInfo.Address,})} else {ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}
}func main() {// 创建默认路由r := gin.Default()//两种浏览器地址获取参数的办法// 绑定路由规则 /user/search?username=zhangsan&address=北京r.GET("/user/search", urlQueryHandle)// 2. 绑定路由规则/user/search/lisi/北京。 获取请求URL路径中的参数的方式如下r.GET("/user/search/:username/:address", paramsPathHandle)//========================表单提交方法======================// 绑定路由规则r.POST("/user/search", formParamsHandle)//json// 绑定路由规则r.POST("/user/json", paramsJsonHandle)//// 绑定路由规则--文件上传r.POST("/upload/single", singleFileUploadHandle)绑定路由规则--多文件上传r.POST("/upload/multi", multiFileUploadHandle)//使用 ShouldBind() 方法, 根据请求方式,自动提取 JSON, form表单 和 Query 类型的参数,放入结构体中// 绑定路由规则r.GET("/user/query", queryHandle)r.POST("/user/form", fromHandle)r.POST("/user/jsons", jsonHandle)//路由组的使用// 绑定路由规则shopGroup := r.Group("/shop"){// /shop/infoshopGroup.GET("/info", func(ctx *gin.Context) {ctx.JSON(http.StatusOK, "/shop/info")})// /shop/cartshopGroup.GET("/cart", func(ctx *gin.Context) {ctx.JSON(http.StatusOK, "/shop/cart")})}//路由组嵌套// 绑定路由规则shopGroup1 := r.Group("/shop1"){// shop/bookshopBookGroup1 := shopGroup1.Group("/book")// shop/book/infoshopBookGroup1.GET("/info", func(ctx *gin.Context) {ctx.JSON(http.StatusOK, "shop/book/info")})}// 监听端口r.Run(":9000")
}

二、重定向事项

Gin之重定向
1.外部重定向(redirect重定向)
2.内部重定向(redirect重定向)
3.路由重定向(forward转发)

//	======================//go 1.重定向---www.baidu.comr.GET("/a", func(c *gin.Context) {//Redirect是*Context的方法,传入的参数是(code int, location string) ,无返回值//StatusMovedPermanently是301c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")})//内部重定向//2.内部重定向(redirect重定向)----内部重定向r.GET("/bb", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "/b")})r.GET("/b", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"hello": "world",})})//3.路由重定向(forward转发)====r.GET("/ab11", func(c *gin.Context) {/*Context结构体里有Request字段(类型是*http.Request),Request结构体里有一个URL字段(类型是*url.URL),URL结构体里面有path字段(类型是string)*///跳转到/b对应的路由处理函数c.Request.URL.Path = "/b11"r.HandleContext(c)})r.GET("/b11", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"hello": "world",})})

1.

 

三、其他内容 ,所有代码

package mainimport ("encoding/json""fmt""github.com/gin-gonic/gin""net/http"
)// /user/search?username=zhangsan&address=北京
// urlQuery 获取 url中?后面携带的参数
func urlQueryHandle(ctx *gin.Context) {// 如果指定的key 没有对应的值就使用默认值username1 := ctx.DefaultQuery("username", "lisi")// 根据key 获取值username2 := ctx.Query("username")address := ctx.Query("address")// 返回JSON 字符串ctx.JSON(http.StatusOK, gin.H{"message":   "ok","username1": username1,"username2": username2,"address":   address,})
}// /user/search/lisi/北京。 获取请求URL路径中的参数的方式如下
// paramsPathHandle 获取url path中参数
func paramsPathHandle(ctx *gin.Context) {// 获取参数值username := ctx.Param("username")address := ctx.Param("address")// 数据返回ctx.JSON(http.StatusOK, gin.H{"message":  "ok","username": username,"address":  address,})
}//=================================// formParamsHandle 获取form表单提交数据
func formParamsHandle(ctx *gin.Context) {// 获取不到值时就是用默认值username1 := ctx.DefaultPostForm("username", "lisi")username2 := ctx.PostForm("username")address := ctx.PostForm("address")// 以Json 字符串的形式返回ctx.JSON(http.StatusOK, gin.H{"message":   "ok","username1": username1,"username2": username2,"address":   address,})
}// json参数
// paramsJsonHandle 获取json字符串相关的参数
func paramsJsonHandle(ctx *gin.Context) {// 获取request.Body() 中的数据(这里没有进行错误处理)// 返回的是字节数组dataBytes, _ := ctx.GetRawData()// 定义一个mapvar m map[string]interface{}// 反序列化 别忘了&_ = json.Unmarshal(dataBytes, &m)// 数据返回ctx.JSON(http.StatusOK, m)}//文件上传
/*单个文件上传文件上传接收的文件格式是: multipart/form-data
*/// singleFileUploadHandle 当文件上传
func singleFileUploadHandle(ctx *gin.Context) {// 获取文件// 根据上传时的参数名获取上传的文件内容 --> 返回对象为 *multipart.FileHeaderfileHeader, err := ctx.FormFile("file")if err != nil {ctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})return}// 保存文件内容// 拼接文件名, 这里直接写死了targetFileName := fmt.Sprintf("C:/Users/黑熊精/Pictures/%s", fileHeader.Filename)//targetFileName := fmt.Sprintf("%s", fileHeader.Filename)// 将文件保存到指定的目录err = ctx.SaveUploadedFile(fileHeader, targetFileName)if err != nil {ctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})} else {ctx.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("%s upload success!", fileHeader.Filename),})}
}//多文件上传/**多文件上传
*/// multiFileUploadHandle 多文件上传
func multiFileUploadHandle(ctx *gin.Context) {// form 是一个存储文件信息的结构体/**type Form struct {Value map[string][]stringFile  map[string][]*FileHeader*/form, err := ctx.MultipartForm()if err != nil {ctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})return}// 获取文件列表,并保存, 返回的是一个切片 []*FileHeaderfiles := form.File["file"]for i, file := range files {targetFileName := fmt.Sprintf("C:/Users/黑熊精/Pictures/%d_%s", i, file.Filename)err = ctx.SaveUploadedFile(file, targetFileName)if err != nil {ctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error(),})return}}ctx.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("upload success!"),})
}// shuldbind数据的绑定的办法
// 使用 ShouldBind() 方法, 根据请求方式,自动提取 JSON, form表单 和 Query 类型的参数,放入结构体中
// 用户信息信息结构体
// 加上 binding:"required" 标签,说明该参数是必填的,如果不填就会报错
type UserInfo struct {Username string `json:"username" form:"username" binding:"required"`Address  string `json:"address" form:"address" binding:"required"`
}// 获取query参数
func queryHandle(ctx *gin.Context) {var userInfo UserInfo// 获取数据err := ctx.ShouldBind(&userInfo)if err == nil {ctx.JSON(http.StatusOK, gin.H{"message":  "ok","username": userInfo.Username,"address":  userInfo.Address,})} else {ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}
}func jsonHandle(ctx *gin.Context) {var userInfo UserInfo// 获取数据err := ctx.ShouldBind(&userInfo)if err == nil {ctx.JSON(http.StatusOK, gin.H{"message":  "ok","username": userInfo.Username,"address":  userInfo.Address,})} else {ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}
}func fromHandle(ctx *gin.Context) {var userInfo UserInfo// 获取数据err := ctx.ShouldBind(&userInfo)if err == nil {ctx.JSON(http.StatusOK, gin.H{"message":  "ok","username": userInfo.Username,"address":  userInfo.Address,})} else {ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}
}func main() {// 创建默认路由r := gin.Default()//两种浏览器地址获取参数的办法// 绑定路由规则 /user/search?username=zhangsan&address=北京r.GET("/user/search", urlQueryHandle)// 2. 绑定路由规则/user/search/lisi/北京。 获取请求URL路径中的参数的方式如下r.GET("/user/search/:username/:address", paramsPathHandle)//========================表单提交方法======================// 绑定路由规则r.POST("/user/search", formParamsHandle)//json// 绑定路由规则r.POST("/user/json", paramsJsonHandle)//// 绑定路由规则--文件上传r.POST("/upload/single", singleFileUploadHandle)绑定路由规则--多文件上传r.POST("/upload/multi", multiFileUploadHandle)//使用 ShouldBind() 方法, 根据请求方式,自动提取 JSON, form表单 和 Query 类型的参数,放入结构体中// 绑定路由规则r.GET("/user/query", queryHandle)r.POST("/user/form", fromHandle)r.POST("/user/jsons", jsonHandle)//路由组的使用// 绑定路由规则shopGroup := r.Group("/shop"){// /shop/infoshopGroup.GET("/info", func(ctx *gin.Context) {ctx.JSON(http.StatusOK, "/shop/info")})// /shop/cartshopGroup.GET("/cart", func(ctx *gin.Context) {ctx.JSON(http.StatusOK, "/shop/cart")})}//路由组嵌套// 绑定路由规则shopGroup1 := r.Group("/shop1"){// shop/bookshopBookGroup1 := shopGroup1.Group("/book")// shop/book/infoshopBookGroup1.GET("/info", func(ctx *gin.Context) {ctx.JSON(http.StatusOK, "shop/book/info")})}//	======================//go 1.重定向---www.baidu.comr.GET("/a", func(c *gin.Context) {//Redirect是*Context的方法,传入的参数是(code int, location string) ,无返回值//StatusMovedPermanently是301c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")})//内部重定向//2.内部重定向(redirect重定向)----内部重定向r.GET("/bb", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "/b")})r.GET("/b", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"hello": "world",})})//3.路由重定向(forward转发)====r.GET("/ab11", func(c *gin.Context) {/*Context结构体里有Request字段(类型是*http.Request),Request结构体里有一个URL字段(类型是*url.URL),URL结构体里面有path字段(类型是string)*///跳转到/b对应的路由处理函数c.Request.URL.Path = "/b11"r.HandleContext(c)})r.GET("/b11", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"hello": "world",})})// 监听端口r.Run(":9000")
}

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

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

相关文章

WPF icon的设置

想给控件设置个圆形图片&#xff0c;代码如下&#xff1a; ​<Setter Property"Icon"><Setter.Value><Image Source"/WpfApp1;component/Resource/1.ico" Width"16" Height"16"/></Setter.Value></Setter&…

ncnn-android-yolov7跑自己模型的注意事项

ncnn-android-yolov7 这是一个示例 ncnn android 项目&#xff0c;它依赖于 ncnn 库和 opencv https://github.com/Tencent/ncnn https://github.com/nihui/opencv-mobile https://github.com/xiang-wuu/ncnn-android-yolov7 如何构建和运行 步骤1 https://github.com/Ten…

LeetCode 0771. 宝石与石头

【LetMeFly】771.宝石与石头 力扣题目链接&#xff1a;https://leetcode.cn/problems/jewels-and-stones/ 给你一个字符串 jewels 代表石头中宝石的类型&#xff0c;另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型&#xff0c;你想…

linux 在excel里面找内容

linux 在excel里面找内容 背景&#xff1a;在大数据行业中&#xff0c;很多数据源是excel文件&#xff0c;但是常常会出现查找excel内容找到对应的文件&#xff0c;所以制作了简单的shell脚本方便查询对应的excel文件 查看下面精简的内容即可&#xff0c;开箱即用 shell转换 …

网络知识点之-堆叠与集群(1-堆叠)

本文章收录至《网络》专栏&#xff0c;点击右上角专栏图标可访问本专栏&#xff01; 堆叠技术是在以太网交换机上扩展端口使用较多的另一类技术&#xff0c;是一种非标准化技术。各个厂商之间不支持混合堆叠&#xff0c;堆叠模式为各厂商制定&#xff0c;不支持拓扑结构。流行的…

flask自己写登录验证和角色验证

python flask程序需要用户登录也需要角色验证&#xff0c;可以采用如下方法 def is_login(func):wraps(func)def inner(*args,**kwargs):user session.get(user)if not user:return redirect(url_for(login))return func(*args,**kwargs)return innerdef roles_required(*arg…

vue项目实现数组中添加多个相同的对象

在写项目的时候&#xff0c;有时候想有一个有较大length的对象数组&#xff0c;则可以使用如下的方法&#xff1a; export default {data() {const item {date: 2016-05-02,name: 王小虎,address: 上海市普陀区金沙江路 1518 弄};return {tableData: Array(20).fill(item)}} …

将Parasoft和ChatGPT相结合会如何?

ChatGPT是2023年最热门的话题之一&#xff0c;是OpenAI训练的语言模型。它能够理解和生成自然语言文本&#xff0c;并接受过大量数据的训练&#xff0c;包括用各种编程语言编写的许多开源项目的源代码。 软件开发人员可以利用大量的知识库来协助他们的工作&#xff0c;因为它具…

「预告」飞凌嵌入式邀您相约第13届配电技术应用论坛

2023年8月3日~5日&#xff0c;第十三届配电技术应用论坛即将在浙江杭州举行&#xff0c;飞凌嵌入式受邀参加。 作为助力快速实现“双碳”目标和新型电力系统建设&#xff0c;加强“双碳”目标下的智能配电网技术研发布局的主要会议&#xff0c;第十三届配电技术应用论坛将从政…

vue 前端 邮箱、密码、手机号码等输入验证规则

最近在写前端表单验证的时候&#xff0c;发现一篇文章质量很好&#xff0c;所以写下这篇文章记录 原文章链接&#xff1a;vue 邮箱、密码、手机号码等输入验证规则 1.手机号 const checkPhone (rule, value, callback) > {const phoneReg /^1[34578]\d{9}$$/;if (!value…

力扣刷题-翻转字符串

刷题链接&#xff1a;344. 反转字符串 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 示例 1&#xff1a; 输入&…

【vue3】vue3接收props以及emit的用法

技术&#xff1a;vue3.2.40 UI框架&#xff1a;arco-design 2.44.7 css技术&#xff1a;less 4.1.3 实现&#xff1a;子组件接收props以及通过emit方法传值父组件 vue3使用的组合式API&#xff0c;我这里使用的是defineComponent 1.父页面调用子组件 <template><d…

FPGA开发:按键消抖

按键是FPGA开发板上的重要交互元件&#xff0c;因为按键的内部的结构设计&#xff0c;在按下和松开按键时&#xff0c;按键会无法避免地产生机械抖动&#xff0c;因此要对按键输入进行特殊处理&#xff0c;否则可能会因为机械抖动产生意外的重复触发。 按键消抖有很多方法&…

C++设计模式之模板方法、策略模式、观察者模式

面向对象设计模式是”好的面向对象设计“&#xff0c;所谓”好的面向对象设计“指的是可以满足”应对变化&#xff0c;提高复用“的设计。 现代软件设计的特征是”需求的频繁变化“。设计模式的要点是”寻求变化点&#xff0c;然后在变化点处应用设计模式&#xff0c;从而更好地…

我的2023上半年总结

Hi~C站的小伙伴们好久不见哇&#xff01;釉色终于回到C站&#xff0c;开始要输出了&#xff01;这一篇文章是我的2023上半年的总结&#xff0c;以此&#xff0c;致敬那段迷茫但又不曾被辜负的时光。 文章目录 总括——你愿意花五分钟时间读读我的文章吗学习——制定目标&#…

【Matlab】基于粒子群优化算法优化BP神经网络的时间序列预测(Excel可直接替换数据)

【Matlab】基于粒子群优化算法优化BP神经网络的时间序列预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理2.数学公式3.文件结构4.Excel数据5.分块代码5.1 fun.m5.2 main.m 6.完整代码6.1 fun.m6.2 main.m 7.运行结果 1.模型原理 基于粒子群优化算法&#xff08;Pa…

nsq整体架构及各个部件作用详解

文章目录 前言 nsq的整体架构图 部件&#xff1a;nsqd 部件&#xff1a;nsqlookupd 部件&#xff1a;nsq连接库 部件&#xff1a;nsqadmin 前言 上两篇博客 centos环境搭建nsq单点_YZF_Kevin的博客-CSDN博客 linux环境搭建nsq集群_YZF_Kevin的博客-CSDN博客 我们讲了nsq是…

桥梁安全监测系统中数据采集上传用 什么?

背景 2023年7月6日凌晨时分&#xff0c;G5012恩广高速达万段230公里加80米处6号大桥部分桥面发生垮塌&#xff0c;导致造成2车受损后自燃&#xff0c;3人受轻伤。目前&#xff0c;四川省公安厅交通警察总队高速公路五支队十四大队民警已对现场进行双向管制。 作为世界第一桥梁…

Hadoop 之 Spark 配置与使用(五)

Hadoop 之 Spark 配置与使用 一.Spark 配置1.Spark 下载2.单机测试环境配置3.集群配置 二.Java 访问 Spark1.Pom 依赖2.测试代码1.计算 π 三.Spark 配置 Hadoop1.配置 Hadoop2.测试代码1.统计字符数 一.Spark 配置 环境说明环境版本AnolisAnolis OS release 8.6Jdkjava versi…

差速驱动机器人的车轮里程计模型

一、说明 车轮测程法是指使用旋转编码器(即连接到车轮电机以测量旋转的传感器)的测程法(即估计运动和位置)。这是轮式机器人和自动驾驶汽车定位的有用技术。 在本文中,我们将通过探索差速驱动机器人的车轮里程计模型来深入研究车轮里