爲Flask編寫1個百度編輯器的插件

原文地址:javascript

http://52sox.com/write-a-flask-plugin-for-ueditor/php

近期項目開發中,隔壁那個搞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件事情:

  1. 根據不一樣的請求參數調用不一樣的函數

  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

相關文章
相關標籤/搜索