原文地址:javascript
近期項目開發中,隔壁那個搞python的哥們居然笑着對我說,但願我能給他寫1個百度編輯器的demo,方便他直接調用。
當時真的受寵若驚,這哥們實力不在我之下,只能答應它了。上網搜索下,有1篇文章Flask項目集成富文本編輯器UEditor實現圖片上傳功能已經有1個現成的例子了。
這篇文章的做者,直接在視圖中定義對應的操做,進行一系列圖片上傳功能的。可是,這並無知足個人要求,我想要的想過是直接導入一個模塊,而後它幫我作完一切的事情。好比這樣的形式:html
from xxx import yyy app = Flask(__name__) yyy(app)
因而只好從頭開始學習。
這裏,我按照以下的方式從頭編寫1個Flask版本的百度編輯器的插件:前端
百度文檔的解讀java
後端實際代碼的編寫python
前端代碼的編寫git
下面咱們開始咱們編寫插件的過程。github
在百度文檔中,已經說明UEditor提供4種後臺語言,分別爲php,asp,asp.net和jsp。首先須要配置serverUrl參數,當ueditor初始化會向serverUrl中的URL發起對後端配置的請求。
而配置的優先級以下:json
後端獲取的配置項 > 實例化傳入的配置項 > ueditor.config.js文件的配置項
能夠看到,後端獲取的配置項優先級是最高的。在對後端配置請求的過程當中,會對配置文件config.json
中的設置進行讀取。
而在請求的過程當中,百度文檔統一請求格式說明中已經說明,經過GET請求上的action參數來判斷是什麼類型的請求。後端根據不一樣的請求,進行對應的處理後,須要返回給定格式的內容給前端Javascript。返回的結果通常爲JSON的形式。flask
如今咱們已經對百度編輯器UEditor的文檔進行了初步的解讀,下面咱們開始編寫咱們實際的代碼。
在這裏,咱們主要會用到config和uploadimage這2個配置,其餘功能留給讀者本身去實現。
在編寫代碼以前,我打算這樣來實現這個插件:
配置文件爲1個python的模塊
有1個模塊用於處理對應請求的操做
有1個模塊用於處理圖片上傳的操做,這裏直接拿取以前Flask文檔做者中的上傳模塊
而後咱們逐一進行講解。
這裏,我打算將百度默認提供的配置寫入到1個config的模塊中,原本打算使用相似以下的方式:
imageAction = "uploadimage" imageFieldName = "upfile" ...
因爲時間比較緊,一時半會作不到Flask中讀取配置文件後爲1個字典的形式,所以簡化爲該模塊直接返回1個字典,以下所示:
CONFIG = dict(imageActionName = "uploadimage", # 執行上傳圖片的action名稱 imageFieldName = "upfile", #提交的圖片表單名稱 imageMaxSize = 2048000, #上傳大小限制,單位B imageAllowFiles = ['.png', '.jpg', '.jpeg', '.gif', '.bmp'], #上傳圖片格式顯示 imageCompressEnable = True, #是否壓縮圖片,默認是true imageCompressBorder = 1600, #圖片壓縮最長邊限制 imageInsertAlign = "none", #插入的圖片浮動方式 imageUrlPrefix = "", #圖片訪問路徑前綴 imagePathFormat = "upload/{yyyy}/{mm}/{dd}/{time}{rand:6}" )
咱們將這段代碼定義爲config模塊中,這樣,咱們就完成了配置模塊的內容了。
這裏咱們定義1個ueditor的模塊用於咱們處理請求的操做。這裏,我定義了1個UEditor的類用於處理這個操做:
class UEditor(object): pass
首先咱們要作的第一步是解決請求參數的問題,讓不一樣的請求調用不一樣的處理函數,咱們將其定義在該類的get_action
函數中:
def get_action(self): action = request.args.get('action') if action: return self.handle(action)
咱們將具體處理的過程放在handle函數中,在這個函數中,咱們要作2件事情:
根據不一樣的請求參數調用不一樣的函數
將不一樣函數返回的結果返回給調用者
而後是handle函數其具體的源碼:
def handle(self, action): if action == 'config': result = get_config() elif action == 'uploadimage': result = upload_image() else: result = {'state': '未實現'} res = make_response(json.dumps(result)) res.headers['Access-Control-Allow-Origin'] = '*' res.headers['Access-Control-Allow-Headers'] = 'X-Requested-With,X_Requested_With' return res
能夠看到,這部分的源碼和咱們以前編寫的並無什麼不一樣。在action時咱們應該將配置文件中的內容直接返回便可:
def get_config(): return CONFIG
而在上傳圖片的時候,咱們根據配置文件中的配置,將其傳遞給上傳文件的模塊,這裏咱們直接把以前Flask那篇文章做者git上的Uploader拿了過來。其實他也是參考php的實現的源碼,將其修改成python版本而言。
def upload_image(): """上傳圖片""" fieldName = CONFIG.get('imageFieldName') conf = dict(pathFormat = CONFIG.get('imagePathFormat'), maxSize = CONFIG.get('imageMaxSize'), allowFiles = CONFIG.get('imageAllowFiles') ) if request.files.get(fieldName): field = request.files[fieldName] uploader = Uploader(field, conf, 'static') result = uploader.getFileInfo() else: result = {'state': '上傳接口出錯'} return result
這裏,在Uploader類中第1個參數爲類文件對象,第2個參數爲對應的配置,第3個參數爲圖片上傳的根目錄。最後,經過這個實例的getFileInfo方法獲得後端上傳成功後返回的內容。
這樣,咱們就基本解決了後端圖片上傳的過程了。可是,前端的調用問題咱們徹底尚未涉及到,下面咱們來講說前端的調用問題。
關於前端調用的問題,我我的的設想是在1個模板文件中咱們引入百度UEditor對應的Javascript文件,而後咱們初始化對應的對象後,設置serverUrl爲咱們給定的URL地址便可操做了。通常咱們的代碼是這樣的:
<script type="text/javascript" charset="utf-8" src="static/ueditor.config.js"></script> <script type="text/javascript" charset="utf-8" src="static/ueditor.all.min.js"> </script> <script type="text/javascript" charset="utf-8" src="static/lang/zh-cn/zh-cn.js"></script> <div> <div id="editor" style="height:400px;"></div> </div> <script type="text/javascript"> var ue = UE.getEditor('editor', { serverUrl: "xxxx/yyyyy" }); </script>
以前咱們後端代碼的過程只解決了圖片上傳的問題,關於serverUrl關聯到對應URL的問題還一直沒有解決。
爲了解決這個問題,我打算引入藍圖和Flask提供的add_url_rule
來解決這個問題。
UE = Blueprint('ueditor', __name__, url_prefix= '/ueditor') ... def init_app(self,app): self.app = app UE.add_url_rule('/upload/' 'uploads', self.get_action, methods = ['POST', 'GET', 'OPTIONS']) self.app.register_blueprint(UE)
而後咱們讓Flask應用實例註冊這個藍圖,這樣當咱們服務器啓動時,就可使用這個藍圖url地址了。
最後,咱們總結下這個插件的使用方法,咱們新建1個app模塊,其源碼相似以下:
from flask import Flask, render_template from ueditor import UEditor app = Flask(__name__) ue = UEditor(app) @app.route('/') def index(): return render_template('index.html')
在這裏,咱們引入咱們以前編寫的插件模塊,而後將其實例化操做。而在index.html文件中則爲咱們以前引入百度編輯器的內容。
在這裏index.html
的內容相似以下:
<script type="text/javascript" charset="utf-8" src="/static/ueditor/ueditor.config.js"></script> <script type="text/javascript" charset="utf-8" src="/static/ueditor/ueditor.all.min.js"> </script> <script type="text/javascript" charset="utf-8" src="/static/ueditor/lang/zh-cn/zh-cn.js"></script> <div> <div id="editor" style="height:400px;"></div> <button id="submit">提交</button> </div> <script type="text/javascript"> var ue = UE.getEditor('editor', { serverUrl: "/ueditor/upload/" }); </script>
這樣咱們便完成了百度編輯器的1個插件的編寫了。
參考文章:
http://fex-team.github.io/ueditor/#server-deploy
http://fex-team.github.io/ueditor/#server-config
http://fex-team.github.io/ueditor/#dev-request_specification