[Python][flask][flask-wtf]關於flask-wtf中API使用實例教程

来源:http://www.cnblogs.com/alima/archive/2016/08/26/5796298.html
-Advertisement-
Play Games

本文為flask-wtf中的幾乎所有常用API實現,併在實例中運用flask-wtf包,同時包含了作者在學習開發階段的一些心得體會。 ...


簡介:簡單的集成flask,WTForms,包括跨站請求偽造(CSRF),文件上傳和驗證碼。

一.安裝(Install)

此文仍然是Windows操作系統下的教程,但是和linux操作系統下的運行環境相差甚微。

使用Python版本3.5.2.

上一篇文章提到Virtualenv環境運行Python,這次仍然建立Python虛擬運行環境以便實現不同數據包的隔離。

  • 創建wtfdemo虛擬運行環境

用控制台(管理員運行模式)進入(cd)到想要創建工程的路徑下,創建wtfdemo文件夾。

mkdir wtfdemo

進入(cd)wtfdemo文件夾,創建Python虛擬運行環境。

virtualenv flaskr

出現如下字樣,說明虛擬環境創建成功

PS:本次提供第二種創建Python虛擬運行環境的使用方法

virtualenv -p source_file\python.exe target_file

為什麼提出第二種創建方法,你會發現,當你的Python Web程式開發多了以後,PC上難免安裝了很多版本的Python運行環境。

舉例:當PC上同時安裝了Python2.7和Python3.5,運行virtualenv flaskr後,建立的Python虛擬運行環境是Python2.7版本的,但是我們的開發環境是Python3.5。

在控制臺中輸入一下指令,你就會發現問題。

virtualenv -h

出現下麵圖片顯示,預設的virtualenv安裝路徑是Python2.7,也就是預設的安裝的虛擬環境是Python2.7版本。

所以,在這種情況下,請指定你需要的Python版本,並建立虛擬運行環境。

  • 安裝flask-wtf庫文件

進入Python虛擬運行環境(在上一篇博文中寫過),執行以下指令。

pip install flask
pip install flask-wtf
pip install flask-login
pip install flask-sqlalchemy

出現如下圖所示,說明安裝成功。

flask安裝成功。

flask-wtf安裝成功。

flask-login安裝成功。(本次使用flask-wtf庫時需要輔助以該運行庫)

flask-sqlalchemy安裝成功。

至此,環境配置階段結束。

 

二.Flask-WTF

flask-wtf實現了簡單集成WTForms,包括CSRF,文件上傳以及Google內嵌的驗證碼。

特性:

①集成了WTForms。

②包含了帶有CSRF的安全表單

③全局的CSRF保護

④驗證碼Recaptcha的支持

⑤支持Flask-Upload的文件上傳

⑥多語言集成

但,成也集成敗也集成,flask-wtf不包含WTForms中許多重要的API,在進行複雜作業時顯得力不從心。

 

實際上,flask-wtf下整合的WTForm單元已經能基本滿足一些小型網站的建設使用了。

三.在實例中應用

  • 文件結構

上一篇博文中,文件結構很是混亂,在實際維護中很不方便,會留下很多隱患,比如後期維護人員無法很快的切人項目中進行解讀代碼。

此處將各個模塊進行分離,抽離出各個不同的模塊。這樣的有點是單個文件只操作自己的功能,代碼可讀性強,邏輯清晰。缺點就是大型項目時文件會有很多碎小的文件,需要經常使用from import語句從不同的文件中引用出不同的功能。

但是相對於優點,缺點所帶來的風險是很小的。實際工作中,這樣的分文件管理項目是極力推薦的,邏輯清晰,可維護性高是每一個優秀的項目應該具有的最基本屬性。

本文采用以下文件結構。

wtfdemo→flaskr
    →templates →login.html
            →index.html
→uploads →wtf.py →model.py →views.py →run.py
→config.py →form.py

本次應用實現一個簡單的用戶登錄功能模塊,文中涵蓋的flask-login包將在下一篇博文中詳細解釋,如果想馬上瞭解,請查看flask-login官方文檔

  • 詳細參數解析

config.py代碼如下所示。

 1 import os
 2 
 3 basedir = os.path.abspath(os.path.dirname(__file__))
 4 
 5 SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'test.db')
 6 SQLALCHEMY_TRACK_MODIFICATIONS = False
 7 
 8 CSRF_ENABLED = True
 9 SECRET_KEY = 'you will never guess'
10 
11 RECAPTCHA_PUBLIC_KEY = '6LeYIbsSAAAAACRPIllxA7wvXjIE411PfdB2gt2J'
12 RECAPTCHA_PRIVATE_KEY = '6LeYIbsSAAAAAJezaIq3Ft_hSTo0YtyeFG-JgRtu'

一句一句解釋

①OS模塊是Python標準庫中的一個用於訪問操作系統功能的模塊,OS模塊提供了一種可移植的方法使用操作系統的功能。

這裡利用os.path.abspath()函數,取出該文件下的絕對路徑。

②將取出的絕對路徑下存放到basedir中,以便被其他文件引用。

③SQLALCHEMY_DATABASE_URI用於連接資料庫,SQLALCHEMY_TRACK_MODIFICATIONS追蹤對象的修改並且發送信號,這裡在上一篇文章講解過。

④CSRF_ENABLED為是否開啟flask-wtf下的CSRF(跨站請求偽造)保護,True為開啟保護狀態。

⑤SECRET_KEY設置Flask的應用密匙,同時CSRF開啟保護時,同時需要一個密匙,如果不在文件中明確指出,通常與你的 Flask 應用密鑰一致。如果想要使用不同的密匙,請在文件中配置CSRF單獨的密匙。

WTF_CSRF_ENABLED = False

⑥RECAPTCHA_PUBLIC_KEY與RECAPTCHA_PRIVATE_KEY分別為,必需公鑰與必需私鑰。

 

wtf.py代碼如下。

 1 from flask import Flask
 2 from flask_sqlalchemy import SQLAlchemy
 3 from config import SQLALCHEMY_DATABASE_URI, SQLALCHEMY_TRACK_MODIFICATIONS
 4 from flask_login import LoginManager, AnonymousUserMixin
 5 
 6 app = Flask(__name__)
 7 app.config.from_object('config')
 8 db = SQLAlchemy(app)
 9 lm = LoginManager()
10 lm.init_app(app)
11 lm.login_view = 'login'
12 lm.login_message = 'Please log in!'
13 lm.login_message_category = 'info'
14 lm.anonymous_user = AnonymousUserMixin
15 lm.session_protection = 'strong'
16 lm.refresh_view = 'login'
17 lm.needs_refresh_message = 'Please enter your info'
18 lm.needs_refresh_message_category = "refresh_info"
19 
20 from model import User
21 import views

①引用包中的函數說明。

Flask函數為flask架構的主函數,一切flask架構的Web開發都是由此函數引申出來的。

SQLAlchemy函數為flask-sqlalchemy包的主函數,由此函數綁定相應的flask架構應用,就可以實現連接資料庫的操作。

SQLALCHEMY_DATABASE_URI與SQLALCHEMY_TRACK_MODIFICATIONS為config.py中配置相應的參數,在此文件中被引用以便使用。

LoginManager函數是flask-login包的主函數,由此將flask架構和flask-login連接成一個整體。

②app.config.from_object函數將config文件下能配置到app的條目,綁定到app上。結果等同於直接綁定,等同結果如下。

app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = SQLALCHEMY_TRACK_MODIFICATIONS

③其他關於flask-login包下的函數,在下篇博文中將詳細的講解,本篇文章重點介紹flask-wtf包中的API使用。

 

form.py代碼構成如下。

 1 from flask_wtf import Form
 2 from wtforms import TextField, BooleanField
 3 from wtforms.validators import DataRequired
 4 from flask_wtf.recaptcha import RecaptchaField
 5 
 6 from werkzeug import secure_filename
 7 from flask_wtf.file import FileField
 8 
 9 class LoginForm(Form):
10     username = TextField('username', validators=[DataRequired()])
11     password = TextField('password', validators=[DataRequired()])
12     remember_me = BooleanField('remember_me', default=False)
13     recaptcha = RecaptchaField()
14         
15 class UploadForm(Form):
16     file = FileField()

①Form為flask-wtf的基礎form類型,一切的網頁表單都是繼承Form父類的屬性,並添加自己獨有的處理

②TextField, BooleanField是WTForm構建的文字域和覆選框域,對應HTML的<input type='text'/>和<input type='checkbox'/>標簽。

③DataRequired驗證TextField是否為空,為空返回一個錯誤信息(error message)

④在將文件保存在文件系統之前,要堅持使用secure_filename函數來確保文件名是安全的。

⑤flask-wtf整合了flask-upload中的部分函數,所以FileField不是從WTForm中引用出來的。FileField顧名思義,對應HTML標簽<input type='file'/>標簽。

⑥分析LoginForm類

1 class LoginForm(Form):
2     username = TextField('username', validators=[DataRequired()])
3     password = TextField('password', validators=[DataRequired()])
4     remember_me = BooleanField('remember_me', default=False)
5     recaptcha = RecaptchaField()

類成員構成: 變數名 = xxxField(),其中xxxField中可以選擇傳入<input/>標簽的name,validators屬性判斷如果TextBox中為None則返回錯誤消息

變數名可以在相對應的HTML文件中使用對應的 form.變數名 使用。

解析:此處添加兩個TextBox一個輸入用戶名,一個輸入密碼。一個CheckBox覆選框,實現記住用戶功能。最後一個為登陸時防止惡意登陸的驗證碼。

 

model.py代碼構成。

 1 from wtf import db
 2 from flask_login import UserMixin
 3 
 4 class User(db.Model, UserMixin):
 5     id = db.Column(db.Integer, primary_key=True)
 6     username = db.Column(db.String(80), unique=True)
 7     password = db.Column(db.String(80), unique=True)
 8     
 9     def __init__(self, username, password):
10         self.username = username
11         self.password = password
12         
13     def __repr__(self):
14         return '<User %r>' % self.username

①將wtf中模塊中的db參數引用到model.py中,以創建ORM資料庫映射關係

②其中UserMixin為flask-login中的用戶類,其中包含了一些可以在實現用戶登錄時驗證時需要的屬性。

③User類中定義id,用戶名及密碼屬性。__init__為User類的構造函數,__repr__方便在調試中輸出數據時使用。

 

views.py代碼構成。(下邊的代碼包含了Flask框架下的一些簡單應用,請在有一定Flask架構基礎的情況下,可以快速的切入下段代碼。其中flask-login在本文只一筆帶過,將在下篇博文中詳細解析flask-login包的API使用實例教程)

 1 from flask import render_template, flash, redirect, session, url_for, request, g
 2 from flask_login import login_user, logout_user, current_user, login_required, AnonymousUserMixin, fresh_login_required, login_fresh
 3 from wtf import app, db, lm, User
 4 from form import LoginForm, UploadForm
 5 
 6 @app.before_request
 7 def before_request():
 8     g.user = current_user
 9  
10 @lm.user_loader
11 def load_user(id):
12     user = User.query.filter_by(id=id).first()
13     return user
14 
15 @app.route('/login', methods=['GET', 'POST'])
16 def login():
17     if g.user is not None and g.user.is_authenticated:
18         login_fresh()
19         session['_fresh'] = False
20         return redirect(url_for('index'))
21     if g.user.is_active == True:
22         flash('active is True')
23     else:
24         flash('active is False')
25     form = LoginForm()
26     if form.validate_on_submit():
27         user = User.query.filter_by(username=form.username.data, password=form.password.data).first()
28         if(user is not None):
29             login_user(user,remember=form.remember_me.data)
30             return redirect(request.args.get("next") or url_for('index'))
31     return render_template('login.html', form=form)
32     
33 @app.route('/', methods = ['GET', 'POST'])
34 @app.route('/index', methods=['GET', 'POST'])
35 @login_required
36 def index():
37     form = UploadForm()
38 
39     if form.validate_on_submit():
40         filename = secure_filename(form.file.data.filename)
41         form.file.data.save('uploads/' + filename)
42         return redirect(url_for('upload'))
43 
44     return render_template('upload.html', form=form)
45     
46 @app.route('/logout')
47 @login_required
48 def logout():
49     logout_user()
50     return redirect(url_for('login'))

①from form import LoginForm, UploadForm, InfoForm

將form.py中定義的表單類引入到該文件中。

②before_request函數,定義為flask-login綁定用戶時使用,在發起請求之前首先調用此函數。

③load_user函數,定義為根據ID取出用戶實體。

④login函數,詳細分析:

@app.route('/login', methods=['GET', 'POST'])         #接受前段POST和GET的表單信息,綁定到發佈/login頁面上
def login():
    if g.user is not None and g.user.is_authenticated:#判斷用戶是否登錄過系統,或者是否使用過記住用戶這個功能        
return redirect(url_for('index')) #如果滿足條件,則跳轉到/index界面
form = LoginForm() #實例化LoginForm() if form.validate_on_submit(): #validate_on_submit函數判斷form表單中是否有提交動作,如果有,則獲取該動作 user = User.query.filter_by(username=form.username.data, password=form.password.data).first()#獲取是否存在用戶(這種未加密登錄方法不推薦在實際項目中使用) if(user is not None): #判斷取出的資料庫用戶實體是否為空 login_user(user,remember=form.remember_me.data)#將用戶實體,記住用戶選項,綁定到flask-login中 return redirect(request.args.get("next") or url_for('index'))#重定向到next頁面或是index頁面 return render_template('login.html', form=form) #使用模板函數,將form綁定到login.html頁面上

⑤index函數分析

@app.route('/', methods = ['GET', 'POST'])            #接受前段POST和GET的表單信息,綁定到發佈跟目錄上
@app.route('/index', methods=['GET', 'POST'])        #接受前段POST和GET的表單信息,綁定到發佈/index頁面上
@login_required                                       #驗證用戶是否登錄
def index():                                         
form = UploadForm() #實例化UploadForm() if form.validate_on_submit():                  #判斷表單中是否存在提交動作 filename = secure_filename(form.file.data.filename)#secure_filename函數確保文件名是安全,並賦值到filename中 form.file.data.save('uploads/' + filename) #將文件保存到工程目錄的位置 return redirect(url_for('index')) #上傳完文件後將頁面重定向到index.html return render_template('index.html', form=form) #使用模板函數

 ⑥logout函數分析

@app.route('/logout') #將函數綁定到/logout鏈接上
@login_required       #驗證用戶是否登錄
def logout():
    logout_user()     #清空session中的緩存
    return redirect(url_for('login'))#重定向到login.html頁面上

 

login.html代碼構成

<html>
<head>
Login-Demo
</head>
<body>
<form method="POST" action="">
    {% with messages = get_flashed_messages() %}
    {% if messages %}
    <ul>
    {% for message in messages %}
        <li>{{ message }} </li>
    {% endfor %}
    </ul>
    <hr/>
    {% endif %}
    {% endwith %}
    {{form.csrf_token}}
    {{form.username(size=80)}}
    {% for error in form.username.errors %}
        <span style="color: red;">[{{error}}]</span>
    {% endfor %}<br>
    {{ form.password(size=80) }}
    {% for error in form.password.errors %}
        <span style="color: red;">[{{error}}]</span>
    {% endfor %}<br>
    <p>{{ form.remember_me }} Remember Me</p>
    <p></p>
    <p><input type="submit" value="Sign In"></p>
    <a href="{{ url_for('logout') }}">Logout</a>
</form>
</body>
</html>

 

一下講解表單中各個語句的含義。

{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
    <li>{{ message }} </li>
{% endfor %}
</ul>
<hr/>
{% endif %}
{% endwith %}

①get_flashed_messages函數獲取flask後端發動的flash消息。

②判斷如果是消息類型的話迴圈輸出

{{form.csrf_token}}
{{form.username(size=80)}}
{% for error in form.username.errors %}
    <span style="color: red;">[{{error}}]</span>
{% endfor %}<br>
{{ form.password(size=80) }}
{% for error in form.password.errors %}
    <span style="color: red;">[{{error}}]</span>
{% endfor %}<br>
<p>{{ form.remember_me }} Remember Me</p>
<p><input type="submit" value="Sign In"></p>
<a href="{{ url_for('logout') }}">Logout</a>

①form.csrf_token設置開啟CSRF保護

②form.username(size=80),創建一個長度為80px的TextBox,對應前面提到的LoginForm創建的成員變數username

③for error in form.username.errors,此處抓取validators=[DataRequired()]返回的錯誤信息(error message)

④form.password(size=80),創建一個長度為80px的TextBox,對應前面提到的LoginForm創建的成員變數password

⑤form.remember_me,創建一個CheckBox,對應前面提到的LoginForm創建的成員變數remember_me

⑥<input type="submit" value="Sign In">添加一個按鈕,點擊後觸發form.validate_on_submit()函數

⑦<a href="{{ url_for('logout') }}">前段調用後端函數的一種方法,調用後端函數view.py中的logout函數

 

index.html代碼構成

<html>
<head>
{% if filedata %}
<h3>{{ filedata.filename }}</h3>
{% endif %}
</head>
<body>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
    <li>{{ message }} </li>
{% endfor %}
</ul>
<hr/>
{% endif %}
{% endwith %}
<a href="{{ url_for('logout') }}">Logout</a>
<form method="post" enctype="multipart/form-data">
    {{ form.hidden_tag() }}
    {{ form.file }}
    <input type="submit">
</form>
</body>
</html>

將UploadForm類中的file呈現在頁面上。

 

最後,我們為了運行程式,添加run.py文件。

from wtf import app
app.run(debug=True)

 運行如下代碼,執行此次實常式序。

 

四.運行實常式序

打開瀏覽器輸入 http://127.0.0.1:5000/login,進入登錄界面。

關於資料庫的操作已經在上一篇博文里寫的很清楚了,在資料庫中已經添加了用戶(username=john,password=1)。

①當直接點擊Sign In按鈕之後,會出現如下圖顯示的效果。

出現上面[This field is required.]是from.py文件中validators=[DataRequired()]的功勞,這段代碼幫你驗證了提交表單中TextBox是否為空。

②當輸入用戶名和密碼之後,你會發現,點擊Sign In按鈕之後,並沒有跳轉到預期的index.html界面。

Q:為什麼沒有跳轉。

A:這和我們之前的一個疏忽造成的,之前的代碼我已經留下了一個位置修改這個問題。

下麵我們來分析,問題是點擊按鈕無法執行代碼中的跳轉,說明後端代碼綁定控制項的時候出現問題。

那是什麼問題呢,flask-wtf已經為你提供了一個可以查出問題的方法,使用form.errors檢索出在提交表單之後發生的問題。

在views.py文件的login函數中添加如下代碼(在實例化LoginForm之後添加)

flash(form.errors)

重新運行程式,輸入用戶名和密碼,點擊Sign In按鈕。

看到{'recaptcha': ['The response parameter is missing.']}你發現問題了麽,對的,就是因為筆者的一個不小心,沒有在HTML文件實例化recaptcha,由於驗證碼和按鈕有一個相互作用的關係,試想當你登錄一個系統,不輸入驗證碼直接點擊登錄,會發生一樣的問題。

解決辦法:

在login.html添加如下代碼。

<p>{{ form.remember_me }} Remember Me</p>
<p>{{ form.recaptcha }}</p>#添加的代碼
<p><input type="submit" value="Sign In"/><p>

再次重新啟動程式,這回我們就會看到我們需要的樣子。

 輸入用戶名和密碼,按驗證碼要求點擊相應的圖片,點擊Sign In按鈕,登錄成功!

點擊Choose File,讓我們上傳一個文件試試看,點擊upload按鈕之後,你會在項目根目錄下的Uploads文件夾找到你上傳的文件。

PS:本地運行並上傳文件,不會出現問題。如果你是發佈在網路中的時候,請註意一下幾個問題。

①圖片同名問題。

②上傳文件夾許可權問題。(筆者之前在項目中處理的辦法是將讀寫許可權賦予給everyone用戶,但是這樣會大大降低伺服器的安全性)

 

關於flask-wtf中文件上傳的一些解析,將在以後講解flask-upload的時候一起講解。

關於本文中的flask-login包,我們將在下一篇文章中解析。

 

以上就是基本的flask-wtf使用實例說明,歡迎探討轉載及引用參考,你們的回應是我的動力。

如果文中存在錯誤或是某個地方說的不夠精確,勞煩批評指出。

以上,辛苦了。

 

參考:

[1] github源碼:https://github.com/lepture/flask-wtf

[2] flask-wtf官方文檔:https://flask-wtf.readthedocs.io/en/latest/

 

*本文為Alima原創,如果轉載請聯繫筆者,轉載註明格式[轉載][博客園][Alima][關於flask-wtf中API使用實例教程],併在文首註明本文鏈接,多謝合作。

*非法轉載及非法抄襲博文將依照網路著作權流程辦理,請尊重作者勞動成果,最終解釋權歸Alima與博客園共同所有,感謝合作


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 不多說,先上代碼,代碼的註釋寫的已經挺詳細的了 首先先瞭解了URL的一些常用的方法,現在我嘗試利用網址讀入內容到控制台列印輸出 很好奇會列印出什麼東西呢 下麵就是列印出來的東西 並不是想象中的會將我寫的博客列印出來,而是列印出了頁面的HTML佈局代碼 而教程中,使用Tomcat伺服器,URL地址指定 ...
  • 自定義模板引擎類 MyTpl.class.php 1 <?php 2 class MyTpl 3 { 4 private $tpl_vars = array(); 5 //分配 6 public function assign($key,$value){ 7 $this->tpl_vars[$key ...
  • 設計模式重點在於代碼風格的實現,使項目易於開發維護以及更新,同時,在底層代碼中存在著各種設計模式,使之易於拓展。總而言之,學會設計模式非常重要,在學習了《Head first 設計模式》之後,根據個人見解將裡面的知識與個人知識經驗結合提煉出來,方便以後自己回頭查閱複習,也同大家一起學習,如有不足,歡 ...
  • 首先如果TCP學過以後,再看UDP進行數據傳輸也是大同小異的,只是用到的類不同 UDP進行傳輸需要DataSocket和Datapacket類,Datapacket叫數據報,每一個數據報不能大於64k,都記錄著數據信息,發送端的IP、埠號, 以及要發送到的接收端的IP、埠號。 UDP進行傳輸是將 ...
  • 學Kotlin其實要看:http://kotlinlang.org/docs/kotlin docs.pdf 線上版是不完整的!!!少了一些章節,會有點難看懂後面的文檔。 我選擇了WordPress里的錯誤消息管理類wp error.php為對象,沒有依賴其他具體場景和類,所以比較適合移植和對比。 ...
  • ASA的美國總統競選 在這個大選之年,美國統計協會(ASA)將學生競賽和總統選舉放在一起,將學生預測誰是2016年總統大選的贏家準確的百分比作為比賽點。詳情見: http://thisisstatistics.org/electionprediction2016/ 獲取數據 互聯網上有很多公開的民調 ...
  • ...
  • 歐拉函數,就是歐拉發現的一個關於求素數的的公式,然後我們編個函數實現這個公式。 歐拉發現求小於等於n的正整數中有多少個數與n互質可以用這個公式: euler(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn),其中p1,p2……pn為x的所有素因數,x是不為0 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...