TasK 1: post含有文件及文本数据的form表单
1.1 UI交互
- 图片框使用的是element-Ui的走马灯
<div style="display: flex; justify-content: space-around; margin-top: 2%;">
<div id="btn_wrapper" style="border: none;">
<el-button id="select_VIS_btn" type="primary" plain size="mini" @click="click_to_selectVIS">传入可见光图像</el-button>
</div>
<div id="btn_wrapper" style="border: none;">
<el-button id="select_IR_btn" type="primary" plain size="mini" @click="click_to_selectIR"> 传入红外图像</el-button>
</div>
</div>
<div id="carousel">
<template>
<div id="banner">
<el-carousel :height="bannerHeight2 + 'px'" trigger="click" :autoplay="false" :initial-index="send_carousel_initial_index">
<el-carousel-item v-for="item in send_img_list" :key="item">
<img id="carousel_item_image" :src="item" alt="">
</el-carousel-item>
</el-carousel>
</div>
</template>
</div>
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n+1) {
background-color: #d3dce6;
}
- 需求:点击“传入可见光图像”选择本地图片,并回显到图片框;点击“可见光识别”按钮,将请求递交给flask后台,并让后台返回相应的数据
1.2 解决跨域问题
- 跨域问题一般都在后端解决。
def after_request(response):
response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin') or 'http://127.0.0.1:5000' or 'http://localhost:8082/'
response.headers['Access-Control-Allow-Methods'] = 'PUT, GET, POST, DELETE'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, Accept, Origin, Referer, User-Agent'
response.headers['Access-Control-Allow-Credentials'] = 'true'
return response
app = Flask(__name__)
app.after_request(after_request)
1.3 Vue相关代码
- 上传的表单的功能代码:(不显示)
<div style="display: none;">
<form action="" method="post" enctype="multipart/form-data">
<input id="select_VIS_Input" type="file" accept="image/jpeg,image/x-png,image/gif" size="30" name="photo_UAV" @change="selectVIS($event)">
<input id="select_IR_Input" type="file" size="30" name="photo_InfraRed" @change="selectIR($event)">
<input id="mode_Input" ref="select_mode_Input" type="text" class="txt_input" name="mode" style="margin-top:15px;">
</form>
</div>
- “传入可见光图像”按钮触发函数的业务逻辑
- 使用 reader.readAsDataURL(file) 将图片文件生成对应的URL,读取后的结果保存在reader.result变量中;
- 注意:图片对象不能通过中间变量存储,在另外个函数进行读取,只能在这个局部作用域读取,这是浏览器的安全机制导致;
- 要回显图片,一定要将图片文件对象转化为编码后的url,否则由于浏览器安全机制,是读取不到原来的url的;
- 【看vue.js文档】若赋值修改单变量的值,能立即渲染;但对于数组某下标的赋值修改却不行。因此要使用this.$set(des_obj, index, sec_obj);
- 若修改了走马灯播放图片列表的值,修改后的图片url会放在列表的最后,[此处列表仅含有两个图片url(index=0,1)];为了让选择的图片能立即看到效果,修改carousel_initial_index。
click_to_selectVIS() {
document.getElementById('select_VIS_Input').click()
document.getElementById('select_VIS_btn').blur()
},
selectVIS(e) {
const that = this
const file = e.target.files[0]
if (file) {
// 其中this.request_form是在data定义,但未赋值的变量 request_form: {},
// 注意:图片对象不能通过中间变量存储,在另外个函数进行读取,只能在这个局部作用域读取,这是浏览器的安全机制导致
this.request_form.append('photo_UAV', file, file.name)
const reader = new FileReader()
// 要回显图片,一定要将图片文件对象转化为编码后的url,否则由于浏览器安全机制,是读取不到原来的url的
reader.readAsDataURL(file)
reader.onloadend = function() {
const dataURL = reader.result
// 【看vue.js文档】若赋值修改单变量的值,能立即渲染;但对于数组某下标的赋值修改却不行。
// 因此要使用this.$set(des_obj, index, sec_obj)
that.$set(that.send_img_list, 0, dataURL)
}
document.getElementById('select_VIS_btn').style = 'background-color: #f0f9eb; color: #67C23A; border-color: #c2e7b0;'
// 若修改了走马灯播放图片列表的值,修改后的图片url会放在列表的最后,[此处列表仅含有两个图片url(index=0,1)]
// 为了让选择的图片能立即看到效果,修改carousel_initial_index
this.send_carousel_initial_index = 1
}
}
- “可见光识别”按钮业务逻辑
- 注意:若FormData已有key K,使用FormData.append(Key, Value)将不起作用。因此要判断是否存在了key K,再使用不同的方法赋值。
VISRegc() {
if (this.request_form.has('mode')) {
this.request_form.set('mode', 1)
} else {
this.request_form.append('mode', 1)
}
document.getElementById('VIS_btn').blur()
if (this.request_form.has('photo_UAV')) {
this.send_VIS_request()
this.get_carousel_initial_index = 2
}
}
1.4 Flask后台读取数据
- 使用request.values.get()获取任何(值)参数;
- 使用request.files[‘key’] 获取参数文件
mode = request.values.get('mode')
img = request.files['photo_UAV']
TasK 2: get文件且展示
- 业务要求:Task1post数据后,后台会response一组数据,这组数据含有识别结果图在后台的url。前台根据这个url再次向后台发起get请求,后台发送文件对象。前台接收此对象,并在某个image组件展示出来。
2.1 UI展示
2.2 Vue相关代码
- 此处要用async-await实现异步操作;
- 在向后台发起get请求,需加上当前时间的参数,防止出现浏览器缓存相关问题;
- responseType: ‘blob’ 设置接收对象是blob对象
- URL.createObjectURL()创建响应返回的对象对应的URL
- this.$set(this.get_img_list, 0, objectURL) 修改绑定展示区域的数据;
async send_image_request(data) {
try {
const res = await this.$http.post('/upload_image', this.multisrc_form)
const get_image_url = res.data.image_url
const res2 = await this.$http.get('/send_image', {
params: { url: get_image_url, t: +new Date() },
responseType: 'blob'
})
try {
const obj = res2.data
const objectURL = URL.createObjectURL(obj)
this.$set(this.get_img_list, 0, objectURL)
} catch (err) {
console.log(err)
}
} catch (err) {
console.log(err)
}
}
2.3 后台接收参数并发送含有对象的响应
- 此处使用了flask.send_from_directory()方法[API文档]
@app.route('/send_image/',methods=['GET'])
def send_image():
download_image_url = request.values.get('url')
index = download_image_url.rfind('/')
dir = download_image_url[:index]
file_name = download_image_url[index+1:]
print("处理结果返回成功!!!")
try:
response = send_from_directory(dir, file_name, as_attachment=True)
return response
except Exception as e:
return jsonify({"code": "异常", "message": "{}".format(e)})
Task3:选取txt文件,点击按钮可显示
- 业务需求:点击“传入文本模态”按钮,选择txt文件。点击“文本显示”,显示文本的内容信息。
3.1 UI展示
3.2 vue相关代码
- 点击按钮使用了回调函数selectText(getTextContent);
<div style="display: none;">
<form action="" method="post" enctype="multipart/form-data">
<input id="select_Img_Input" type="file" accept="image/jpeg,image/x-png,image/gif" size="30" name="photo_UAV" @change="selectImg($event)">
<input id="select_Text_Input" type="file" accept="text/plain" size="30" name="text" @change="selectText(getTextContent)">
<input id="mode_Input" type="text" class="txt_input" name="mode" style="margin-top:15px;">
</form>
</div>
<div id="" style="height: 80%;">
<div style="display: flex; justify-content: space-around; margin-top: -30%;">
<div id="popover_wrapper">
<div style="display: flex; justify-content: space-around;">
<template>
<el-popover
placement="top"
:title="text_title"
width="200"
trigger="click"
:content="text_content"
>
<el-button id="Text_btn" slot="reference" type="info" round>文本显示</el-button>
</el-popover>
</template>
</div>
</div>
</div>
</div>
- selectText()函数内容:
- 使用 reader.readAsText(resultFile, ‘UTF-8’)读取txt文本内容;
- 此处的callback函数是getTextContent
selectText(callback) {
const resultFile = document.getElementById('select_Text_Input').files[0]
if (resultFile) {
this.request_form.append('infos', resultFile)
this.text_title = resultFile.name
this.text_content = resultFile.data
const reader = new FileReader()
reader.readAsText(resultFile, 'UTF-8')
reader.onload = function(e) {
const fileContent = reader.result
if (callback && (typeof callback === 'function')) {
callback(fileContent)
}
}
}
document.getElementById('select_Text_btn').style = 'background-color: #f0f9eb; color: #67C23A; border-color: #c2e7b0;'
}
getTextContent(textContent) {
this.text_content = textContent
}