flask、element、vue项目实战:搭建一个加密excel数据的网站


本文分享知识:

  1. element 中上传组件 upload 的使用方法
  2. table 表格组件、form 表单组件、tooltip 提示框组件
  3. Python 中 os 模块的使用
  4. flask 接受前端传递的文件
  5. pyinstaller 打包 flask 项目

项目源码地址:https://gitee.com/myrensheng/encryption

加密文件比加密字符串更加复杂。

一、前端

页面的布局如下:
在这里插入图片描述

第一行为文件上传区,以及显示上传数据的表格。

第二行为加密的选项,以及加密后的数据表格。

1.1 上传文件
<el-upload class="upload-demo" drag :multiple=false :show-file-list=false
           :on-success="GetTableDate" action="http://127.0.0.1:5000/upload" multiple>
    <i class="el-icon-upload"></i>
    <div class="el-upload__text">只能上传excel文件;
        <br>将文件拖到此处,或<em>点击上传</em>
    </div>
    <div class="el-upload__tip" slot="tip"></div>
</el-upload>

el-upload 文件上传组件

on-success 方法,文件上传完成后,调用 GetTableDate 方法

action=“http://127.0.0.1:5000/upload” 上传的地址

1.2 数据表格
<el-table :data="tableData" max-height="250" border style="width: 100%">
    <el-table-column type="index" :index="indexMethod"></el-table-column>
    <el-table-column v-for="i in tableCols" :prop="i+''" :label="i+''">
    </el-table-column>
</el-table>

data:显示的数据

el-table-column type=“index” :index=“indexMethod” 显示表格索引

prop 属性,对应列内容的字段名

label 显示的标题

1.3 加密选项

表单组件

<el-form label-width="80px" :model="ruleForm" :rules="rules" ref="ruleForm">
    <el-form-item label="" prop=""> </el-form-item>
</el-form>

model 表单数据对象

rules 表单验证规则

加密内容输入框

考虑到各种不可预测的因素,以及完成加密多列的功能。这里将加密列全部用 1,2,3,4… 数字表示。即:1 表示第一列,输入的数字用英文逗号(,)隔开。

<el-form-item label="加密列" prop="encryCols">
	<el-input v-model="ruleForm.encryCols"></el-input>
</el-form-item>

el-input 输入框组件

v-model 输入的内容赋值给 ruleForm.encryCols

加密算法选择框

加密算法有很多中,用一个下拉框组件搞定

<el-form-item label="加密算法">
    <el-select v-model="ruleForm.encryModel" placeholder="请选择加密算法">
        <el-option label="md5_32" value="md5_32"></el-option>
        <el-option label="md5_16" value="md5_16"></el-option>
        <el-option label="sha1" value="sha1"></el-option>
        <el-option label="sha224" value="sha224"></el-option>
        <el-option label="sha256" value="sha256"></el-option>
        <el-option label="sha512" value="sha512"></el-option>
    </el-select>
</el-form-item>

el-select下拉框组件

el-option 下拉框中的选项

v-model=“ruleForm.encryModel” 将 el-option 中的 value 值绑定到ruleForm中的 encryModel 变量中

大小写单选框

加密后的字符串可以是大写也可以是小写

<el-form-item label="大写小写">
    <el-radio-group v-model="ruleForm.encryStyle">
        <el-radio label="小写"></el-radio>
        <el-radio label="大写"></el-radio>
    </el-radio-group>
</el-form-item>

el-radio-group 单选框

el-radio 单选框中的选项

提交、重置按钮

为防止后端接口请求过于频繁,当没有上传数据时,不请求数据。

重置按钮作用:清空输入框、回复初始化的选项

<el-form-item>
    <el-button type="primary" v-if="tableData" @click="submitForm('ruleForm')">
    提交
    </el-button>
    <el-tooltip class="item" v-else effect="dark" content="未上传Excel文件"
    placement="top-start">
    <el-button type="danger">提交</el-button>
    </el-tooltip>
    <el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>

用 v-if 、v-else 判断按钮是否需要调用函数

1.4 加密数据

加密数据表格中只显示输入的加密列,以及加密后的数据。

<el-table :data="md5TableData" max-height="250" border style="width: 100%">
    <el-table-column type="index" :index="indexMethod"></el-table-column>
    <el-table-column v-for="j in md5TableCols" :prop="j+''" :label="j+''">
    </el-table-column>
</el-table>

data:显示的数据

el-table-column type=“index” :index=“indexMethod” 显示表格索引

prop 属性,对应列内容的字段名

label 显示的标题

1.5 下载按钮

当没有加密数据时,下载按钮不请求后端接口。

<a v-if="md5TableData" href="http://127.0.0.1:5000/download">
    <el-button type="primary" style="margin-top: 10px;">
    下载
    </el-button>
</a>
<el-tooltip class="item" v-else effect="dark" content="没有加密文件"
placement="top-start">
	<el-button size="small" type="danger" style="margin-top: 10px;">下载</el-button>
</el-tooltip>

用 v-if 、v-else 判断按钮是否需要调用函数

el-tooltip 提示框组件

二、后端

2.1 、upload 文件上传

上传的文件接口,文件保存到同级目录下。当上传新的文件时,需要提前删除之前上传及加密后的文件。

@app.route("/upload", methods=["POST"])
def upload():
    # 上传文件到 static/excel 文件夹中
    # 清空数据文件
    if os.listdir(excel_path):
        excel_file = os.path.join(excel_path, os.listdir(excel_path)[0])
        os.remove(excel_file)
    # 清空已加密的excel文件
    if os.listdir(encry_excel_path):
        encry_excel_file = os.path.join(encry_excel_path, os.listdir(encry_excel_path)[0])
        os.remove(encry_excel_file)
    if 'file' not in request.files:
        return jsonify({"status": 400, "msg": "请上传excel文件!"})
    # 获取文件
    file = request.files['file']
    if file.filename != '' and allowed_file(file.filename):
        # 文件名不为空并且是excel文件
        filename = file.filename
        file.save(os.path.join(excel_path, filename))
        return jsonify({"status": 200, "msg": filename + "保存成功!"})
    return jsonify({"status": 400, "msg": "请上传excel文件"})

os.path.join() 拼接文件地址

os.remove() 删除文件夹下的文件

flask 中使用 request.files[‘file’] 获取上传的文件

file.save() 保存文件

2.2 table 数据表格接口

该接口用于返回上传的excel文件的数据

import xlrd
import xlwt

def get_table_values(file_path=excel_path):
    # 默认加密第一个表中的数据
    if os.listdir(file_path):
        filename = os.path.join(file_path, os.listdir(file_path)[0])
        workbook = xlrd.open_workbook(filename=filename)
        table = workbook.sheets()[0]
        # 默认返回前5行数据
        # table_rows = 5 if table.nrows >= 5 else table.nrows
        table_rows = table.nrows
        if table_rows == 0:
            return {"status": 400, "msg": "excel中没有数据!"}
        # 获取数据
        row_list = []
        for r in range(table_rows):
            row_dict = {}
            for k, v in enumerate(table.row_values(rowx=r)):
                row_dict[str(k + 1)] = v
            row_list.append(row_dict)
        return {"table_cols": table.ncols, "row_list": row_list, "excel_name": os.listdir(file_path)[0],
                "sheet_name": workbook.sheet_names()[0]}
    # 没有excel文件或者上传的不是excel文件
    return None

@app.route("/table", methods=["GET", "POST"])
def table():
    excel_values = get_table_values()
    # print(excel_values)
    if excel_values:
        return jsonify({"status": 200, "msg": "获取数据成功!", "excel_values": excel_values})
    else:
        return jsonify({"status": 400, "msg": "请上传excel文件"})

xlrd.open_workbook() 打开指定的excel文件

workbook.sheets()[0] 表示第一个工作薄

table.nrows 表格的行数

table.row_values() 返回对应行的数据

2.3 encryption 数据加密

用于接受前端传递的加密参数

import hashlib
def encryption_str(string, encry_model="md5_32", encry_style=True):
    # 加密为 utf-8 编码
    utf_8_str = str(string).encode("utf8")
    # 函数字典
    param_dict = {
        "md5_32": hashlib.md5(utf_8_str),
        "md5_16": hashlib.md5(utf_8_str),
        "sha1": hashlib.sha1(utf_8_str),
        "sha224": hashlib.sha224(utf_8_str),
        "sha256": hashlib.sha256(utf_8_str),
        "sha512": hashlib.sha512(utf_8_str)
    }
    encry_result = param_dict[encry_model].hexdigest()
    if encry_model == 'md5_16':
        encry_result = encry_result[8:-8]
    # 返回结果
    return encry_result if encry_style == "小写" else encry_result.upper()

def encryption_clos(encry_cols=None, encry_model=None, encry_style=None):
    # 当加密的是空字符串是不加密,保留空字符串
    if not encry_model or not encry_cols or not encry_style:
        return None
    if os.listdir(excel_path):
        filename = os.path.join(excel_path, os.listdir(excel_path)[0])
        workbook = xlrd.open_workbook(filename=filename)
        table = workbook.sheets()[0]
        # excel 中没有数据
        if table.ncols == 0:
            return "excel 中没有数据!"
        if max(encry_cols) - 1 > table.ncols:
            # 输入的加密列不在excel中
            return str(max(encry_cols)) + "超过excel中最大的列"
        # 开始加密数据
        encry_workbook = xlwt.Workbook()
        work_sheet = encry_workbook.add_sheet("md5加密数据")
        c = 0
        for col in encry_cols:
            r = 0
            col_values = table.col_values(colx=col - 1)
            work_sheet.write(r, c, str(col))
            work_sheet.write(r, c + 1, str(col) + "_" + encry_model + "_" + encry_style)
            for v in col_values:
                if v == '':
                    encry_v = v
                else:
                    encry_v = encryption_str(string=v, encry_model=encry_model, encry_style=encry_style)
                work_sheet.write(r + 1, c, v)
                work_sheet.write(r + 1, c + 1, encry_v)
                r += 1
            c += 2
        encry_file = os.path.join(encry_excel_path, '加密数据.xlsx')
        encry_workbook.save(encry_file)
        # 返回md5文件的前5行数据
        encry_table_info = get_table_values(file_path=encry_excel_path)
        return encry_table_info
    return "服務器內部錯誤"

@app.route("/encryption", methods=["GET", "POST"])
def encryption():
    r_json = request.json
    encry_content = r_json["encryContent"]
    # 加密算法
    encry_model = r_json["encryModel"]
    # 加密类型(大写、小写)
    encry_style = r_json["encryStyle"]
    print(encry_content)
    if encry_content == "textarea":
        encry_textarea = str(r_json["input_textarea"])
        res = {
            "status": 200,
            "output_textarea": encryption_str(encry_textarea, encry_model=encry_model, encry_style=encry_style),
            "msg": "加密成功!"
        }
        return jsonify(res)

    # 需要加密的列
    encry_cols = r_json["encryCols"]
    if False in [i.isnumeric() for i in encry_cols.strip().strip(",").split(",")]:
        return jsonify({"status": 400, "msg": "加密列以英文‘,’隔开!"})
    # 加密成功,直接返回加密后的数据
    encry_cols = list(set([int(i) for i in encry_cols.split(",")]))
    encry_excel_values = encryption_clos(encry_cols, encry_model, encry_style)
    if isinstance(encry_excel_values, dict):
        return jsonify({"status": 200, "msg": "加密成功!", "excel_values": encry_excel_values})
    else:
        return jsonify({"status": 400, "msg": encry_excel_values})

requests.json 获取前端 post 的请求数据

isinstance() 判断变量的数据类型

2.4 download 文件下载

用于下载加密后的文件

@app.route("/download", methods=["GET", "POST"])
def download():
    return send_from_directory(encry_excel_path, '加密数据.xlsx')

send_form_directory() 用来发送文件

三、前后端交互

用 axios 库来实现前后端数据交互

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!--导入 axios 获取数据-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
<script>
		new Vue({
			el: '#app',
			delimiters:['[{', '}]'],
			data: function() {
				return {
					FiledsCheckboxGroup: ['上海'],
					// EncryRadioGroup: encryptions[0],
					tableCols: ["上传数据预览"],
					tableData: null,
					md5TableCols: ["加密数据预览"],
					md5TableData: null,
					// excel名字
					excel_name: "Excel文件名",
					sheet_name: null,
					// 表单数据
					ruleForm: {
						encryCols: '',
						encryModel: "md5_32",
						encryStyle: '小写',
						encryContent:'excel'
					},
					// 表单验证
					rules: {
						"encryCols": [{
							required: true,
							message: '请输入加密列',
							trigger: 'blur'
						}]
					},
					// 单字符串加密
					output_textarea:null,
					textareaEncryForm:{
					    encryModel: "md5_32",
						encryStyle: '小写',
						input_textarea:null,
						encryContent:'textarea'
					},
				}
			},
			methods: {
				async GetTableDate(response, file, fileList) {
					// 获取上传excel的数据并展示
					const {
						data: res
					} = await this.$http.get("http://127.0.0.1:5000/table")
					if (res.status != 200) {
						this.$message({
							showClose: true,
							message: res.msg,
							center: true,
							type: 'error'
						})
						this.tableCols = ["数据预览,暂无数据"]
						this.tableData = []
					} else {
						this.$message({
							showClose: true,
							message: res.msg,
							center: true,
							type: 'success'
						})
						this.tableCols = res.excel_values.table_cols
						this.tableData = res.excel_values.row_list
						this.excel_name = res.excel_values.excel_name
						this.sheet_name = res.excel_values.sheet_name
					}
				},
				submitForm(formName) {
					this.$refs[formName].validate(async (valid) => {
						if (valid) {
							// 提交需要加密的列
							const {
								data: res
							} = await this.$http.post("http://127.0.0.1:5000/encryption", this.ruleForm)
							if (res.status == 200) {
								this.$message({
									showClose: true,
									message: res.msg,
									center: true,
									type: 'success'
								});
								this.md5TableCols = res.excel_values.table_cols;
								this.md5TableData = res.excel_values.row_list;
							} else {
								this.$message({
									showClose: true,
									message: res.msg,
									center: true,
									type: 'error'
								})
							}
						} else {
							this.$message({
								showClose: true,
								message: "请输入需要加密的列!",
								center: true,
								type: 'error'
							})
							return false;
						}
					});
				},
				resetForm(formName) {
					this.ruleForm.encryModel = "md5_32";
					this.ruleForm.encryCols = "";
					this.ruleForm.encryStyle = "小写";
					this.$refs[formName].resetFields();
				},
				indexMethod(index) {
					return index;
				},
				async textareasubmitForm(textareaEncryForm) {
							const {data: res} = await this.$http.post("http://127.0.0.1:5000/encryption", this.textareaEncryForm)
							if (res.status == 200) {
								this.$message({
									showClose: true,
									message: res.msg,
									center: true,
									type: 'success'
								});
								console.log(res);
								this.output_textarea = res.output_textarea;
							} else {
								this.$message({
									showClose: true,
									message: res.msg,
									center: true,
									type: 'error'
								})
							}
				},
				textarearesetForm() {
					this.textareaEncryForm.encryModel = "md5_32";
					this.textareaEncryForm.input_textarea = null;
					this.textareaEncryForm.encryStyle = "小写";
					this.output_textarea = null;
				},
			},
		})
</script>

四、打包exe文件

终于,小凡完成了加密excel文件的事情,考虑到经理和其他需要使用的同事没有Python环境,于是,小凡用 Python中的 pyinstaller 工具,将代码打包为 exe 文件。

pyinstaller -F --add-data="./static;./static" --add-data="./templates;./templates" --add-data="./tools.py;." app.py
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅帅的Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值