Home » Flask 教程 » Flask项目集成富文本编辑器UEditor 实现图片上传功能
  • 28
  • 08月

本文介绍如何在Flask项目中集成富文本编辑器UEditor,并实现文件上传、图片上传、视频上传及涂鸦功能。

[TOC]

UEditor简介

UEditor是由百度「FEX前端研发团队」开发的所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码。

由于1.4.2版本之后的版本与之前版本存在较大的差异,本文以1.4.3版本为蓝本。

具体文档参见:http://fex-team.github.io/ueditor/

在Flask项目中加入UEditor

下载UEditor:

访问UEditor首页,下载1.4.3 PHP UTF-8版本的UEditor,并解压到Flask应用程序的static目录。解压之后的目录结构是这样的:

| static/
| | ueditor/
| | |+dialogs/
| | |+lang/
| | |+php/
| | |+themes/
| | |+third-party/
| | |-config.json
| | |-index.html
| | |-ueditor.all.js
| | |-ueditor.all.min.js
| | |-ueditor.config.js
| | |-ueditor.parse.js
| | |-ueditor.parse.min.js

+表示目录。

在项目中加入UEditor:

我们在Flask应用程序的templates目录新建一个index.html文件(可根据实际情况选择文件名,或者把代码加入需要使用UEditor的文件):

在head标签加入下面几行:

<script type="text/javascript" charset="utf-8" src="{{ url_for('static', filename='ueditor/ueditor.config.js') }}"></script>
<script type="text/javascript" charset="utf-8" src="{{ url_for('static', filename='ueditor/ueditor.all.min.js') }}"> </script>
<!--建议手动加在语言,避免在ie下有时因为加载语言失败导致编辑器加载失败-->
<!--这里加载的语言文件会覆盖你在配置项目里添加的语言类型,比如你在配置项目里配置的是英文,这里加载的中文,那最后就是中文-->
<script type="text/javascript" charset="utf-8" src="{{ url_for('static', filename='ueditor/lang/zh-cn/zh-cn.js') }}"></script>

在body标签加入:

<script id="editor" type="text/plain"></script>

<script type="text/javascript">
    //实例化编辑器
    //建议使用工厂方法getEditor创建和引用编辑器实例,如果在某个闭包下引用该编辑器,直接调用UE.getEditor('editor')就能拿到相关的实例
    var ue = UE.getEditor('editor', {
        serverUrl: "/upload/"
    });
</script>

请求路径配置:

UEditor 1.4.2+ 起,推荐使用统一的请求路径,在部署好前端代码后,需要修改 ueditor.config.js 里的 serverUrl 参数(或者初始化时指定,见上面的代码),改成 '/upload/'

UEditor初始化时,会向后端请求配置文件,后端收到请求后返回JSON格式的配置文件。具体实现参照后面的代码。

详细配置内容参见文档。

创建Flask应用程序(app.py):

# -*- coding: utf-8 -*-
# filename: app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/upload/', methods=['GET', 'POST'])
def upload():
    pass

if __name__ == '__main__':
    app.run(debug=True)

应用程序运行之后,我们访问 http://localhost:5000/ 就可以看到UEditor编辑器了,上图:

flask-ueditor-demo.png

UEditor后端请求规范说明

与后台通信的功能列表:

  • 上传图片
  • 拖放图片上传、粘贴板图片上传
  • word文档图片转存
  • 截图工具上传
  • 上传涂鸦
  • 上传视频
  • 上传附件
  • 在线图片管理
  • 粘贴转存远程图片

统一请求格式说明:

  • 前端请求通过唯一的后台文件 /upload/ 处理前端的请求
  • /upload/通过GET上的action参数,判断是什么类型的请求
  • 省去不必要的请求,去除涂鸦添加背景的请求,用前端FileReader读取本地图片代替
  • 请求返回数据的格式,常规返回json字符串,数据包含state属性(成功时返回'SUCCESS',错误时返回错误信息)。
  • 请求支持jsonp请求格式,当请求有通过GET方式传callback的参数时,返回json数据前后加上括号,再在前面加上callback的值,格式类似这样: cb({"key": "value"})

详细说明:http://fex-team.github.io/ueditor/#dev-request_specification

Flask实现后端请求

获取配置信息

由于接口升级,编辑器初始化时,首先会向后端请求配置信息,后端收到请求后,返 回相应的配置信息即可。

请求参数:

GET {"action": "config"}
POST "upfile": File Data

返回格式:

// 需要支持callback参数,返回jsonp格式
{
    "imageUrl": "http://localhost/ueditor/php/controller.php?action=uploadimage",
    "imagePath": "/ueditor/php/",
    "imageFieldName": "upfile",
    "imageMaxSize": 2048,
    "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"]
}

主要功能代码:

@app.route('/upload/', methods=['GET', 'POST'])
def upload():
    action = request.args.get('action')

    # 解析JSON格式的配置文件
    # 这里使用PHP版本自带的config.json文件
    with open(os.path.join(app.static_folder, 'ueditor', 'php',
                           'config.json')) as fp:
        try:
            # 删除 `/**/` 之间的注释
            CONFIG = json.loads(re.sub(r'\/\*.*\*\/', '', fp.read()))
        except:
            CONFIG = {}

    if action == 'config':
        # 初始化时,返回配置文件给客户端
        result = CONFIG

    return json.dumps(result)

文件、视频、图片上传

图片上传包括:本地图片上传、拖拽图片上传、粘贴板图片上传。

这些功能实现的方法是一样的,所以放到一起来讲。上传的文件可用request.files['upfile']获取。

请求参数:

GET {"action": "uploadimage"}
POST "upfile": File Data

action说明:

  • uploadimage 上传图片
  • uploadvideo 上传视频文件
  • uploadfile 上传附件(文件)

返回格式:

{
    "state": "SUCCESS",
    "url": "upload/demo.jpg",
    "title": "demo.jpg",
    "original": "demo.jpg"
}

主要功能代码:

@app.route('/upload/', methods=['GET', 'POST'])
def upload():
    result = {}
    action = request.args.get('action')

    if action in ('uploadimage', 'uploadvideo', 'uploadfile'):
        upfile = request.files['upfile']  # 这个表单名称以配置文件为准
        # upfile 为 FileStorage 对象
        # 这里保存文件并返回相应的URL
        upfile.save(filename_to_save)
        result = {
            "state": "SUCCESS",
            "url": "upload/demo.jpg",
            "title": "demo.jpg",
            "original": "demo.jpg"
        }

    return json.dumps(result)

涂鸦功能

涂鸦功能上传经过BASE64编码的图片(一般为PNG格式),可用request.form['upfile']获取,后端收到之后需要先解码,再保存。

请求参数:

GET {"action": "uploadscrawl"}
POST "content": Base64 Data

返回格式:

{
    "state": "SUCCESS",
    "url": "upload/demo.jpg",
    "title": "demo.jpg",
    "original": "demo.jpg"
}

主要功能代码:

@app.route('/upload/', methods=['GET', 'POST'])
def upload():
    result = {}
    action = request.args.get('action')

    if action in ('uploadscrawl'):
        base64data = request.form['upfile']  # 这个表单名称以配置文件为准
        img = base64.b64decode(base64data)
        # 这里保存文件并返回相应的URL
        with open(filename_to_save, 'wb') as fp:
            fp.write(img)
        result = {
            "state": "SUCCESS",
            "url": "upload/demo.jpg",
            "title": "demo.jpg",
            "original": "demo.jpg"
        }

    return json.dumps(result)

远程抓图

远程抓图主要是把站外的图片保存到本地或者指定的图片服务器。

当复制粘贴其他网站的网页的图片时,会触发远程抓图功能。

远程图片列表可通过request.form.getlist('source[]')获取。这里暂时不清楚是 什么原因,为什么request.form.getlist('source') 为空。

核心思路:遍历远程图片列表,通过urllib把图片下载并保存,下载完成之后按照格 式返回结果。

请求参数:

GET {
    "action": "catchimage",
     "source": [
        "http://a.com/1.jpg",
        "http://a.com/2.jpg"
    ]
}

返回格式:

// 需要支持callback参数,返回jsonp格式
// list项的state属性和最外面的state格式一致
{
    "state": "SUCCESS",
    "list": [{
        "url": "upload/1.jpg",
        "source": "http://b.com/2.jpg",
        "state": "SUCCESS"
    }, {
        "url": "upload/2.jpg",
        "source": "http://b.com/2.jpg",
        "state": "SUCCESS"
    }, ]
}

完整DEMO

Flask UEditor完整DEMO:https://coding.net/u/wtx358/p/flask-ueditor-demo/git

实现了图片上传、附件上传、视频上传、涂鸦、远程抓图等功能。