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

第1章 认识Flask

学习目标

  • 了解Flask框架,能够说出Flask框架的发展史以及特点

  • 熟悉隔离Python环境的创建方式,能够独立在计算机上创建隔离的Python环境

  • 掌握Flask的安装方式,能够独立在计算机上安装Flask框架

  • 掌握PyCharm配置隔离环境的方式,能够独立在PyCharm工具中配置隔离环境

  • 掌握Flask程序的基本结构,能够归纳Flask类、路由、视图函数和开发服务器的作用

  • 熟悉配置项,能够列举至少5个Flask配置项的作用

  • 掌握配置信息的使用,能够通过访问字典元素、导入文件和导入对象这3种方式

  • 熟悉Flask扩展包,能够列举至少3个Flask扩展包的用途

Web应用程序发展至今涵盖的技术持续扩大,这在一定程度上给Web应用程序的开发者增加了开发难度。为了提高开发者编写Web应用程序的效率,Python引入了一些成熟的Web应用程序框架,开发者只需要按照框架的约定,在指定位置编写核心业务的逻辑代码即可。 Flask作为目前比较流行的Web应用程序框架,自发布以来备受好评,在Web开发领域占据一席之地。本章将围绕着Flask框架的入门知识进行讲解,使读者对Flask框架建立初步的认识。

1.1 Flask简介

Flask是一个用Python编写的微框架,它可以帮助开发者在短时间内完成一个功能丰富的Web应用程序。微框架并不意味着将Web应用程序的所有代码放置在一个py文件中,而是意味着代码简洁且易于扩展。 Flask默认依赖两个外部库:Werkzeug WSGI工具包和Jinja2模板引擎,它只保留了Web开发的核心功能,而不包括用户认证、表单验证、发送邮件等其他Web应用程序框架通常包含的功能。开发者若需要给Flask程序添加额外的功能,可以在Flask官网找到相应的扩展包进行开发。

Flask之所以如此受欢迎,离不开其自身具备的几个特点。

1.内置开发服务器和调试器

Flask自带开发服务器,它可以让开发者在调试Web应用程序时无须安装其他的网络服务器,比如Tomcat、JBoss、Apache等,为程序正式投入运行提供了一定的保障。另外,基于Flask开发的程序默认处于调试状态,当程序运行出现异常时,Flask程序会同时向启动Python程序的控制台和HTTP客户端发送错误信息。

2.使用Jinja2模板

Flask使用Jinja2模板引擎将HTML页面与应用程序联系起来。Jinja2是一个灵活的模板引擎技术,它由Django模板引擎发展而来,但比Django模板引擎更加高效。Jinja2模板引擎使用配制的语义系统,它不仅提供了灵活的模板继承技术,还可以自动防止XSS跨站攻击。

3.极强的定制型

Flask社区提供了功能丰富的扩展包,让程序在保持核心功能简单的同时实现功能的丰富与扩展。开发者可以根据自己的需求添加扩展包,也可以自行开发扩展包,借助扩展包来快速开发一个功能丰富的网站,并实现对网站的个性化定制。

4.基于Unicode编码

Flask完全基于Unicode编码格式,这对制作非纯ASCII字符集的网站而言非常方便。由于HTTP协议支持传输任何编码格式,但该协议要求每次传输时要在请求头中显式指定使用的编码格式,Flask程序默认会为请求头指定UTF-8编码,使开发者无须再担心编码问题。

5.完全兼容WSGI 1.0标准

WSGI(Web服务器网关接口)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口,它制定了一套通信标准,保证Web服务器可以跟Web应用程序之间相互通信。Flask程序完全兼容WSGI,它能够运行到任何Web服务器。

6.无缝衔接单元测试

Flask提供了一个与Python自带的单元测试框架unittest无缝衔接的测试接口,即Flask对象的test_client()函数,通过该函数测试程序可以模拟HTTP访问客户端,调用Flask路由绑定的视图函数,并且获取视图函数的返回值进行自定义的验证。

1.2 搭建Flask开发环境

1.2.1 创建虚拟的Python环境

在实际开发Flask程序时,程序的不同版本可能会依赖不同的环境,这时需要在系统中安装多个版本的Python解释器或依赖包,如果直接在物理环境中进行配置,那么多个版本的Python解释器之间可能会产生干扰。为了解决这个问题,我们需要使用virtualenv工具创建虚拟环境,以隔离不同版本的Python解释器。

在使用virtualenv工具之前,我们需要先在计算机中安装virtualenv工具。virtualenv工具可通过pip命令在线安装,具体命令如下所示。

pip install virtualenv

一台计算机中可以创建多个虚拟环境,我们可以将不同版本的Python解释器安装到不同的虚拟环境中。

1.创建虚拟环境

创建虚拟环境的命令格式如下所示。

virtualenv 虚拟环境名
virtualenv –p Python解释器的路径 虚拟环境名

若通过第1个命令创建虚拟环境,则虚拟环境中使用的Python版本是由系统环境变量设置的Python解释器决定的;若通过第2个命令创建虚拟环境,则虚拟环境中使用的Python版本是由用户显式指定的Python解释器决定的。

例如,在E:\env_space目录下通过第1个命令创建虚拟环境flask_env,具体命令如下所示。

E:\env_space>virtualenv flask_env

2.使用虚拟环境

若希望使用虚拟环境,需要执行虚拟环境目录Scripts下的activate文件。例如,使用刚刚创建的虚拟环境flask_env,具体命令如下所示。

E:\env_space>.\flask_env\Scripts\activate

上述命令执行后,会工作在虚拟环境flask_env下,并在提示符前面显示虚拟环境的名称flask_env,具体如下所示。

(flask_env) E:\env_space>

3.退出虚拟环境

使用deactivate命令可以退出当前工作的虚拟环境。例如,使用deactivate命令退出虚拟环境flask_env,具体命令如下所示。

(flask_env) E:\env_space>deactivate
E:\env_space>

多学一招:requirement.txt

不同的Flask项目可能会依赖不同的虚拟环境,若要在新计算机中运行项目,就需要重复为该项目配置一套相同的虚拟环境,为了区分和记录每个项目的依赖包及其版本,以便在新计算机中复现项目的虚拟环境,我们可以通过一个requirement.txt文件记录项目的所有依赖包及其版本号,以便在新计算机中实现一键安装的效果。 需要说明的是,requirement.txt文件的名称是开发者之间约定俗成的,也可以进行重新命名。

requirement.txt文件的使用一般分为以下两步。

(1)通过pip命令将虚拟环境依赖的扩展包及其版本号记录到requirement.txt文件中,具体命令如下所示。

pip freeze > requirements.txt

(2)在新计算机中,通过pip命令根据requirement.txt文件记录的依赖包及其版本号安装相应版本的依赖包,具体命令如下所示。

pip install -r requirements.txt

1.2.2 安装Flask

若我们要开发Flask项目,还需要在虚拟环境中安装Flask。Flask是由Python编写的框架,也可以直接通过pip命令进行安装。例如,在虚拟环境flask_env中使用pip命令安装Flask 2.0.2,具体命令如下所示。

(flask_env) E:\env_space>pip install flask 

Flask安装了6个依赖包,分别是Jinja2、MarkupSafe、Werkzeug、click、colorama和itsdangerous。

依赖包版本说明
Jinja23.0.2模板渲染引擎
MarkupSafe2.0.1HTML字符转义工具
Werkzeug2.0.2WSGI工具集,它封装了Web框架中的很多内容,包含请求、响应、WSGI开发服务器、调试器和重载器
click8.0.1命令行工具
colorama0.4.4命令行彩色显示工具
itsdangerous2.0.1提供各种加密签名功能

为了验证Flask包是否安装成功,我们可以在命令行窗口中输入“python”进入Python解释器,并在Python解释器中尝试导入Flask,具体如下所示。

(flask_env) E:\env_space>python
Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import flask

执行导入flask库的指令后,没有产生任何的错误信息,说明安装成功了。

1.2.3 安装PyCharm

PyCharm是一款较多开发者使用的集成开发环境,它具有调试、语法高亮、Project管理、代码跳转、智能提示、单元测试、版本控制等功能,可以实现程序编写、运行、测试一体化。

打开浏览器,访问PyCharm官网的下载页面。

Professional是专业版本,该版本支持Django、Flask、远程开发、数据库和SQL语句等更多的高级功能,且需要用户付费购买。 Community是社区版本,该版本属于轻量级的Python开发工具,且是免费的。

该安装步骤过程在python程序设计课程中已经介绍过了,这里不再赘述。

1.2.4 在PyCharm中配置虚拟环境

若要使用PyCharm工具开发Flask程序,既可以另行创建新的虚拟环境,也可以使用创建好的虚拟环境进行开发。接下来,在PyCharm工具中新建一个项目,并为该项目配置虚拟环境flask_env。

首次打开PyCharm工具时会进入Welcome to PyCharm界面。

单击Welcome to PyCharm界面中的“Create New Project”按钮进入New Project界面。

Location文本框用于填写项目的路径及名称,默认名称为untitled; Project Interpreter用于选择Python解释器,它包含New environment using和Existing interpreter两个选项,其中New environment using代表新创建的环境,Existing interpreter代表已经存在的Python解释器。

将项目的名称由untitled修改为first_pro,单击标注的 按钮弹出Add Python Interpreter窗口。

Virtualenv Environment表示添加虚拟环境中的Python解释器,Conda Environment表示添加Conda环境中的Python解释器,System Interpreter表示添加本地的Python解释器。

单击Add Python Interpreter窗口中标注的 按钮,弹出Select Python Interpreter窗口,在该窗口中选择虚拟环境flask_env中的python.exe。

单击Select Python Interpreter窗口中的“OK”按钮,关闭Select Python Interpreter窗口,跳转回Add Python Interpreter窗口,在Add Python Interpreter窗口中单击“OK”按钮,关闭Add Python Interpreter窗口并跳转回New Project界面,此时New Project界面中显示了选择的Python解释器。

单击New Project界面中的“Create”按钮,进入first_pro项目的主界面。

1.3 开发第一个Flask程序

1.3.1 编写Hello Flask程序

在first_pro项目中创建一个名称app的py文件,并在该文件中编写Hello Flask程序的代码,具体代码如下所示。

# 导入Flask类
from flask import Flask
#实例化Flask类
app=Flask(__name__)
# 定义视图函数,并为该函数注册路由
@app.route("/")
def hello_flask():
    return "<p>Hello,Flask!</p>"
if __name__ == "__main__":
    # 启动开发服务器
    app.run()

在浏览器的地址栏中输入http://127.0.0.1:5000/,按下回车键后看到的页面效果如下图所示。

1.3.2 程序的基本结构

Hello Flask程序包含3个比较重要的部分,分别是Flask类、开发服务器、路由与视图。

1.Flask类

Flask类是flask包中的核心类,该类中封装了很多与Flask程序相关的方法,通过这些方法可以轻松地对Flask程序进行相应的操作。所有的Flask程序中必须要创建一个Flask类的对象,创建Flask类对象的方式非常简单,只需要调用构造方法即可。

在Hello Flask程序中,创建Flask类对象的代码如下所示创建Flask类对象的代码如下所示。

app = Flask(__name__)

上述代码中,构造方法中传入了一个必选参数namename是Flask中一个特殊的变量,用于保存程序主模块或者包的名称。除了必选参数外,构造方法中还可以根据需要传入以下几个可选参数。

static_folder:用于指定存放静态文件的文件夹名称,默认值为static。 static_url_path:用于指定前端访问静态文件的路径,默认值为static_folder的名称。 template_folder:用于指定存放模板文件的文件夹名称,默认为应用程序根路径下的templates文件夹。

2.开发服务器

Flask的依赖包Werkzeug提供了一个简易的开发服务器,供开发人员在开发和测试阶段运行程序,可以暂时不配置生产服务器(如Apache)。Flask程序创建成功以后,便可以启用开发服务器测试程序是否有效。 使用开发服务器有两种方式,一种方式是通过命令行使用开发服务器,另一种方式是通过代码使用开发服务器,即调用Flask类的对象的run()方法。

app.run()

host:运行当前程序的主机名称,默认值为'127.0.0.1'或'localhost'。 port:运行当前程序的主机对应的端口号,默认值为5000。 debug:是否启用调试模式,默认值为False。

3.路由与视图

路由是一种目前主流的Web框架中应用的技术,用于帮助用户直接根据URL访问某个页面,而无须再从主页导航到这个页面。当初始化Flask类对象时,会注册程序中所有的URL规则,一旦用户在浏览器发送访问某个页面的URL请求后,服务器便会将该URL请求交给Flask程序,这时Flask程序会根据URL规则找到与之关联的视图。

在Flask中,视图是Python函数或Python类,用于对浏览器发送的请求进行处理,并返回响应内容给Web服务器。视图返回的响应内容既可以是一个包含HTML代码的字符串,也可以表单等。

例如,在Hello Flask程序中,定义视图函数及URL规则的代码如下所示。

@app.route("/")
def hello_flask():
    return "<p>Hello, Flask!</p>"

1.4 Flask程序配置

1.4.1 常用配置项介绍

在开发Flask程序的过程中,根据不同的应用环境需要不同的配置,比如开关调试模式、密钥以及其他依赖于环境的内容,经常会将常用的属性存储在系统配置文件中,这样可以提高程序的复用性。 Flask内置了众多配置项,这些配置项都是大写形式的变量,开发人员可以通过设置这些配置项来定制程序的一些行为。

配置项说明
ENV指定应用运行的环境,默认值为'production'
DEBUG启用/禁用调试模式。当ENV的值为'development'时, DEBUG的默认值为True,否则为False
TESTING启用/禁用测试模式,默认值为False
PROPAGATE_EXCEPTIONS显式启用/禁用异常的传播。在PROPAGATE_EXCEPTIONS未设置的情况下,若TESTING 或 DEBUG 为True,则该配置项隐式设为True
PRESERVE_CONTEXT_ON_EXCEPTION当一个异常发生时,不会弹出请求上下文,默认值为None
TRAP_HTTP_EXCEPTIONS若没有处理HTTPException异常的处理器,是否重新引发该异常被交互调试器处理,而并非将HTTPException作为一个简单错误响应进行返回,默认值为False
TRAP_BAD_REQUEST_ERRORS尝试操作一个请求字典中不存在的键,会返回一个400页面
配置项说明
SECRET_KEY表示密钥,用于安全签署会话Cookie,也可用于应用或扩展的其他安全需求,它的值是一个长的随机字符串
SESSION_COOKIE_NAME会话Cookie的名称,默认值为'session'
SESSION_COOKIE_DOMAIN会话Cookie会生效的域匹配规则
SESSION_COOKIE_PATH会话Cookie的路径
SESSION_COOKIE_HTTPONLY控制Cookie是否被设为HTTP only标志,默认值为True
SESSION_COOKIE_SECURE控制Cookie是否被设为secure标志,默认值为True
SESSION_COOKIE_SAMESITE限制外部站点的请求如何发送 cookie,默认值为None,可以被设置为'Lax'(推荐)或者'Strict'
配置项说明
PERMANENT_SESSION_LIFETIME控制长期会话的生命周期,默认值为timedelta(days=31),即 2678400 秒
SESSION_REFRESH_EACH_REQUEST当 session.permanent 为True时,控制每个响应是否都发送Cookie,默认值为True
USE_X_SENDFILE启用/禁用X-Sendfile,默认值为False。有些网络服务器, 如 Apache ,会启动X-Sendfile,以便更有效地提供数据服务。本配置项仅在使用这种服务时才有意义
SEND_FILE_MAX_AGE_DEFAULT默认缓存控制的最大期限,以秒为单位,默认值为43200(12小时)秒
SERVER_NAME设置应用绑定的主机和端口
APPLICATION_ROOT应用的根路径,默认值为'/'
PREFERRED_URL_SCHEME当没有请求上下文时使用预案生成外部URL,默认值为'http'
配置项说明
MAX_CONTENT_LENGTH设置请求数据中读取的最大字节数,默认值为None。若该配置项并未配置,且也未指定 CONTENT_LENGTH,为了安全将不会读取任何数据
JSON_AS_ASCII是否采用ASCII编码序列化对象,默认值为 True。若该配置项的值设为False,则Flask会按Unicode编码输出
JSON_SORT_KEYS是否按照字母顺序对JSON对象的键进行排序,默认值为True,这对于缓存来说是非常有用的
JSONIFY_PRETTYPRINT_REGULAR控制jsonify 响应是否输出新行、空格和缩进等排版格式的内容,以便于阅读,默认值为False。该配置项在调试模式下总是启用
JSONIFY_MIMETYPEjsonify 响应的媒体类型,默认值为'application/json'
TEMPLATES_AUTO_RELOAD模板更新时自动重载
EXPLAIN_TEMPLATE_LOADING是否记录模板文件如何载入调试信息,默认值为False
MAX_COOKIE_SIZE设置Cookie的最大字节数,默认值为 4093。若该配置项的值小于Cookie的字节数,则发出警告;若该配置项的值为0,则关闭警告

1.4.2 配置信息的使用

在Flask中,若需要在程序中使用配置信息,以便对程序的一些行为进行定制,则可以采用多种方式将配置信息保存到Flask类对象的config属性中。config属性的值是一个flask.Config类的对象,flask.Config类是一个Python字典子类,它的工作方式类似于字典,既可以通过访问字典元素的方式使用配置信息,也可以通过flask.Config类提供的导入配置项的方法使用配置信息。

1.通过访问字典元素的方式使用配置文件

可以通过访问字典元素的方式获取Flask程序的配置项,并重新为该配置项赋值。例如,通过为Flask类的对象app设置配置项TESTING,以启用测试模式,代码如下所示。

app.config['TESTING'] = True

若希望一次修改多个配置项,则可以调用flask.Config从父类继承的update()方法实现。例如,通过为Flask类的对象app设置配置项TESTING和SECRET_KEY,从而为程序启用测试模式以及设置密钥,具体代码如下所示。

app.config.update(
TESTING=True, 
SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/'
)

2.通过导入文件的方式使用配置文件

可以将所有的配置项存入单独的文件中,之后将该文件导入到Flask程序中。flask.Config类中提供了一些从文件中导入配置项的方法,关于这些方法的介绍如下。

from_file():从指定的文件中导入配置项,并更新配置项的值。 from_pyfile():从py文件中导入配置项,并更新配置项的值。

# 通过from_file()方法从config.json文件中导入配置项
import json
app.config.from_file("config.json", load=json.load)
# 通过from_pyfile()方法从config.py文件中导入配置项
app.config.from_pyfile("config.py")

3.通过导入对象的方式使用配置信息

可以通过定义Python类属性的方式设置配置项,之后将包含配置项的Python类或Python类实例化的对象导入到Flask程序中。flask.Config类中提供了一些从Python类中导入配置项的方法from_object(),from_object()方法用于从给定对象中导入配置项,并更新配置项的值。 需要说明的是,from_object()方法只会加载Python类中以大写字母命名的属性。如果Python类中有一个@property属性,则该类在被传递给from_object()方法之前需要进行实例化。

定义一个包含两个配置项TESTING和SECRET_KEY的类Settings,之后调用from_object()方法从Settings类中加载配置项,并在程序中使用这些配置信息,具体代码如下所示。

class Settings:
    # 启用测试模式
    TESTING=True
    # 设置密钥
    SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/'
app.config.from_object(Settings)

1.5 Flask扩展包

Flask自身并没有提供一些重要的功能模块,比如发送电子邮件、用户认证、数据库操作等,开发人员在实际开发中若需要完成这些功能,既可以使用Flask为应用增加的扩展包,也可以按照自己的需求自行开发扩展包,这样做不仅能够避免程序代码变得臃肿且复杂,而且提高了程序的可扩展性。

常用的Flask扩展包如下表所示。

扩展包说明
Flask-SQLalchemy操作数据库
Flask-migrate管理迁移数据库
Flask-Mail邮件
Flask-WTF表单
Flask-Bable提供国际化和本地支持
Flask-script插入脚本
Flask-Login认证用户状态
Flask-OpenID认证
Flask-RESEful开发REST API 工具
Flask-Bootstrap集成前端Twitter Bootstrap框架
Flask-Moment本地化日期和时间
Flask-Admin简单和可扩展的管理接口框架

Flask程序若希望使用某个扩展包,则需要先在当前工作环境中使用pip命令安装该扩展包。以安装扩展包Flask-SQLalchemy为例,具体安装命令如下所示。

pip install flask-sqlalchemy

扩展包Flask-SQLalchemy安装成功之后,便可以被应用引入到程序中。扩展包有着一定编写约定,它内部一般会提供一个扩展类,只要在创建扩展类对象时传入程序实例即可完成初始化过程。

以扩展包Flask-SQLalchemy提供的扩展类SQLAlchemy为例,创建SQLAlchemy对象的示例代码如下所示。

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
# 实例化Flask类
app = Flask(__name__)
# 实例化SQLAlchemy类
db = SQLAlchemy(app)

需要注意的是,尽管扩展包可以快速实现某些功能,不过有些扩展包可能会存在一些潜在的Bug,不同的扩展包之间甚至可能会出现冲突。因此我们在选择扩展包时,应该尽量从实际需求的角度出发,对扩展包的质量和兼容性多做考量,以保证效率与灵活性之间的平衡。

1.6 本章小结

本章作为本书的开篇章节,主要讲解了Flask框架的相关知识,包括Flask简介、搭建Flask开发环境、开发第一个Flask Web程序、Flask程序配置和Flask扩展包。通过学习本章的内容,希望读者能够对Flask框架建立初步的认识,为后续深入学习Flask框架做好准备工作。

1.7 习题

一,填空题

1.Flask默认以来Werkzeug工具包和()模板引擎。

2.使用()命令可以推出通过virtualenv创建的虚拟环境。

3.Flask是一个用()语言编写的微框架。

4.Flask的开发服务器默认使用的端口号为()。

5.Flask通过设置()定制程序的一些行为。

二,判断题

1.Flask自带开发服务器。()

2.Flask的依赖包Werkzeug提供了一个简易的开发服务器。()

3.Flask中的视图是Python函数或类。()

4.Flask完全兼容WSGI1.0标准。()

5.Flask的开发服务器只能通过命令行方式启动。()

三,选择题

1.下列选项中,哪个参数用于指定运行Flask程序的主机端口号?()

A.host

B.port

C.dubug

D.portal

2.下列选项中,用于在创建Flask类对象时指定模板文件存放目录的参数是()。

A.static_url_path

B.static_folder

C.template_folder

D.static_host

3.下列选项中,表示启用/禁用调式模式的配置项是()。

A.ENV

B.DEBUG

C.TESTING

D.SECRET_KEY

4.下列选项中,用于操作数据库的扩展包是()。

A.Flask-SQLAlchemy

B.Flask-Migrate

C.Flask-Mail

D.Flask-WTF

5.下列选项中,关于Flask的描述错误的是()。

A.Flask是一个由Python语言编写的微框架

B.Flask默认使用Django模板引擎将HTML页面与应用程序联系起来

C.Flask完全基于Unicode编码格式

D.Flask自带开发服务器,可以让开发者在调试Web应用程序时无须安装其他的网络服务器


http://www.kler.cn/a/230241.html

相关文章:

  • 【机器学习chp8】统计学习理论
  • QT6学习第四天 感受QT的文件编译
  • idea_卸载与安装
  • transformer.js(三):底层架构及性能优化指南
  • 1-golang_org_x_crypto_bcrypt测试 --go开源库测试
  • Spring Boot 应用开发:构建高效、可扩展的 Java 微服务
  • 游戏开发-会飞的小鸟(已完结,附源码)
  • SQL Server数据库日志查看若已满需要清理的三种解决方案
  • es6模块化导入导出与commonjs模块化(nodejs导入导出)详解——导入import
  • 搜索引擎DuckDuckGo代理指南
  • 【DDD】学习笔记-服务行为模型
  • [ChatGPT们】ChatGPT 如何辅助编程初探
  • MC34063异常发热分析
  • MATLAB算法实战应用案例精讲-【图像处理】计算机视觉(基础篇)(四)
  • Linux 文件比较工具
  • 用HTML5 + JavaScript实现下雪效果
  • OpenCV-31 获得形态学卷积核
  • jvm一级缓存
  • jmeter二次开发函数-生成身份证号
  • sql求解连续两个以上的空座位
  • arcgis各种版本下载
  • 再识C语言 DAY15 【指针(中)理论结合实践】
  • 无人机激光雷达标定板
  • 限制Unity帧率的方式
  • 【QT】opcuaServer 的构建
  • ELAdmin 新增Module