【Flask-Vue开发】post含有文件及文本数据的form表单并get文件且展示

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
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值