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

Go语言设计Web框架

如何设计一个Web框架

项目规划

在开始设计Web框架之前,我们需要对整个项目进行规划。主要包括以下几个方面:

  • 项目结构
  • 依赖管理
  • 路由设计
  • 控制器设计
  • 日志和配置管理

项目结构

首先,我们定义项目的目录结构:

├── cmd/
│   └── main.go
├── config/
│   └── config.yaml
├── controllers/
│   └── blog_controller.go
├── handlers/
│   └── blog_handler.go
├── routers/
│   └── router.go
├── utils/
│   ├── log.go
│   └── config.go
└── go.mod

依赖管理

在 go.mod 文件中添加必要的依赖:

module mywebframework

go 1.18

require (github.com/gin-gonic/gin v1.7.4gopkg.in/yaml.v3 v3.0.1
)

自定义路由器设计

我们将使用 Gin 框架作为基础,自定义一个路由器。

路由器实现
在 routers/router.go 中实现路由器:

package routersimport ("github.com/gin-gonic/gin""mywebframework/controllers"
)func SetupRouter() *gin.Engine {router := gin.Default()// 设置路由api := router.Group("/api"){api.GET("/blogs", controllers.GetBlogs)api.POST("/blogs", controllers.CreateBlog)api.PUT("/blogs/:id", controllers.UpdateBlog)api.DELETE("/blogs/:id", controllers.DeleteBlog)}return router
}

控制器设计

控制器负责处理具体的业务逻辑。

博客控制器
在 controllers/blog_controller.go 中实现控制器:

package controllersimport ("net/http""strconv""github.com/gin-gonic/gin""mywebframework/utils"
)type Blog struct {ID      int    `json:"id"`Title   string `json:"title"`Content string `json:"content"`
}var blogs = make(map[int]Blog)func GetBlogs(c *gin.Context) {c.JSON(http.StatusOK, blogs)
}func CreateBlog(c *gin.Context) {var blog Blogif err := c.ShouldBindJSON(&blog); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}id := len(blogs) + 1blog.ID = idblogs[id] = blogc.JSON(http.StatusCreated, blog)
}func UpdateBlog(c *gin.Context) {idStr := c.Param("id")id, err := strconv.Atoi(idStr)if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})return}var blog Blogif err := c.ShouldBindJSON(&blog); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}if _, ok := blogs[id]; !ok {c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"})return}blogs[id].Title = blog.Titleblogs[id].Content = blog.Contentc.JSON(http.StatusOK, blogs[id])
}func DeleteBlog(c *gin.Context) {idStr := c.Param("id")id, err := strconv.Atoi(idStr)if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})return}if _, ok := blogs[id]; !ok {c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"})return}delete(blogs, id)c.JSON(http.StatusNoContent, nil)
}

日志和配置设计

日志和配置管理对于生产环境非常重要。

日志实现
在 utils/log.go 中实现日志功能:

package utilsimport ("log""os"
)func LogInfo(msg string) {log.Println("[INFO]", msg)
}func LogError(msg string) {log.Println("[ERROR]", msg)
}func init() {logFile, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)if err != nil {log.Fatal(err)}multiWriter := log.Writer()multiWriter = io.MultiWriter(multiWriter, logFile)log.SetOutput(multiWriter)
}

配置实现
在 utils/config.go 中实现配置加载:

package utilsimport ("io/ioutil""log""gopkg.in/yaml.v3"
)type Config struct {Port string `yaml:"port"`
}var Cfg Configfunc LoadConfig(path string) {yamlFile, err := ioutil.ReadFile(path)if err != nil {log.Fatalf("Error reading config file: %v", err)}err = yaml.Unmarshal(yamlFile, &Cfg)if err != nil {log.Fatalf("Error unmarshaling config data: %v", err)}
}

配置文件
在 config/config.yaml 中定义配置:

port: ":8080"

主程序

在 cmd/main.go 中启动主程序:

package mainimport ("mywebframework/routers""mywebframework/utils"
)func main() {utils.LoadConfig("config/config.yaml")router := routers.SetupRouter()router.Run(utils.Cfg.Port)
}

测试

现在,我们可以运行程序并测试各个API接口。

运行程序

go run cmd/main.go

测试API
使用 Postman 或者 curl 进行测试:

获取所有博客:

curl -X GET http://localhost:8080/api/blogs

创建博客:

curl -X POST -H "Content-Type: application/json" -d '{"title":"First Blog", "content":"This is the first blog."}' http://localhost:8080/api/blogs

更新博客:

curl -X PUT -H "Content-Type: application/json" -d '{"title":"Updated Blog", "content":"This is the updated blog."}' http://localhost:8080/api/blogs/1

删除博客:

curl -X DELETE http://localhost:8080/api/blogs/1

扩展Web框架

项目结构

我们将在原有的项目结构基础上添加新的目录和文件:

mywebframework/
├── cmd/
│   └── main.go
├── config/
│   └── config.yaml
├── controllers/
│   ├── blog_controller.go
│   └── user_controller.go
├── handlers/
│   ├── blog_handler.go
│   └── user_handler.go
├── middleware/
│   └── session.go
├── routers/
│   └── router.go
├── static/
│   └── index.html
├── templates/
│   └── login.html
├── utils/
│   ├── log.go
│   ├── config.go
│   └── i18n.go
└── go.mod

静态文件支持

静态文件支持是Web应用中常见的需求,通常用于处理CSS、JavaScript和HTML等文件。

添加静态文件目录

在 static/ 目录中添加一个简单的 HTML 文件 index.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Static File Example</title>
</head>
<body><h1>Hello, World!</h1>
</body>
</html>
在路由器中添加静态文件处理

在 routers/router.go 中添加静态文件处理:

package routersimport ("github.com/gin-gonic/gin""mywebframework/controllers""mywebframework/middleware"
)func SetupRouter() *gin.Engine {router := gin.Default()// 设置静态文件处理router.Static("/static", "./static")// 设置路由api := router.Group("/api"){api.GET("/blogs", controllers.GetBlogs)api.POST("/blogs", controllers.CreateBlog)api.PUT("/blogs/:id", controllers.UpdateBlog)api.DELETE("/blogs/:id", controllers.DeleteBlog)}auth := router.Group("/auth"){auth.POST("/login", controllers.Login)auth.POST("/logout", controllers.Logout)}router.Use(middleware.SessionMiddleware())// 设置模板路由router.LoadHTMLGlob("templates/*")router.GET("/", func(c *gin.Context) {c.HTML(http.StatusOK, "index.html", gin.H{})})return router
}

Session支持

Session 支持对于用户状态管理非常重要,特别是在需要登录验证的情况下。

安装依赖

在 go.mod 中添加 github.com/gin-contrib/sessions 和 github.com/gin-contrib/sessions/cookie 依赖:

go get github.com/gin-contrib/sessions
go get github.com/gin-contrib/sessions/cookie
实现Session中间件

在 middleware/session.go 中实现Session中间件:

package middlewareimport ("github.com/gin-contrib/sessions""github.com/gin-contrib/sessions/cookie""github.com/gin-gonic/gin"
)func SessionMiddleware() gin.HandlerFunc {store := cookie.NewStore([]byte("secret-key"))return sessions.Sessions("mysession", store)
}

表单支持

表单支持主要用于处理用户提交的数据,如登录表单。

实现用户控制器

在 controllers/user_controller.go 中实现用户控制器:

package controllersimport ("net/http""strings""github.com/gin-gonic/gin""github.com/gin-contrib/sessions"
)func Login(c *gin.Context) {session := sessions.Default(c)email := c.PostForm("email")password := c.PostForm("password")// 简单的验证逻辑if email == "test@example.com" && password == "password" {session.Set("user", email)session.Save()c.JSON(http.StatusOK, gin.H{"message": "Login successful"})} else {c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})}
}func Logout(c *gin.Context) {session := sessions.Default(c)session.Clear()session.Save()c.JSON(http.StatusOK, gin.H{"message": "Logout successful"})
}func IsAuthenticated(c *gin.Context) bool {session := sessions.Default(c)user, _ := session.Get("user").(string)return strings.TrimSpace(user) != ""
}
实现登录页面

在 templates/login.html 中实现登录页面:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Login</title>
</head>
<body><h1>Login</h1><form action="/auth/login" method="post"><label for="email">Email:</label><input type="email" id="email" name="email" required><br><br><label for="password">Password:</label><input type="password" id="password" name="password" required><br><br><button type="submit">Login</button></form>
</body>
</html>

用户认证

用户认证用于保护某些路由,只有经过认证的用户才能访问。

实现认证中间件

在 middleware/auth.go 中实现认证中间件:

package middlewareimport ("github.com/gin-gonic/gin""mywebframework/controllers"
)func AuthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {if !controllers.IsAuthenticated(c) {c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})c.Abort()return}c.Next()}
}
更新路由器

在 routers/router.go 中使用认证中间件:

package routersimport ("github.com/gin-gonic/gin""mywebframework/controllers""mywebframework/middleware"
)func SetupRouter() *gin.Engine {router := gin.Default()// 设置静态文件处理router.Static("/static", "./static")// 设置路由api := router.Group("/api"){api.GET("/blogs", controllers.GetBlogs)api.POST("/blogs", controllers.CreateBlog)api.PUT("/blogs/:id", controllers.UpdateBlog)api.DELETE("/blogs/:id", controllers.DeleteBlog)}auth := router.Group("/auth"){auth.POST("/login", controllers.Login)auth.POST("/logout", controllers.Logout)}router.Use(middleware.SessionMiddleware())router.Use(middleware.AuthMiddleware())// 设置模板路由router.LoadHTMLGlob("templates/*")router.GET("/", func(c *gin.Context) {c.HTML(http.StatusOK, "index.html", gin.H{})})return router
}

多语言支持

多语言支持使得应用能够适应不同地区的用户。

安装依赖

在 go.mod 中添加 github.com/nicksnyder/go-i18n/v2/i18n 依赖:

go get github.com/nicksnyder/go-i18n/v2/i18n
实现多语言支持

在 utils/i18n.go 中实现多语言支持:

package utilsimport ("github.com/nicksnyder/go-i18n/v2/i18n""golang.org/x/text/language"
)var (bundle     *i18n.Bundlelocalizer  *i18n.LocalizerlocaleTags = map[string]language.Tag{"en": language.English,"zh": language.Chinese,}
)func init() {bundle = i18n.NewBundle(language.English)bundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal)// 加载翻译文件enMessages := `greeting: Hello, {{.Name}}!`zhMessages := `greeting: 你好,{{.Name}}!`bundle.LoadTranslationTemplate(enMessages, "en")bundle.LoadTranslationTemplate(zhMessages, "zh")localizer = i18n.NewLocalizer(bundle, "en")
}func TranslateMessage(tag string, messageID string, args ...interface{}) (string, error) {t, ok := localeTags[tag]if !ok {t = language.English}localizer := i18n.NewLocalizer(bundle, t.String())return localizer.Localize(&i18n.LocalizeConfig{MessageID: messageID, TemplateData: args})
}
更新控制器

在 controllers/blog_controller.go 中使用多语言支持:

package controllersimport ("net/http""strconv""github.com/gin-gonic/gin""mywebframework/utils"
)type Blog struct {ID      int    `json:"id"`Title   string `json:"title"`Content string `json:"content"`
}var blogs = make(map[int]Blog)func GetBlogs(c *gin.Context) {c.JSON(http.StatusOK, blogs)
}func CreateBlog(c *gin.Context) {var blog Blogif err := c.ShouldBindJSON(&blog); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}id := len(blogs) + 1blog.ID = idblogs[id] = blogc.JSON(http.StatusCreated, blog)
}func UpdateBlog(c *gin.Context) {idStr := c.Param("id")id, err := strconv.Atoi(idStr)if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})return}var blog Blogif err := c.ShouldBindJSON(&blog); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}if _, ok := blogs[id]; !ok {c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"})return}blogs[id].Title = blog.Titleblogs[id].Content = blog.Contentc.JSON(http.StatusOK, blogs[id])
}func DeleteBlog(c *gin.Context) {idStr := c.Param("id")id, err := strconv.Atoi(idStr)if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})return}if _, ok := blogs[id]; !ok {c.JSON(http.StatusNotFound, gin.H{"error": "Blog not found"})return}delete(blogs, id)c.JSON(http.StatusNoContent, nil)
}func Greeting(c *gin.Context) {tag := c.Query("lang")message, err := utils.TranslateMessage(tag, "greeting", c.Param("name"))if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}c.JSON(http.StatusOK, gin.H{"greeting": message})
}
更新路由器

在 routers/router.go 中添加多语言支持的路由:

package routersimport ("github.com/gin-gonic/gin""mywebframework/controllers""mywebframework/middleware"
)func SetupRouter() *gin.Engine {router := gin.Default()// 设置静态文件处理router.Static("/static", "./static")// 设置路由api := router.Group("/api"){api.GET("/blogs", controllers.GetBlogs)api.POST("/blogs", controllers.CreateBlog)api.PUT("/blogs/:id", controllers.UpdateBlog)api.DELETE("/blogs/:id", controllers.DeleteBlog)}auth := router.Group("/auth"){auth.POST("/login", controllers.Login)auth.POST("/logout", controllers.Logout)}router.Use(middleware.SessionMiddleware())router.Use(middleware.AuthMiddleware())// 设置模板路由router.LoadHTMLGlob("templates/*")router.GET("/", func(c *gin.Context) {c.HTML(http.StatusOK, "index.html", gin.H{})})// 添加多语言支持的路由router.GET("/greeting/:name", controllers.Greeting)return router
}
pprof支持

pprof 是 Go 标准库提供的性能分析工具,可以帮助我们分析应用的性能瓶颈。

启用 pprof

在 routers/router.go 中启用 pprof

package routersimport ("github.com/gin-gonic/gin""net/http"_ "net/http/pprof""mywebframework/controllers""mywebframework/middleware"
)func SetupRouter() *gin.Engine {router := gin.Default()// 设置静态文件处理router.Static("/static", "./static")// 设置路由api := router.Group("/api"){api.GET("/blogs", controllers.GetBlogs)api.POST("/blogs", controllers.CreateBlog)api.PUT("/blogs/:id", controllers.UpdateBlog)api.DELETE("/blogs/:id", controllers.DeleteBlog)}auth := router.Group("/auth"){auth.POST("/login", controllers.Login)auth.POST("/logout", controllers.Logout)}router.Use(middleware.SessionMiddleware())router.Use(middleware.AuthMiddleware())// 设置模板路由router.LoadHTMLGlob("templates/*")router.GET("/", func(c *gin.Context) {c.HTML(http.StatusOK, "index.html", gin.H{})})// 添加多语言支持的路由router.GET("/greeting/:name", controllers.Greeting)// 启用 pprofrouter.GET("/debug/pprof/", gin.WrapH(http.HandlerFunc(pprof.Index)))router.GET("/debug/pprof/cmdline", gin.WrapH(http.HandlerFunc(pprof.Cmdline)))router.GET("/debug/pprof/profile", gin.WrapH(http.HandlerFunc(pprof.Profile)))router.GET("/debug/pprof/symbol", gin.WrapH(http.HandlerFunc(pprof.Symbol)))router.GET("/debug/pprof/trace", gin.WrapH(http.HandlerFunc(pprof.Trace)))return router
}
测试

现在,我们可以运行程序并测试各个新增功能。

运行程序

go run cmd/main.go

测试静态文件
访问静态文件:

curl http://localhost:8080/static/index.html

测试登录和注销

访问登录页面:

curl http://localhost:8080/auth/login

提交登录表单:

curl -X POST -d "email=test@example.com&password=password" http://localhost:8080/auth/login

注销测试多语言支持
访问多语言问候:

curl http://localhost:8080/greeting/john?lang=en
curl http://localhost:8080/greeting/john?lang=zh
测试 pprof

访问 pprof 页面:

curl http://localhost:8080/debug/pprof/

Web服务

使用net/http包搭建Web服务

基本用法

package mainimport ("fmt""net/http"
)func helloHandler(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello, World!")
}func main() {http.HandleFunc("/", helloHandler)http.ListenAndServe(":8080", nil)
}

这段代码定义了一个简单的HTTP服务器,监听8080端口,并对所有请求返回"Hello, World!"。

HTTP客户端

发送GET请求

package mainimport ("io/ioutil""net/http""fmt"
)func main() {resp, err := http.Get("https://www.ulcerprevention.com")if err != nil {// 处理错误}defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)fmt.Println(string(body))
}

Request对象

获取查询参数

func handleRequest(w http.ResponseWriter, r *http.Request) {query := r.URL.Query()fmt.Fprintf(w, "Query: %v", query)
}

设置和读取Cookie

func setCookie(w http.ResponseWriter, r *http.Request) {cookie := http.Cookie{Name: "session", Value: "12345"}http.SetCookie(w, &cookie)
}func getCookie(w http.ResponseWriter, r *http.Request) {cookie, err := r.Cookie("session")if err == nil {fmt.Fprintf(w, "Cookie: %s", cookie.Value)}
}

Session

虽然标准库没有直接支持Session,但可以通过第三方库实现,如github.com/go-session/session。

Go日志

基础日志记录

import ("log"
)func main() {log.Println("This is a log message.")
}

处理文件

读取文件

data, err := ioutil.ReadFile("file.txt")
if err != nil {// 处理错误
}
fmt.Println(string(data))

中间件

实现日志中间件

func loggingMiddleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {log.Println(r.Method, r.URL.Path)next.ServeHTTP(w, r)})
}

Redirect重定向

执行重定向

func redirectHandler(w http.ResponseWriter, r *http.Request) {http.Redirect(w, r, "/", http.StatusFound)
}

Golang下载文件

下载文件到本地

resp, err := http.Get("http://example.com/file")
if err != nil {// 处理错误
}
defer resp.Body.Close()out, err := os.Create("localfile")
if err != nil {// 处理错误
}
defer out.Close()io.Copy(out, resp.Body)

数据验证

使用validator库

import ("github.com/go-playground/validator/v10"
)type User struct {Name string `validate:"required"`
}var validate = validator.New()func validateUser(user User) error {return validate.Struct(user)
}

更多相关信息,https://t.me/gtokentool 

相关文章:

Go语言设计Web框架

如何设计一个Web框架 项目规划 在开始设计Web框架之前&#xff0c;我们需要对整个项目进行规划。主要包括以下几个方面&#xff1a; 项目结构依赖管理路由设计控制器设计日志和配置管理 项目结构 首先&#xff0c;我们定义项目的目录结构&#xff1a; ├── cmd/ │ └…...

2024年10月28日练习(双指针算法)

一.11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09; 1.题目描述&#xff1a; 这个题目代表的意思就是数组上每个对应的值就相当于每条垂直线的高度&#xff0c;就相当于短板效应&#xff0c;两 个高度的线会取最短的长度因为那样水才不会漏。而两条线的数组的下标…...

Objective-C 音频爬虫:实时接收数据的 didReceiveData_ 方法

在互联网技术领域&#xff0c;数据的获取和处理是至关重要的。尤其是对于音频内容的获取&#xff0c;实时性和效率是衡量一个爬虫性能的重要指标。本文将深入探讨在Objective-C中实现音频爬虫时&#xff0c;如何高效地使用didReceiveData:方法来实时接收数据&#xff0c;并通过…...

提升网站流量和自然排名的SEO基本知识与策略分析

内容概要 在当今数字化时代&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;成为加强网站可见度和提升流量的重要工具。SEO的基础知识包括理解搜索引擎的工作原理&#xff0c;以及如何通过优化网站内容和结构来提高自然排名。白帽SEO和黑帽SEO代表了两种截然不同的策略&a…...

雷池社区版compose文件配置讲解--fvm

在现代网络安全中&#xff0c;选择合适的 Web 应用防火墙至关重要。雷池&#xff08;SafeLine&#xff09;社区版免费切好用。为网站提供全面的保护&#xff0c;帮助网站抵御各种网络攻击。 docker-compose.yml 文件是 Docker Compose 的核心文件&#xff0c;用于定义和管理多…...

基于51单片机的智能断路器proteus仿真

地址&#xff1a; https://pan.baidu.com/s/16lfGgrgVr9V7JehonMNVQA 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectro…...

(N-154)基于springboot酒店预订管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 前端技术&#xff1a;AdminLTEBootstrapLayUIHTMLjQuery 服务端技术&#xff1a;springbootmybatis-plusthymeleaf 本项目分前台和后台…...

elasticsearch 8.x 插件安装(三)之拼音插件

elasticsearch 8.x 插件安装&#xff08;三&#xff09;之拼音插件 elasticsearch插件安装合集 elasticsearch插件安装&#xff08;一&#xff09;之ik分词器安装&#xff08;含MySQL更新&#xff09; elasticsearch 8.x插件&#xff08;二&#xff09;之同义词安装如何解决…...

快速遍历包含合并单元格的Word表格

Word中的合并表格如下&#xff0c;现在需要根据子类&#xff08;例如&#xff1a;果汁&#xff09;查找对应的品类&#xff0c;如果这是Excel表格&#xff0c;那么即使包含合并单元格&#xff0c;也很容易处理&#xff0c;但是使用Word VBA进行查找&#xff0c;就需要一些技巧。…...

手机收银云进销存管理软件,商品档案Excel格式批量导入导出,一键导入Excel的商品档案

如果您有Excel的商品档案&#xff0c;那么就可以批量导入到我们的手机云进销存软件系统里&#xff0c;就不需要人工手工一个个商品的新建商品档案&#xff0c;大大提高工作效率。如果您看下面的步骤不会操作&#xff0c;可以联系我们技术支持&#xff0c;来帮您把商品档案导入。…...

html 中识别\n自动换行

CSS实现&#xff1a;white-space <div style"white-space: pre-wrap;" v-html"str"> </div>white-space: normal|nowrap|pre|pre-line|pre-wrap|initial|inherit;值描述换行符空格和制表符文字换行行尾空格normal默认。空白会被浏览器忽略。合…...

用QWebSocketServer写websocket服务端

1. 引入必要的头文件 #include <QCoreApplication> #include <QWebSocketServer> #include <QWebSocket> #include <QDebug> #include <QObject>QCoreApplication&#xff1a;用于创建控制台应用的事件循环。QWebSocketServer&#xff1a;提供 …...

云原生后端:现代应用架构的核心力量

云原生后端&#xff1a;现代应用架构的核心力量 云原生后端是基于云环境进行设计和开发的一种理念&#xff0c;利用云服务和云原生技术构建的服务端应用。它旨在提供灵活、高效、弹性和可扩展的解决方案&#xff0c;成为推动应用现代化的核心力量。本文将详细探讨云原生后端的…...

arcgis中dem转模型导入3dmax

文末分享素材 效果 1、准备数据 (1)DEM (2)DOM 2、打开arcscene软件 3、加载DEM、DOM数据 4、设置DOM的高度为DEM...

Python自动化测试中的Mock与单元测试实战

在软件开发过程中&#xff0c;自动化测试是确保代码质量和稳定性的关键一环。而Python作为一门灵活且强大的编程语言&#xff0c;提供了丰富的工具和库来支持自动化测试。本文将深入探讨如何结合Mock与单元测试&#xff0c;利用Python进行自动化测试&#xff0c;以提高代码的可…...

物联网海量数据下的时序数据库选型:InfluxDB、TDEngine、MongoDB与HBase对比与建议

随着物联网&#xff08;IoT&#xff09;的普及&#xff0c;各行业纷纷部署大量传感器、设备生成的数据流&#xff0c;面对如此海量的时间序列数据&#xff0c;如何高效存储、查询和分析成为关键。为此&#xff0c;时序数据库&#xff08;Time Series Database, TSDB&#xff09…...

Python中的数据可视化:Matplotlib基础与高级技巧

Python中的数据可视化&#xff1a;Matplotlib基础与高级技巧 数据可视化是数据分析和数据科学中不可或缺的一部分。通过图表&#xff0c;我们可以更直观地观察数据的分布和趋势。Matplotlib作为Python最基础、也是最广泛使用的绘图库之一&#xff0c;不仅支持多种常用图表&…...

数组名和指针数组名深度复习

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> //sizeof只关注占用内存空间的大小&#xff0c;不在乎内存中存放的是什么 //是操作符 /* int main() { char arr[] { "abcdef" }; //a b c d e f \0 printf("%d\n", sizeof(arr));//…...

Linux 诞生

目录 Linux诞生背景 Linus Torvalds的创举 Linux内核的首次发布 Linux诞生背景 在计算机操作系统的发展史上&#xff0c;Linux是一个重要的里程碑。它的诞生源于对自由、开放和协作精神的追求&#xff0c;以及对Unix操作系统的深入研究和改进。 在1991年之前&#xff0c;Un…...

借助Aspose.Email,管理受密码保护的 PST 文件

在当今的数字环境中&#xff0c;保护您的数据比以往任何时候都更加重要。确保您的电子邮件数据受到密码保护是维护安全性的关键步骤。对于使用 Microsoft Outlook 数据的开发人员来说&#xff0c;管理受密码保护的 PST&#xff08;个人存储表&#xff09;文件可能是一项关键任务…...

MySQL数据库MHA高可用

目录 一、MHA简述 二、MHA 的组成 三、MHA 的特点 四、MHA工作原理 五、MHA部署步骤 六、搭建 MySQL MHA MHA一主两从高可用集群示意图 实验环境 1. Master、Slave1、Slave2 节点上安装 mysql5.7 2. 关闭防火墙 3. 修改 Master、Slave1、Slave2 节点的主机名 4. 修…...

DevEco Studio使用技巧和插件推荐

DevEco Studio是一款强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;为开发者提供了丰富的功能和插件。以下是一些使用技巧和插件推荐&#xff1a; 使用技巧 设置中文界面&#xff1a; 打开DevEco Studio&#xff0c;选择“Configure”&#xff0c;再点击“Prefer…...

使用Node.js与Express构建RESTful API

&#x1f496; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4bb; Gitee主页&#xff1a;瑕疵的gitee主页 &#x1f680; 文章专栏&#xff1a;《热点资讯》 使用Node.js与Express构建RESTful API 1 引言 2 Node.js与Express简介 3 安装Node.js与Express 4 创建Express项目 5…...

从0开始搭建一个生产级SpringBoot2.0.X项目(二)SpringBoot应用连接数据库集成mybatis-plus

前言 最近有个想法想整理一个内容比较完整springboot项目初始化Demo。 连接Oracle数据库集成mybatis-plus&#xff0c;自定义WrapperFactory。配置代码生成器 一、引入jar包 <!--oracle驱动 --><dependency><groupId>org.springframework.boot</groupI…...

Docker部署教程:打造流畅的斗地主网页小游戏

Docker部署教程&#xff1a;打造流畅的斗地主网页小游戏 一、项目介绍项目简介项目预览 二、系统要求环境要求环境检查Docker版本检查检查操作系统版本 三、部署斗地主网页小游戏下载镜像创建容器检查容器状态查看容器日志安全设置 四、访问斗地主网页小游戏五、总结 一、项目介…...

redis的客户端

目录 redis的客户端一&#xff1a;jedis1&#xff1a;jedis的使用步骤&#xff1a;2&#xff1a;jedis连接池 二&#xff1a;springDataRedis1:入门使用2&#xff1a;配置序列化器3&#xff1a;stringRedisTemplate redis的客户端 一&#xff1a;jedis 1&#xff1a;jedis的使…...

图片分类标注工具python

图片分类标注工具 运行代码&#xff1a;将代码保存到 Python 文件中并运行。选择文件夹&#xff1a;运行时会弹出对话框&#xff0c;选择要分类的图片文件夹。标注分类&#xff1a;程序会逐张显示图片&#xff0c;你可以在下方输入框中输入类别标签&#xff0c;并点击“Next”…...

Rust命令行,实现自动反编译Android APK包工具

Rust-CLI实现自动反编译APK Rust提供了比较好的CLI接口,可以快速的编写命令行应用, 用于日常的工具类使用。 分享一个用Rust命令行实现自动反编译Android APK包工具&#xff0c;是之前学习Rust写的一个练手小工具&#xff0c;可以快速反编译APK&#xff0c;同时也学习下用Rust…...

10. NSTableView Table 数据表格

表格是非常重要和复杂的一个控件&#xff0c;本节会用大量篇幅来把表格这东西力求讲清楚。 基本设置 表格结构 表格是 OS X 组件中为数不多采用了MVC设计模式来实现的控件&#xff0c;即tableView–dataSource–Delegate&#xff0c;这种分层架构给处理数据带来了极大的便利…...

javase笔记8---File与IO流

File类型 简介 在程序中&#xff0c;使用java.io.File这个类来描述和操作磁盘上的一个文件或文件夹(目录)。 File这个类&#xff0c;能新建、删除、移动&#xff0c;重命名文件或文件夹&#xff0c;也能获取或者修改文件或文件夹的信息(如大小&#xff0c;修改时间等)&#xf…...

做企业网站设计与实现/优化关键词排名推广

前言 kafka的外在表现很像消息系统&#xff0c;允许发布和订阅消息流&#xff0c;但是它和传统的消息系统有很大的差异&#xff1a; 首先&#xff0c;kafka是个现代分布式系统&#xff0c;以集群的方式运行&#xff0c;可以自由伸缩 其次&#xff0c;kafka可以按照要求存储数…...

wordpress设置特殊字体/江门seo外包公司

在下载的软件工具的时候&#xff0c;会被询问到你的计算机是32位还是64位&#xff0c;有不了解自己电脑的朋友可能会一头雾水&#xff0c;软件安装便不能继续。怎么看电脑是32位还是64位&#xff1f;本篇就来教你们怎么查看电脑是32位还是64位的。用电脑的人都知道电脑处理器(C…...

在什么网站做调查问卷/百度做个人简介多少钱

package com.Summer_0421.cn;import java.util.Arrays; import java.util.Scanner;/*** author Summer* 使用java面向对象之前的知识 完成规定的功能;* 附加要求 :* 1. 可以注册多个用户* 2. 每个注册的用户都可以登录* 3. 注册的用户名是唯一的* 4. 已经登录的用户 必须注销登…...

公司网站管理制定的作用/网络营销推广的要点

一.通过python3安装cocoapigit clone https://github.com/pdollar/coco.gitcd coco/PythonAPIpython3 setup.py build_ext --inplacepython3 setup.py build_ext install二.验证cocoapi是否安装成功进入python命令行就可以直接导入了&#xff0c;执行import pycocotools命令不报…...

可以做打赏视频的网站/福建seo快速排名优化

RxJava 的合并操作符主要包括如下几个&#xff1a;startWith &#xff1a;在数据序列的开头增加一项数据merge &#xff1a;将多个 Observable 合并为一个mergeDelayError &#xff1a;合并多个 Observable&#xff0c;让没有错误的 Observable 都完成后再发射错误通知zip &…...

制作网站图片不显示/网络营销软文范文

目录 一、事件监听 API 二、同步 API 三、异步 API 四、API大全 五、api的私人订制 一、事件监听 API 以 on 开头的 API 用来监听某个事件是否触发。 二、同步 API 以 Sync 结尾的 API 都是同步 API。 三、异步 API 大多数 API 都是异步 API。 四、API大全 请戳这里&a…...