偶然在Java开发同事那里看到他们临时项目使用的一个文件上传页面,比我原来写的好看,并且支持拖拽上传、多个文件上传。但它使用Java提供服务,没法直接使用, 简单写了一个Python Flask的后端脚本。
前端页面如下:
?
目录结构:
? ? ? ? flask_file_upload
? ? ? ? ? -- static
? ? ? ? ? ? ? ?-- uploads
? ? ? ? ? ? ? ? ? ? -- 视频.mp4
? ? ? ? ? -- app.py
? ? ? ? UI_file_upload
? ? ? ? ? -- css
? ? ? ? ? ? ? -- style.css
? ? ? ? ? -- images
? ? ? ? ? -- scripts
? ? ? ? ? ? ?--?lang.zh-Hans.js
? ? ? ? ? ? ?--?transfer.js
? ? ? ? ? -- index.html
app.py :
# !usr/bin/python3
# -*- coding=utf-8 -*-
# @File : app.py
# @Time : 2021-07-06
import os
import json
from urllib.parse import quote, unquote
from gevent import monkey
from gevent.pywsgi import WSGIServer
from flask_cors import CORS, cross_origin
from werkzeug.utils import secure_filename
from flask import Flask, \
Blueprint, \
request, \
jsonify, \
make_response, \
send_from_directory
monkey.patch_all() # 将python标准的io方法,都替换成gevent中的同名方法,遇到io阻塞gevent自动进行协程切换
app = Flask(__name__)
cors = CORS(app)
app.config['JSON_AS_ASCII'] = False # 而json.dumps方法需要添加参数 ensure_ascii=False;避免显示中文乱码
# app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024 # 设置上传文件大小
basepath = os.path.dirname(__file__)
UPLOAD_PATH = os.path.join(basepath, r'static\uploads')
# 解析文件大小并分配相应的单位
def allocateUnit(value):
multiplyFactor = 0
tokens = ["bytes", "KB", "MB", "GB", "TB"]
while value > 1024:
value /= 1024
multiplyFactor += 1
if multiplyFactor <= 4:
tokensUnit = tokens[multiplyFactor]
return "%s %s" % (round(value, 2), tokensUnit)
@app.route('/files/<filename>', methods=["GET", "POST"])
def get_image(filename):
if request.method == 'GET':
# filename = quote(filename, "utf-8") # 若使用 secure_filename, 则必须转换
response = make_response(send_from_directory(UPLOAD_PATH, filename, as_attachment=True))
response.headers["Content-Disposition"] = "attachment; filename={}".format(
filename.encode().decode('latin-1'))
return response
if request.method == 'POST':
# filename = quote(filename, "utf-8") # 若使用 secure_filename, 则必须转换
file_path = os.path.join(UPLOAD_PATH, filename)
os.remove(file_path)
return jsonify({'data': {'code': 'Delete success !'}}), 200
@app.route('/files/', methods=['POST', 'GET'])
def upload():
if request.method == 'GET':
file_list = []
for root, dirs, files in os.walk(UPLOAD_PATH):
for f in files:
f_dict = {}
f_p = os.path.join(root, f)
# f_size = round((((os.stat(f_p)).st_size)/1024)/1000, 2)
f_size = allocateUnit((os.stat(f_p)).st_size)
f_dict["name"] = unquote(f, "utf-8")
f_dict["size"] = (f_size)
file_list.append(f_dict)
return json.dumps(file_list)
if request.method == 'POST':
f = dict(request.form)['fileName'] # f = 2022-03%E6%8A%80%E6%9C%AF%E7%A0%94%E5%8F%91%E4%B8%AD%E5%BF%83KPI%E8%80%83%E6%A0%B8%E8%A1%A8.xlsx
f = unquote(f, "utf-8") # Uri解码后:f = 2022-03技术研发中心KPI考核表.xlsx
fname = request.files.get('newfile')
# 当前文件所在路径; 由于secure_filename 会忽略中文(“2022-03技术研发中心KPI考核表.xlsx” 会被更改为 “2022-03KPI.xlsx”),弃用
# upload_file_path = os.path.join(basepath, r'static\uploads', secure_filename(f))
upload_file_path = os.path.join(basepath, r'static\uploads', f)
# print(upload_file_path) # D:\pythontest\98-test\981-flaskupload\static\uploads\2022-03技术研发中心KPI考核表.xlsx
fname.save(upload_file_path)
return jsonify({'data': {'code': 'success'}}), 200
if __name__ == '__main__':
# 将 127.0.0.1 8800 修改为本机的 ip地址即可
app.run(threaded=True, host="127.0.0.1", port=8800, debug=True)
?
transfer.js (server_add 按需改为后端服务器的地址):
$(function() {
var isDragOver = false;
var files = [];
// server_add 按需改为后端服务器的地址
var server_add = "http://127.0.0.1:8800/";
var currentFileName;
var uploadQueue = [];
var currentQueueIndex = 0;
var isUploading = false;
var getProgressReties = 0;
var html5Uploader = null;
var items = {};
function initPageStrings() {
document.title = STRINGS.WIFI_TRANS_TITLE;
$('.content_title').text(STRINGS.FILES_ON_DEVICE);
$('.table_header .filename').text(STRINGS.FILENAME);
$('.table_header .size').text(STRINGS.FILE_SIZE);
$('.table_header .operate').text(STRINGS.FILE_OPER);
}
lang.zh-Hans.js (Web页面显示的内容和标题,按需更改):?
????
var STRINGS = {};
STRINGS.WIFI_TRANS_TITLE = 'File Upload'; STRINGS.FILES_ON_DEVICE = '您设备上的文件列表'; STRINGS.FILENAME = '文件名'; STRINGS.FILE_SIZE = '大小'; STRINGS.FILE_OPER = '操作'; STRINGS.CONFIRM_DELETE_BOOK = '是否删除文件?'; STRINGS.DOWNLOAD_FILE = '下载文件'; STRINGS.DELETE_FILE = '删除文件'; STRINGS.USE_ONE_BROWSER = '无法上传文件,请勿使用多个浏览器窗口同时上传。'; STRINGS.UPLOAD_FAILED = '上传失败,请重新打开网络 并 刷新此页重新上传。'; STRINGS.UNSUPPORTED_FILE_TYPE = '请选择文件。'; STRINGS.FILE_IN_QUEUE = '文件已经在上传列队中。'; STRINGS.FILE_EXISTS = '文件已存在,请先删除再重新上传。'; STRINGS.YOU_CHOOSE = '您选择了'; STRINGS.CHOSEN_FILE_COUNT = '个文件,只能上传'; STRINGS.VALID_CHOSEN_FILE_COUNT = '个文件。\n请选择文件,文件名不能重复。'; STRINGS.CANCEL = '取消'; STRINGS.SELECT_YOUR_FILES = '请选择您要上传的文件'; STRINGS.SUPPORTED_FILE_TYPES = '支持MP4'; STRINGS.CANNOT_CONNECT_SERVER = '无法连接到服务器,请重新连接网络并刷新此页后重新上传。'; STRINGS.DRAG_TO_HERE = "拖拽到此处上传"; STRINGS.SELECT_BUTTON_LABLE1 = "选择文件"; STRINGS.SELECT_BUTTON_LABLE2 = "可同时上传多个文件"; STRINGS.SELECT_BUTTON_LABLE = "选择文件"; STRINGS.WIFI_AVAILABLE = "网络连接已启用";
STRINGS.FONT_WIFI_TRANS_TITLE = 'WFi 传字体'; STRINGS.FONT_CONFIRM_DELETE_BOOK = '是否删除字体?'; STRINGS.FONT_UNSUPPORTED_FILE_TYPE = '请选择您要上传的TTF或OTF字体文件。'; STRINGS.FONT_SUPPORTED_FILE_TYPES = '支持TTF和OTF'; STRINGS.FONT_VALID_CHOSEN_FILE_COUNT = '个文件。\n请选择TTF或OTF文件,文件名不能重复。'; STRINGS.FONT_FILE_EXISTS = '文件已存在。'; ?
前端使用Nginx运行,后端Flask运行即可。
前端:
???????? 下载:https://wwz.lanzoul.com/ijaYH07vaf6f?密码:6wcu
?????????
|