本は、背面に接続し、このような複雑なフィールド、ファイル、アップロード画像など未解決の問題を、持っている「と同じボックスを使用して、新しい爆弾」の話を聞いた、これはファイルのアップロードの問題を解決します。ここで写真をアップロードするための新しいポップアップボックス、およびフォームでは、インターフェイスに提出する他のテキストフィールドにアップロードコンポーネントでのシーンがあります。
ここで注意すべきいくつかの問題があります。
- ときに画像が指定したディレクトリにアップロードの種類に応じて、指定されたタイプのフロントエンドで最高の画像をアップロードします。例えば、ここで新しいユーザーは、ユーザーは、アップロード/ユーザー、サーバー上のディレクトリにファイルをアップロード入れ、指定されたタイプ「ユーザー」であるので、ここで、写真をアップロードします。だから、簡単に後のメンテナンスに、別のサーバーへの統一の動き限り、アップロードディレクトリなどのプロジェクト文書はうまく出てコピーする必要があります。
- アップロードコンポーネントは、アップロードが完了した後、バックパス情報の前端部に、汎用的なフォームを使用してデザインに、新しいインタフェースに提出する形式でデータを一致させるために、このパスを取ることによるものです。
ファイルをアップロードするには1.バックエンドインターフェース
1.1 multer
以前に新しいデータを書き込む際に使用され、要求データは、ミドルウェアbodyParserをクライアント要求を解析し、JSON型は、データを受け入れるために使用された場合、これは非常に便利です、が、アップロードファイルが、これは一般的にマルチパート/フォームデータである場合種類は、bodyParserこのタイプは解決することはできません。その後、別のミドルウェアは、本明細書に組み込まmulter。プロのフォームデータのマルチパート/フォームのデータ型を、専門multer。
、その上にアップロードパスで直接DESTを指定するだけで、一般的なWebアプリケーション、場合multerは、2つの方法で使用します。より多くの制御時にアップロードする場合は、ストレージオプションを使用することができます。ここで私は、ファイルをアップロードするファイルを指定するには、単純な、ダイレクトパスからスタート。
// 指定されたファイルアップロードパス VARアップロード= multer({DEST:path.join(__ DIRNAME、 './../public/upload/tmp')})。
パス内のNode.jsに、このモジュールを使用して、相対パスは、ローカルコンピュータのパスに変換./../public/upload/tmpます、我々は公共のディレクトリにアップロード/ tmpディレクトリを建てた場所に注意を払うには、用として、プロジェクトを表現しますこの一時ファイルtmpフォルダが何であるかを、読むことを続けてください。
次に、インターフェイスの定義をアップロードします。
router.post( '/ singleFile'、upload.single( 'ファイル')、関数(REQ、RES、次){ })
ここでは、API /ベース/ singleFileインタフェースを定義し、指定したファイルのフォームタグでアップロードされたファイルを受け入れ、あなたは、公共/アップロード/ tmpディレクトリの下に、この定義の後にファイルにアップロードすることができます。
1.2指定したアップロードディレクトリ
この指定multer道をアップロードするパスは良いスタートが、そのディレクトリは、変数にすることはできません、背後にこのディレクトリにアップロードし、指定され、その後、どのようにそれにディレクトリのアップロード画像を指定されたパラメータに応じて、先端上を通過することができますか?私はここで、「カット」ファイルで最初に考えました。ファイル上のNode.jsは、APIのファイル操作を使用して、最終的にカットして以来。テキストフィールドのデータ、このreq.bodyでは、これとbodyParserが類似している場合は、公式文書の指示がありますが、ファイルに加えて、コールバック関数は、あなたはまた、req.body持つことができます。
app.post( '/プロフィール'、upload.single( 'アバター')、関数(REQ、RES、次へ){ // req.file `avatar`情報ファイル // テキストフィールドを有するreq.bodyデータ、存在する場合、 })
req.body 2つのオブジェクトがNode.jsのに残りの作業の後に次のようにreq.fileでは、コードは次のとおりです。
// 文件上传 router.post( '/ singleFile'、upload.single( 'ファイル')、関数(REQ、RES、次){ 場合(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 => { 場合(ERR ){ res.json(result.createResult(偽、{メッセージ:err.message})) } 他{ せfileNameに = newName.split( '\\' ).pop() res.json(result.createResult(真、{パス:req.body.fileLocation} {$ `/` $ {fileNameに}})) } }) } 他{ res.json(result.createResult(falseに、{メッセージ: 'ファイルのパスが指定されていません' })) } })
ここでは、モジュールfsのリネーム方法の使用は、このメソッドは、ファイルを変更し、ファイルパスの名前を変更することもできますが、ファイルがカットされます。ここで交換するtmpディレクトリの方法はfileLocalhost以上のフロントエンドパスに置き換え、その後、ディレクトリのFileLocationにファイルを移動しています。実装プロセスに関するデバッグトラックに次の郵便配達を使用します。
郵便配達の要求:
tmpディレクトリにアップロード:
指定したユーザーディレクトリに移動:
郵便配達員が返されました:
この時点で、インタフェースは以下を前面にこのインターフェースを呼び出している、書かれていました。
2.フォームコール・インタフェースのフロントエンド
2.1定義フィールドタイプ
最後に実際のフルスタックを反応+のNode.js -オープニング、均一なデータの使用は、データを追加するコンポーネントを追加します。明らかに、ここでプロパティの型と相まって、現実的ではない、テキストボックスが、指定されていないフィールドタイプはcolumns.js:ファイルには、データ・コンポーネントが追加されたファイルアップロードコンポーネントには、このフィールドの対応を表しています。また、場合、あなたはまた、受け入れるサイズフィールドを追加することができ、ファイルの種類、サイズに制限があります。コードは以下の通りであります:
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里面,体验会更好