<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      node.js+react全棧實踐-Form中按照指定路徑上傳文件并

      書接上回,講到“使用同一個新增彈框”中有未解決的問題,比如復雜的字段,文件,圖片上傳,這一篇就解決文件上傳的問題。這里的場景是在新增彈出框中要上傳一個圖片,并且這個上傳組件放在一個Form中,和其他文本字段一起提交給接口。

      這里就有幾個要注意的問題:

      1. 圖片上傳時最好能在前端指定圖片類型,根據這個類型上傳到指定的目錄。比如這里是新增用戶,上傳用戶圖片,那么這里就指定類型是“user”,那么就把這個文件上傳到服務器的upload/user目錄中。這樣方便后期維護,比如要把項目中的文件統一遷移到另外一個服務器,只要把upload目錄復制出來就好了。
      2. 上傳組件是通用的,上傳完之后回傳給前端一個路徑信息,由于使用的是and design中的Form,這時要把這個路徑賽到form的數據中一并提交給新增接口。

      1.后端上傳文件接口

      1.1 使用multer

      前面在寫新增數據,請求數據的時候使用的到中間件bodyParser,解析客戶端請求的時候,使用的json類型接受數據,這個很方便,但是上傳文件的時候是一般是multipart/form-data這種類型,bodyParser不能解析這種類型。于是這里引入另外一種中間件multer。multer專門處理multipart/form-data類型的表單數據,專業的。

      multer有兩種使用方式,如果只是一般的網頁應用,直接指定dest,也就是上傳路徑就可以了。如果上傳時進行更多的控制,可以使用storage選項。這里我從簡單的入手,直接指定文件路徑上傳一個文件。

      // 指定文件上傳路徑
      var upload = multer({dest: path.join(__dirname, './../public/upload/tmp')}); 

      這里使用到node.js中的path模塊,將./../public/upload/tmp這個相對路徑轉換成計算機本地路徑,注意這里我們在express項目的public目錄下新建了upload/tmp目錄,至于為啥是tmp這樣的臨時文件夾,請繼續往下看。

      接著定義上傳接口:

          router.post('/singleFile', upload.single('file'), function (req, res, next) {
          }) 

      這里我們定義了一個api/base/singleFile接口,接受Form中一個名叫file的上傳文件標簽,這樣定義之后就可以吧文件上傳到public/upload/tmp目錄下。

      1.2 指定上傳目錄

      multer這種指定路徑上傳的方式是一開始就指定好了,后面都上傳到這個目錄,就是說這個目錄不能是一個變量,那如何能夠根據前端傳過來的參數將圖片上傳到指定的目錄呢?我這里首先想到的就是“剪切”文件。既然用的是node.js,文件操作的api就少不了剪切文件了。還有官方文檔上說明了,回調函數中除了文件之外,還可以有req.body,如果有文本域數據,將在這個req.body中,這個和bodyParser是類似的。

      app.post('/profile', upload.single('avatar'), function (req, res, next) {
        // req.file 是 `avatar` 文件的信息
        // req.body 將具有文本域數據,如果存在的話
      }) 

      有了req.file,req.body這兩個對象之后剩下的工作就交給node.js了,代碼如下:

      // 文件上傳
      router.post('/singleFile', upload.single('file'), function (req, res, next) {
        if(req.body.fileLocation) {
          const newName = req.file.path.replace(/\\tmp/, '\\' + req.body.fileLocation) + path.parse(req.file.originalname).ext
          fs.rename(req.file.path, newName, err => {
            if (err) {
              res.json(result.createResult(false, { message: err.message }))
            } else {
              let fileName = newName.split('\\').pop()
              res.json(result.createResult(true, { path: `${req.body.fileLocation}/${fileName}` }))
            }
          })
        } else {
          res.json(result.createResult(false, {message: '未指定文件路徑'}))
        }
      })

      注意在這里還使用了fs模塊的rename方法,這個方法可以將文件重命名并修改文件路徑,就是剪切文件了。這里用replace方法把tmp目錄替換成前端傳過來的fileLocalhost,然后將文件移動到這個fileLocation目錄中。下面使用postman來debug跟蹤一下執行過程:

      postman請求:

      上傳到tmp目錄:

       移動到指定的user目錄:

       postman返回:

       

      至此,接口就寫好了,下面就是在前端調用這個接口。 

      2. 前端Form里調用接口 

      2.1 定義字段類型

      在上一篇node.js+react全棧實踐-開篇中,使用的是統一的數據添加組件來添加,數據。columns.js中未指定字段類型,都是文本框,這顯然不切合實際,在這里再加上一個屬性type:file表示在添加數據組件中,這個字段對應一個上傳文件組件。另外,如果對文件類型,大小有限制,這里也可以添加accept,size字段。代碼如下:

      const thumb = { title: '頭像', dataIndex: 'thumb', key: 'thumb', render: src => <img className={style.tableImg} alt='' src={ `${config.baseUrl.resource.upload}${src}` }/>, type: 'file', accept: 'image/gif,image/jpeg', size: 2 } 

      2.2 Upload上傳組件

      剩下的就要研究一下ant design中的Upload組件,看一下文檔就明白了。關鍵代碼如下:

      {field.map((f, index) => {
        switch (f.type) {
          case 'file':
            return <FormItem
              name='file'
              headers={headers}
              key={f.key}
              label={f.title}>
              {getFieldDecorator(f.key)(<div>
                <Upload
                  name="file"
                  accept={f.accept}
                  data={data}
                  listType="picture-card"
                  showUploadList={false}
                  action="http://localhost:3332/api/base/singleFile"
                  beforeUpload={this.beforeFileUpload.bind(this, f)}
                  onChange={this.handleFileChange.bind(this, f)}>
                  {imageURL ? <img src={imageURL} alt="avatar" style={{ width: '100%' }} /> : uploadButton}
                </Upload>
              </div>)}
            </FormItem>
          default:
            return <FormItem key={f.key} label={f.title}>
              {getFieldDecorator(f.key, { rules: [{ validator: this.customerValidator.bind(this, f) }] })(<Input placeholder={'請輸入' + f.title}/>)}
            </FormItem>
        }
      })} 

      name:這個是字段名字,如果是要調用api/base/singleFile這個接口,就要設置為file,和上面的upload.single('file')是對應起來的
      accept:接受的文件類型,從columns.js中thumb字段中獲取,也可以在beforUpload回調中驗證類型
      data:這個就是除了文件之外額外的參數,可以指定為{fileLocation: 'user'}表示要上傳到user子目錄,這里要贊美一下ant design,已經考慮了額外參數
      listType:顯示樣式,參考antd design文檔,不解釋
      showUploadList:同上,不解釋
      action:上傳文件接口,注意這里要使用本地api文件中定義的接口,不能使用服務端的接口路徑,否則會代理失敗的
      beforUpload:上傳文件之前的鉤子,這里要贊美一下ant design,可以額外傳一個參數f,帶入字段信息,這樣就可以獲取字段的accept,size信息,進行驗證
      onChange:文件狀態改變時的鉤子,繼續贊美一下ant design,同上,可以額外傳遞一個參數

      這里有一個小疑問:antd design中解釋onChange:“上傳中、完成、失敗都會調用這個函數”,我測試了一下,確實會調用三次,但是有兩次都返回了response,status都是done,和我想象的不一樣。這上傳成功了,按說有上傳中,完成個回調,那都是done是怎么回事,“完成”調用了兩次?

      onChang回調:

      到這里,接口已調通,文件已經能夠成功的從前端傳到后端了。 

      2.3 Form獲取文件路徑

      最后一個問題,這里使用Form組件填充,收集數據,Form中上傳組件是單獨的跑起來的,最后得到的是一個url,不是文件本身,如何將這個url給到form中呢?這里使用的是form.setFieldsValue({name: value})這個方法,簡答粗暴。代碼如下:

        handleFileChange(field, info) {
          let file = info.file
          if (file.response && file.response.success && file.response.data && file.response.data.path) {
            let { upload } = this.state
            upload.imageURL = `${config.baseUrl.resource.upload}${file.response.data.path}`
            // 為Form對應的字段設置值
            this.props.form.setFieldsValue({ [`${field.key}`]: file.response.data.path })
            this.setState({ upload })
            upload.loading = false
          }
        } 

      注意這里FormItem是動態加載出來的,并不知道是那個字段,所以onChange回調中額外傳遞了參數f,這樣,setFildsValue中就知道這是要設置Form中哪一個數據。

      最后看一下效果:

      上傳文件:

       

      數據表: 

      未解決的問題:

      1.上傳過程中如果因為其他問題導致失敗,并且是在轉移之前失敗,服務器上upload/tmp目錄會有很多的垃圾文件,這里可以在轉移之后把tmp目錄中的文件全部刪掉
      2.文件的校驗是放在beforUpdate鉤子里通過全局提示message.error彈出,這個是不是可以放在getFieldDecorator的rules里面,體驗會更好

       

      posted @ 2019-12-13 18:52  nd  閱讀(2468)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲精品美女一区二区| 亚洲精品一二三四区| 欧美熟妇乱子伦XX视频| 国产永久免费高清在线| 92国产精品午夜福利免费| 亚洲有无码中文网| 日本高清一区免费中文视频| 国产精品久久久久aaaa| 老熟妇老熟女老女人天堂| 国产99青青成人A在线| 亚洲国产精品综合久久2007| 国产在线观看免费观看| 手机在线看片不卡中文字幕 | 忘忧草日本在线播放www| 网友自拍视频一区二区三区| 精品超清无码视频在线观看| 成年女人免费碰碰视频| 亚洲午夜福利网在线观看| 丰满的女邻居2| 久久国产乱子精品免费女| 欧美性白人极品hd| 农村妇女野外一区二区视频 | 99福利一区二区视频| 久久91精品牛牛| 国产女人喷潮视频免费| 国产亚洲精品久久久久久久久| 亚洲精品亚洲人成在线| 国产老熟女视频一区二区| 国产精品天天看天天狠| 欧美人与禽2o2o性论交| 国产强奷在线播放免费| 少妇人妻88久久中文字幕| 老司机亚洲精品一区二区| 国内精品久久久久精免费| 精品国产中文字幕第一页| 午夜大片免费男女爽爽影院| 国产精品人人爽人人做我的可爱| 亚洲香蕉免费有线视频| 美女一区二区三区在线观看视频| 国产精品无码a∨麻豆| 自治县|