Flask項目搭建及部署 —— Python

flask搭建及部署
pip 19.2.3

python 3.7.5

Flask 1.1.1

Flask-SQLAlchemy 2.4.1

Pika 1.1.0

Redis 3.3.11

flask-wtf 0.14.2

1、創建flask項目:
?

創建完成后整個項目結構樹:?

app.py: 項?管理?件,通過它管理項?。

static: 存放靜態文件

templates文件夾:用于放置html模板文件

由于flask屬于輕量級web框架, 更加自由、靈活,可擴展性強,第三方庫的選擇面廣,開發時可以結合自己最喜歡用的輪子,也能結合最流行最強大的Python庫 。所以這個框架的代碼架構需要自己設計。

2、創建項目主要邏輯代碼保存目錄

手動創建application目錄、filter目錄及其子目錄

application : 項目主要邏輯代碼保存目錄

_init_.py : 創建flask應用并加載配置,如mysql,redis,rabbitmq,

apps : 專門用于保存每一個項目的藍圖

app1 : app1藍圖目錄,在app1下的init_.py中文件中創建藍圖對象,view.py中新增對應的視圖文件,在 model.py中寫模型代碼

settings : 項目配置存儲目錄

dev.py : 項目開發階段配置文件

prop.py : 項目生成階段配置文件

static : 項目靜態文件夾(用于存放css一類的文件)

templates : 用于放置html模板文件

filter : 整個項目攔截器目錄

requestFilter.py: 針對整個app項目全局路由攔截規則定義

app.py : 項?管理?件,通過它啟動整個項目

2.1 配置mysql數據庫,加載配置文件并針對整個app項目定義全局db
2.1.1 settings.py

#全局通用配置類
class Config(object):"""項目配置核心類"""#調試模式DEBUG=False
?# 配置日志# LOG_LEVEL = "DEBUG"LOG_LEVEL = "INFO"
?
?# 配置redis# 項目上線以后,這個地址就會被替換成真實IP地址,mysql也是REDIS_HOST = 'your host'REDIS_PORT = your portREDIS_PASSWORD = 'your password'REDIS_POLL = 10
?#數據庫連接格式SQLALCHEMY_DATABASE_URI = "mysql+pymysql://user:password@localhost:3306/test?charset=utf8"# 動態追蹤修改設置,如未設置只會提示警告SQLALCHEMY_TRACK_MODIFICATIONS = False# 查詢時會顯示原始SQL語句SQLALCHEMY_ECHO = False# 數據庫連接池的大小SQLALCHEMY_POOL_SIZE=10#指定數據庫連接池的超時時間SQLALCHEMY_POOL_TIMEOUT=10# 控制在連接池達到最大值后可以創建的連接數。當這些額外的 連接回收到連接池后將會被斷開和拋棄。SQLALCHEMY_MAX_OVERFLOW=2
?
?#rabbitmq參數配置RABBITUSER="user"RABBITPASSWORD="password"RABBITHOST="your ip"RABBITPORT=your port

2.1.2 dev.py

from . import Config
?
class DevelopmentConfig(Config):'開發模式下的配置'# 查詢時會顯示原始SQL語句SQLALCHEMY_ECHO = True

2.1.3 prop.py

from . import Config
?
class ProductionConfig(Config):"""生產模式下的配置"""DEBUG = False

2.1.4 加載配置文件,定義全局的db( SQLALchemy類的實例 )供項目使用

# 主應用的根目錄
app = Flask(__name__)
?
config = {'dev': DevelopmentConfig,'prop': ProductionConfig,
}
?
# 設置配置類
Config = config['dev']
?
# 加載配置
app.config.from_object(Config)
?
# 創建數據庫連接對象
db = SQLAlchemy(app)

dev : 測試環境配置

prop: 生產環境配置

Flask應用app配置加載

通常三種方式

從配置對象中加載:app.config.from_object()

從配置文件中加載:app.config.from_pyfile()-ini文件

從環境變量中加載:app.config.from_envvar()

配置對象

從配置對象中加載,創建配置的類:

# 配置對象,里面定義需要給 APP 添加的一系列配置
class Config(object):DEBUG = True
?
?
app = Flask(__name__)
?
# 從配置對象中加載配置
app.config.from_object(Config)
app.run()

配置文件

從配置文件中加載,在目錄中定義一個配置文件config.ini

app = Flask(__name__)
?
# 從配置對象中加載配置
app.config.from_pyfile("config.ini")
app.run()

環境變量

app = Flask(__name__)
# 從環境變量中加載
app.config.from_envvar("FLASKCONFIG")
app.run()

2.2 定義model模型,負責和數據庫交互
app1.model

from application import db
?
class Wdtest(db.Model):__tablename__ = "wdtest" #設置表名id = db.Column(db.String(100), primary_key=True, comment="主鍵ID")name = db.Column(db.String(20), index=True, comment="姓名" )age = db.Column(db.Integer, default=True, comment="年齡")

模型 表示程序使用的持久化實體. 在Flask-SQLALchemy 中, 模型一般是一個 Python 類, 類中的屬性對應數據庫中的表.

db.Model :創建模型,

db.Column : 創建模型屬性.

tablename :指定表名

模型屬性類型 :

類型名Python類型說明
Integerint普通整數,一般是 32 位
SmallIntegerint取值范圍小的整數,一般是 16 位
Big Integerint 或 long不限制精度的整數
Floatfloat浮點數
Numericdecimal.Decimal定點數
Stringstr變長字符串
Textstr變長字符串,對較長或不限長度的字符串做了優化
Unicodeunicode變長 Unicode 字符串
Unicode Textunicode變長 Unicode 字符串,對較長或不限長度的字符串做了優化
Booleanbool布爾值
Datedatetime.date日期
Timedatetime.time時間
DateTimedatetime.datetime日期和時間
Intervaldatetime.timedelta時間間隔
Enumstr一組字符串
PickleType任何 Python 對象自動使用 Pickle 序列化
LargeBinarystr二進制文件


常用 SQLAlchemy 列選項

選項名說明
primary_key如果設為 True,這列就是表的主鍵
unique如果設為 True,這列不允許出現重復的值
index如果設為 True,為這列創建索引,提升查詢效率
nullable如果設為 True,這列允許使用空值;如果設為 False,這列不允許使用空值
default為這列定義默認值

2.3 聲明藍圖
app1._init.py

#給app取別名為 'index'
index_blu=Blueprint('index',__name__,template_folder='templates',static_folder='static')
?
from .views import *

template_folder:指定模板文件路徑,查找順序,先全局templates里面找,沒找到,再往子藍圖里面找.

這里是把view中所有的視圖都聲明在index這個藍圖里面,接下來我們需要做的是將這個聲明好的藍圖,注冊進我們的項目中。

2.4 將聲明好的藍圖注冊進app中
application.init_:

from application.settings.dev import DevelopmentConfig
from application.settings.prop import ProductionConfig
?
# 主應用的根目錄
app = Flask(__name__)
?
config = {'dev': DevelopmentConfig,'prop': ProductionConfig,
}
?
# 設置配置類
Config = config['dev']
?
# 加載配置
app.config.from_object(Config)
?
# 創建數據庫連接對象
db = SQLAlchemy(app)
?
# todo 注冊藍圖
from .apps.app1 import index_blu
app.register_blueprint(index_blu, url_prefix='/index')

針對:app = Flask(name)解釋

Flask類初始化參數

Flask類init方法部分代碼

def __init__(self,import_name,static_url_path=None,static_folder="static",static_host=None,host_matching=False,subdomain_matching=False,template_folder="templates",instance_path=None,instance_relative_config=False,root_path=None,):pass

import_name:Flask程序所在的包(模塊),傳 __name__

static_url_path:靜態文件訪問路徑,可以不傳,默認為:/ + static_folder

static_folder:靜態文件存儲的文件夾,可以不傳,默認為 static

template_folder:模板文件存儲的文件夾,可以不傳,默認為 templates

3 通過以上的步驟后,我們可以基本操作數據庫了:
以下所有示例代碼,皆在view.py中去實現

3.1 增:
先寫怎么增,然后增加,最后提交

student = Wdtest(id=ids , name=name, age=age)
try:application.db.session.add(student)application.db.session.commit()
except:# 事務回滾application.db.session.rollback()

3.2 刪:
先獲取數據庫中的這個數據,再刪除它

 user = Wdtest.query.first()application.db.session.delete(user)application.db.session.commit()

3.3 改:

user = Wdtest.query.first()
user.name = name
try:application.db.session.commit()
except:# 事務回滾application.db.session.rollback()

3.4 查:

# 查詢所有?戶數據
user_list=Wdtest.query.all()
?
# 查詢有多少個?戶
user_list_num=Wdtest.query.count()
# 查詢第1個?戶
user=Wdtest.query.first()
# 查詢id為3的?戶[3種?式]
user=Wdtest.query.get(3) ?# 根據主鍵查詢
user_list=Wdtest.query.filter_by(id=3).all() ?# 以關鍵字實參形式進行匹配字段
user_list=Wdtest.query.filter(Wdtest.id == 3).all() ?# 以恒等式形式匹配字段
?
# 查詢名字結尾字符為g的所有?戶
Wdtest.query.filter(Wdtest.name.endswith('g')).all()
?
# 查詢名字包含‘wa'的所有項目
user_list=Wdtest.query.filter(Wdtest.name.contains('wa')).all()
# 模糊查詢
user_list =Wdtest.query.filter(Wdtest.name.like('%a%')).all()
# 查詢名字wa開頭和age為20的所有?戶[2種?式]
user_list=Wdtest.query.filter(Wdtest.name.startswith('wa'),Wdtest.age == 20).all()
user_list=Wdtest.query.filter(and_(Wdtest.name.startswith('wa'), Wdtest.age == 20)).all()
?
# 非條件查詢查詢名字不等于wade的所有?戶[2種?式]
user_list=Wdtest.query.filter(not_(Wdtest.name == 'wade')).all()
user_list=Wdtest.query.filter(Wdtest.name != 'wade').all()
?
# in 條件查詢
user_list=Wdtest.query.filter(Wdtest.id.in_(['97124f50-0208-11ea-a66c-04ea56212bdf', '3'])).all()
?
# 所有?戶先按年齡從?到?, 再按id從?到?排序, 取前5個
user_list=Wdtest.query.order_by(Wdtest.age,Wdtest.id.desc()).limit(5).all()
?
# 分?查詢, 每?3個, 查詢第2?的數據
pn = Wdtest.query.paginate(2,3)
print(pn.pages)
print(pn.page)
print(pn.items)

4 路由傳參
有時我們需要將同一類 URL 映射到同一個視圖函數處理,比如:使用同一個視圖函數來顯示不同用戶的個人信息。

# 路由傳遞參數
@app.route('/user/<id>')
def user_info(id):return '%s' % id

路由傳遞的參數默認當做 string 處理

####指定請求方式

在 Flask 中,定義一個路由,默認的請求方式為:

GET

OPTIONS

HEAD

在裝飾器添加請求指定方式:

@app.route('/test', methods=['GET', 'POST'])
def test():return "ok"

5 動態正則匹配路由
flask實現正則匹配步驟:

導入轉換器基類:在 Flask 中,所有的路由的匹配規則都是使用轉換器對象進行記錄

自定義轉換器:自定義類繼承于轉換器基類

添加轉換器到默認的轉換器字典中

使用自定義轉換器實現自定義匹配規則

###實現:

導入轉換器基類

from werkzeug.routing import BaseConverter

自定義轉換器

# 自定義正則轉換器

class RegexConverter(BaseConverter):def __init__(self, url_map, *args):super(RegexConverter, self).__init__(url_map)# 將接受的第1個參數當作匹配規則進行保存self.regex = args[0]

添加轉換器到默認的轉換器字典中,并指定轉換器使用時名字為: re

app = Flask(__name__)
?
# 將自定義轉換器添加到轉換器字典中,并指定轉換器使用時名字為: regex
app.url_map.converters['regex'] = RegexConverter

使用轉換器去實現自定義匹配規則

當前此處定義的規則是:3位數字

@app.route('/index/<regex("[0-9]{3}"):id>')
def user_info(id):return "id 為 %s" % id

自定義轉換器其他函數實現

繼承于自定義轉換器之后,還可以實現 to_python 和 to_url 這兩個函數去對匹配參數做進一步處理:

to_python:

該函數參數中的 value 值代表匹配到的值,可輸出進行查看

匹配完成之后,對匹配到的參數作最后一步處理再返回,比如:轉成 int 類型的值再返回:

class RegexConverter(BaseConverter):def __init__(self, url_map, *args):super(RegexConverter, self).__init__(url_map)# 將接受的第1個參數當作匹配規則進行保存self.regex = args[0]
?def to_python(self, value):return int(value)

系統自帶轉換器

DEFAULT_CONVERTERS = {'default': ? ? ? ? ?UnicodeConverter,'string': ? ? ? ? ? UnicodeConverter,'any': ? ? ? ? ? ? ?AnyConverter,'path': ? ? ? ? ? ? PathConverter,'int': ? ? ? ? ? ? ?IntegerConverter,'float': ? ? ? ? ? ?FloatConverter,'uuid': ? ? ? ? ? ? UUIDConverter,
}

6 增加日志記錄、redis配置加載、mq配置加載
6.1 日志記錄
Settings._init:

# 配置日志
# LOG_LEVEL = "DEBUG"
LOG_LEVEL = "INFO"

日志記錄級別

FATAL/CRITICAL = 致命的,危險的
ERROR = 錯誤
WARNING = 警告
INFO = 信息
DEBUG = 調試
NOTSET = 沒有設置

application._init:

1、日志模塊基礎配置,如:日志存放地址、日志記錄格式、日志等級

#增加日志模塊
def setup_log(Config):#設置日志等級logging.basicConfig(level=Config.LOG_LEVEL)# 創建日志記錄器,指明日志保存的路徑、每個日志文件的最大大小、保存的日志文件個數上限file_log_handler=RotatingFileHandler('log/log',maxBytes=1024 * 1024 * 300, backupCount=10)# 創建日志記錄的格式 日志等級 輸入日志信息的文件名 行數 日志信息formatter = logging.Formatter('%(asctime)s: %(levelname)s %(filename)s:%(lineno)d %(message)s')# 為剛創建的日志記錄器設置日志記錄格式file_log_handler.setFormatter(formatter)# 為全局的日志工具對象(flaskapp使用的)添加日志記錄器logging.getLogger().addHandler(file_log_handler)

2、日志啟動

#日志啟動
setup_log(Config)

6.2 redis配置及加載
之前我們在config中已經把redis的配置已經寫進去了,所以這里可以直接創redis連接池供app全局使用

application._init:

#新增redis連接模塊
def connectRedis(Config):pool = redis.ConnectionPool(host=Config.REDIS_HOST, port=Config.REDIS_PORT, password=Config.REDIS_PASSWORD,max_connections=Config.REDIS_POLL)redis_store = redis.Redis(connection_pool=pool)return redis_store


使用示例:

@index_blu.route("/redis",methods=["POST","GET"])
def add_toRedis():logging.info("come to here")key = request.args.get("key")application.redis_store.set(key , "1233")value=application.redis_store.get( key )print(value)return "12333"


6.3 rabbitmq基礎配置及加載

# rabbitmq配置訪問
# 添加用戶名和密碼
credentials = pika.PlainCredentials(Config.RABBITUSER, Config.RABBITPASSWORD)
# 配置連接參數
parameters = pika.ConnectionParameters(host=Config.RABBITHOST, port=Config.RABBITPORT, credentials=credentials)
connection = pika.BlockingConnection(parameters)
channel = connection.channel()


使用示例:

@index_blu.route("/rabitmq",methods=["POST","GET"])
def add_rabitmq():logging.info("come to rabiitmq")application.channel.queue_declare(queue='queuetest2')
?return "33333"

7 全局攔截器配置
filerter.requestFilter

這里只是簡單針對請求路徑非index的進行攔截,如果還有其他攔截條件或者機制,可以繼續在filter這個包下添加

from flask import request
import application
?
# 攔截器,每次的請求進來都會做的操作
@application.app.before_request
def before_action():# 獲取當前請求的路由(路徑)a = request.pathprint(a)u = a.split('/')if len(a)>2:if u[1] == 'index':print('success')else:return "無權限請求"


攔截器加載進app:

#攔截器加載
requestFilter.before_action


8 請求對象request和返回對象Response
請求對象request,使用前先導入request模塊

from flask import request

獲取url請求參數:request.args

獲取form表單中的數據:request.form

獲取請求體原始數據:request.data

獲取文件數據:request.files

獲取cookie:request.cookies

獲取header信息:request.headers

獲取請求方法:request.method

獲取請求路徑:request.path

Response

視圖函數中可以返回的值

可以直接返回字符串,底層將這個字符串封裝成了Response對象

元組,響應格式(響應體,狀態碼,頭信息),不一定都要寫,底層也是封裝了一個Response對象

返回Response或其子類(jsonify子類返回標準json)

實現一個自定義Response對象步驟

繼承Response對象

實現方法 force_typeforce_type(cls,rv,environ=None)

指定app.response為你定義的類

如果返回的值不是可以返回的對象,就會調用force_type方法

實現

class JSONResponse(Response):
?@classmethoddef force_type(cls, response, environ=None):'''這個方法只有視圖函數返回非字符、非元祖、非Response對象才會調用:param response:是視圖函數的返回值:param environ::return:'''print(response)print(type(response))if isinstance(response,(list,dict)):
?#jsonify除了將字典轉換成json對象,還將對象包裝成了一個Response對象response = jsonify(response)
?return super(JSONResponse,cls).force_type(response,environ)?app.response_class = JSONResponse

9 異常捕獲及自定義異常
捕獲錯誤

errorhandler 裝飾器

注冊一個錯誤處理程序,當程序拋出指定錯誤狀態碼的時候,就會調用該裝飾器所裝飾的方法

參數:

code_or_exception – HTTP的錯誤狀態碼或指定異常

例如統一處理狀態碼為500,404的錯誤給用戶友好的提示:

@app.errorhandler(500)
def internal_server_error(e):return '服務器搬家了哈哈哈'
?
@app.errorhandler(404)
def internal_server_error(e):return '瞎請求什么路徑呢'


例如自定義錯誤413

@app.errorhandler(413)
def zero_division_error(e):return '除數不能為0'

異常捕獲

abort 方法

拋出一個給定狀態代碼的 HTTPException 或者 指定響應,例如想要用一個頁面未找到異常來終止請求,你可以調用 abort(404)。

參數:

code – HTTP的錯誤狀態碼

@index_blu.route("/exception",methods=["POST","GET"])
def exception():logging.info("come to exception")try:print(2)a=3/0except:abort(413)return "ooooo"

10 上下文?

上下文:即語境,語意,在程序中可以理解為在代碼執行到某個時刻,根據之前代碼鎖做的操作以及下文即將要執行的邏輯,可以決定在當前時刻下可以使用到的變量,或者可以做的事情。

Flask中有兩種上下文:請求上下文(request context)和應用上下文(application context)。

Flask中上下文對象:相當于一個容器,保存了Flask程序運行過程中的一些信息。

1.application指的是當你調用app = flask(name)創建的這個對象app。 2.request指的是每次http請求發生時,WSGI server(比如gunicorn)調用Flask.call()之后,在Flask對象內部創建的Request對象; 3.application表示用于相應WSGI請求的應用本身,request表示沒出http請求; 4.appliacation的生命周期大于request,一個application存活期間,可能發生多次http請求,所以,也就會有多個request;

請求上下文(request context):在Flask中,可以直接在視圖函數中使用request這個獨享進行獲取先關數據,而request就是請求上下文的對象,保存了當前本次請求的相關數據,請求上線文對象有:request、session

request:封裝了HTTP請求的內容,針對的是http請求。例如:user = request.args.get('user'),獲取的是get請求的參數。

session:用來記錄請求會話中的信息,針對的是用戶信息。例如:session['name'] = user.id 科可以記錄用戶信息。還可以通過session.get('name')獲取用戶信息。

應用上下文(application context):它不是一直存在的,它只是request context中的一個對app的代理,所謂的local proxy。它的作用主要是幫助request獲取當前的應用,它是伴request而生,隨request而滅的。

應用上下文對象有:current_app,g

current_app:應用程序上下文,用于存儲應用程序中的變量,可以通過current_app.name打印當前app的名稱,也可以在current_app中存儲一些變量,例如:

應用的啟動腳本是哪個文件,啟動時指定了哪些參數

加載了哪些配置文件,導入了哪些配置

連接了哪個數據庫

有哪些可以調用的工具類、常量

當前flask應用在哪個機器上,哪個IP上運行,內存多大

current_app.name
current_app.test_value='value'

g變量:g 作為 flask 程序全局的一個臨時變量,充當者中間媒介的作用,我們可以通過它傳遞一些數據,g 保存的是當前請求的全局變量,不同的請求會有不同的全局變量,通過不同的thread id區別

g.name='abc'
注意:不同的請求,會有不同的全局變量

兩者的區別:

請求上下文:保存了客戶端和服務器交互的數據

應用上下文:flask 應用程序運行過程中,保存的一些配置信息,比如程序名、數據庫連接、應用信息等

11 部署
gunicorn作為服務器,安裝gunicorn

pip3 install gunicorn

啟動

gunicorn -w 3 -b 127.0.0.1:8000 app:app

-w 處理進程數

-b 運?主機ip端?

dpj.wsgi 項?的wsgi

gunicorn常?配置

-c CONFIG : CONFIG,配置?件的路徑,通過配置?件啟動;?產環境使?;?
?
-b ADDRESS : ADDRESS,ip加端?,綁定運?的主機;?
?
-w INT, --workers INT:?于處理?作進程的數量,為正整數,默認為1;?
?
-k STRTING, --worker-class STRTING:要使?的?作模式,默認為sync異步,可以下載?
?
eventlet和gevent并指定?
?
--threads INT:處理請求的?作線程數,使?指定數量的線程運?每個worker。為正整數,默認為1。?
?
--worker-connections INT:最?客戶端并發數量,默認情況下這個值為1000。?
?
--backlog int:未決連接的最?數量,即等待服務的客戶的數量。默認2048個,?般不修改;?
?
-p FILE, --pid FILE:設置pid?件的?件名,如果不設置將不會創建pid?件?
?
--access-logfile FILE : 要寫?的訪問?志?錄--access-logformat STRING:要寫?的訪問?志格式?
?
--error-logfile FILE, --log-file FILE : 要寫?錯誤?志的?件?錄。?
?
--log-level LEVEL : 錯誤?志輸出等級。?
?
--limit-request-line INT : HTTP請求頭的?數的最???,此參數?于限制HTTP請求?的允?
?
許??,默認情況下,這個值為4094。值是0~8190的數字。?
?
--limit-request-fields INT : 限制HTTP請求中請求頭字段的數量。此字段?于限制請求頭字?
?
段的數量以防?DDOS攻擊,默認情況下,這個值為100,這個值不能超過32768?
?
--limit-request-field-size INT : 限制HTTP請求中請求頭的??,默認情況下這個值為8190?
?
字節。值是?個整數或者0,當該值為0時,表示將對請求頭??不做限制?
?
-t INT, --timeout INT:超過這么多秒后?作將被殺掉,并重新啟動。?般設定為30秒;?
?
--daemon: 是否以守護進程啟動,默認false;?
?
--chdir: 在加載應?程序之前切換?錄;?
?
--graceful-timeout INT:默認情況下,這個值為30,在超時(從接收到重啟信號開始)之后仍然活著?
?
的?作將被強?殺死;?般使?默認;?
?
--keep-alive INT:在keep-alive連接上等待請求的秒數,默認情況下值為2。?般設定在1~5秒之?
?
間。?
?
--reload:默認為False。此設置?于開發,每當應?程序發?更改時,都會導致?作重新啟動。?
?
--spew:打印服務器執?過的每?條語句,默認False。此選擇為原?性的,即要么全部打印,要么全部?
?
不打印;?
?
--check-config :顯示現在的配置,默認值為False,即顯示。?
?
-e ENV, --env ENV: 設置環境變量;

本次分享到此結束,覺得有所幫助的朋友點點關注點點贊!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/43276.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/43276.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/43276.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

自定義控件視圖篇(一)測量與布局

在自定義控件的開發過程中&#xff0c;"視圖篇"的測量與布局是非常關鍵的步驟&#xff0c;這直接決定了控件的尺寸、位置以及子視圖的排列方式。下面我將詳細介紹測量和布局的過程&#xff0c;以及如何在自定義控件中正確實現這些步驟。 視圖的測量 (onMeasure) 在…

2021版本的idea熱部署的詳細步驟

背景&#xff1a;我是自己用的是2021版本的idea,然后發現跟2023版本的熱部署不太一樣&#xff0c;所以&#xff0c;今天自己出一期這樣的文章吧&#xff01;&#xff01;&#xff01;其他人配置的時候根據自己的情況&#xff0c;來閱讀吧&#xff01; 第一步&#xff1a;方式一…

MyBatis是如何分頁的及原理

MyBatis 是一種持久層框架&#xff0c;支持通過配置文件和注解將 SQL 映射為 Java 對象。在實際開發中&#xff0c;查詢數據時經常需要進行分頁處理。 MyBatis 也提供了支持分頁的方案&#xff0c;其主要思路是使用 Limit 偏移量和限制個數&#xff0c;來獲取指定數量的數據。下…

音視頻入門基礎:H.264專題(10)——FFmpeg源碼中,存放SPS屬性的結構體和解碼SPS的函數分析

一、引言 FFmpeg源碼對AnnexB包裝的H.264碼流解碼過程中&#xff0c;通過ff_h2645_extract_rbsp函數拿到該H.264碼流中的某個NALU的NALU Header RBSP后&#xff08;具體可以參考&#xff1a;《FFmpeg源碼&#xff1a;ff_h2645_extract_rbsp函數分析》&#xff09;&#xff0c…

【沐風老師】3DMAX建筑體塊生成插件BuildingBlocks使用方法詳解

BuildingBlocks建筑體塊生成插件使用方法詳解 聽說你還在手動建配景樓&#xff1f;有了BuildingBlocks這個插件&#xff0c;一分鐘搞定喔&#xff01; 3DMAX建筑體塊生成插件BuildingBlocks&#xff0c;用于快速自定義街道及生成配景樓區塊。 【適用版本】 3dMax2019及更高版…

空間分析在3D應用中的革命:提升投資回報與業務價值

在3D應用的浪潮中&#xff0c;空間分析技術正成為提升用戶體驗、優化業務決策和解決復雜問題的關鍵工具。本文將深入探討空間分析如何通過提供深度用戶行為洞察和數據可視化&#xff0c;增強3D應用的實際效益和市場競爭力。 一、空間分析的概念與背景 Tony Bevilacqua&#x…

分布式I/O從站的認知

為什么需要分布式I/O從站&#xff1f; 當PLC與控制機構距離過遠時&#xff0c;遠距離會帶來信號干擾&#xff0c;分布式I/O從站只需要一個網絡線纜連接。 ET200分布式I/O從站家族 體積緊湊、功能強大。 ET200SP ET200M ET200S ET200iSP ET200 AL ET200pro ET200 eco PN 通訊協議…

DSSM雙塔特征交互

傳統的DSSM雙塔無法在早期進行user和item側的特征交互&#xff0c;這在一定程度上降低了模型性能。我們想要對雙塔模型進行細粒度的特征交互&#xff0c;同時又不失雙塔模型離線建向量索引的解耦性。下面介紹兩篇這方面的工作。 美團-Dual Augmented Two-tower 在user和item的特…

1. CSS Grid 網格布局教程

CSS Grid 網格布局教程 一、概述 網格布局&#xff08;Grid&#xff09;是最強大的 CSS 布局方案。 它將網頁劃分成一個個網格&#xff0c;可以任意組合不同的網格&#xff0c;做出各種各樣的布局。以前&#xff0c;只能通過復雜的 CSS 框架達到的效果&#xff0c;現在瀏覽器…

linux工具應用_VERDI

verdi 1. 基礎知識1.1 verdi介紹1.2 fsdb文件2. fsdb dump2.1 1st step-設置環境變量LD_LIBRARY_PATH2.2 2nd step-xrun仿真命令2.3 3rd step-仿真過程中調用fsdb函數dump波形2.3.1 在testbench、top.sv中調用fsdb函數2.3.2 在tcl腳本中用xrun的dump指令(同樣要調用fsdb函數)2.…

Scrapy crawl spider 停止工作

Scrapy是一個用于爬取網站數據的流行框架&#xff0c;有時爬蟲可能會停止工作&#xff0c;這通常是由多種原因引起的。以下是一些常見問題及其解決方法&#xff1a; 1、問題背景 用戶在使用 Scrapy 0.16.2 版本進行網絡爬取時遇到問題&#xff0c;具體表現為爬蟲在運行一段時間…

Android 開發中 C++ 和Java 日志調試

在 C 中添加堆棧日志 先在 Android.bp 中 添加 ‘libutilscallstack’ shared_libs:["liblog"," libutilscallstack"]在想要打印堆棧的代碼中添加 #include <utils/CallStack.h> using android::CallStack;// 在函數中添加 int VisualizerLib_Crea…

生物素結合金納米粒子(Bt@Au-NPs ) biotin-conjugated Au-NPs

一、定義與特點 定義&#xff1a;生物素結合金納米粒子&#xff0c;簡稱BtAu-NPs或biotin-conjugated Au-NPs&#xff0c;是指通過特定的化學反應或物理方法將生物素修飾到金納米粒子表面&#xff0c;形成穩定的納米復合材料。 特點&#xff1a; 高穩定性&#xff1a;生物素的修…

重構功能帶來的配套改造查找思路

最近在重構項目中的一個基礎配置功能&#xff0c;這個功能因為后續的業務變化和最初的缺陷設計導致非常難維護和擴展&#xff0c;使用起來也比較費勁&#xff0c;所以決定花一段時間來對它進行重構&#xff0c;去除一些用不到的設計&#xff0c;簡化了使用方式和配置方式&#…

RabbitMQ 遷移

文章目錄 1. 導出配置2. 導入配置3. 導出和導入定義&#xff08;如果不需要消息&#xff09;導出定義導入定義 注意事項參考文檔 要將 RabbitMQ 的配置&#xff08;包括vhost、exchange等&#xff09;從一個實例遷移到另一個實例&#xff0c;您可以遵循以下步驟&#xff1a; 1.…

【VUE基礎】VUE3第七節—Vue Router路由基礎

Vue Router 是 Vue 官方的客戶端路由解決方案。 客戶端路由的作用是在單頁應用 (SPA) 中將瀏覽器的 URL 和用戶看到的內容綁定起來。當用戶在應用中瀏覽不同頁面時&#xff0c;URL 會隨之更新&#xff0c;但頁面不需要從服務器重新加載。 Vue Router 基于 Vue 的組件系統構建&…

LabVIEW在半導體自動化測試中的應用

半導體制造的復雜性和精密度要求極高&#xff0c;每一個生產步驟都需要嚴格的控制和監測。自動化測試設備在半導體制造中起到了關鍵作用&#xff0c;通過精密測量和數據分析&#xff0c;確保產品質量和生產效率。本文介紹如何使用LabVIEW結合研華硬件&#xff0c;開發一個用于半…

C語言編程3:運算符,運算符的基本用法

C語言3&#x1f525;&#xff1a;運算符&#xff0c;運算符的基本用法 一、運算符&#x1f33f; &#x1f387;1.1 定義 運算符是指進行運算的動作&#xff0c;比如加法運算符"“&#xff0c;減法運算符”-" 算子是指參與運算的值&#xff0c;這個值可能是常數&a…

自動化測試高級控件交互方法:TouchAction、觸屏操作、點按,雙擊,滑動,手勢解鎖!

在自動化測試領域中&#xff0c;TouchAction 是一種非常強大的工具&#xff0c;它允許我們模擬用戶在設備屏幕上的各種觸摸事件。這種模擬不僅限于簡單的點擊操作&#xff0c;還包括滑動、長按、多點觸控等復雜的手勢。 點按與雙擊 點按和雙擊是觸屏設備上最基本的操作之一。…

使用 Qt 和 ECharts 進行數據可視化

文章目錄 示例圖表預覽折線圖散點圖柱狀圖使用 Qt 和 ECharts 進行數據可視化一、準備工作1. 安裝 Qt2. 準備 ECharts二、在 Qt 中使用 ECharts1. 創建 Qt 項目2. 配置項目文件3. 在 UI 中添加 WebEngineView4. 加載 ECharts三、創建折線圖、散點圖和柱狀圖1. 折線圖2. 散點圖3…