前后端分离有时候需要实现文件的上传与下载。现使用React与Springboot做一个简单的文件上传Demo
搭建一个最简单的基于springboot的app:myservice,过程不再赘述
创建一个简单的controller,用于与前台交流:
package com.example.myservice.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/file") public class FileController { @RequestMapping(value = "/test", method = RequestMethod.GET) public String test() { return "hello, this file controller"; } }
启动springboot之后,直接在浏览器中get一下,看看是否通了
表示运行成功。
搭建一个简单的基于React的app,现在借助我现有的React-Typescript框架进行试验
import React from "react"; function MainApp(props: any) { return <div>hello, world!</div> } export default MainApp;
简单的页面代码。
页面运行成功。
OK,基本的脚手架搭完,现在就看如何实现。
实现文件上传:
前端考虑使用伪表单进行上传,上传文件希望同时上传一些其他的数据。
理想中的文件结构:
{
param1: any;
param2: any;
...
file: File;
}
根据上述结构,编写上传组件雏形
function FileUpload(props: any) { return <div> <input type="file" /> </div> } function MainApp(props: any) { return <FileUpload /> }
页面上面已经可以显示一个上传文件的按钮,并且有文件上传动作交互了。但是文件路径暂存于浏览器中,并没有放到后台。
如何获取到文件数据呢?有人建议使用id与getElementById。既然这里用了React,为何不尝试使用ref引用组件呢?
function FileUpload(props: any) { const inputRef = React.useRef<any>(); return <div> <input ref={inputRef} type="file" /> {/** 加一个小button测试引用 */} <button onClick={function () { console.log(inputRef.current) }}>log the ref</button> </div> } function MainApp(props: any) { return <FileUpload /> }
点击后面的button,查看控制台打印的对象:
inputref成功到了对象。
下一步的问题就是如何获取文件。这里上传一个文件,然后针对ref进行打印操作,试着获取各种值:
可见value存储了文件路径,files存储着文件内容
通过实验发现,执行inputRef.current.value = "" 可以清空文件列表,也就是直接对element对象的value空字符串赋值可以清空文件
这里验证一下上面所说的:
import React from "react"; function FileUpload(props: any) { return <div> <input type="file" onChange={function (event: React.ChangeEvent<HTMLInputElement>) { console.log(event.target.value); console.log(event.target.files); }} /> </div> } function MainApp(props: any) { return <FileUpload /> } export default MainApp;
结果正确。下面进行文件数据保存的操作
前台代码:(使用Axios的异步交互框架进行发送数据)
import Axios from "axios"; import React from "react"; function FileUpload(props: any) { const inputRef = React.useRef<any>(); const [uploadData, setUploadData] = React.useState<any>(); function handleChange(event: React.ChangeEvent<HTMLInputElement>) { // 将文件的第一个保存到uploadData中 // 仅考虑单文件上传,多文件上传原理差不多 if (event.target.files) { var newUploadData = new FormData(); newUploadData.append("fileInfo", "some file's info"); newUploadData.append("file", event.target.files[0]); setUploadData(newUploadData); } } function handleUpload() { uploadData && Axios.post("http://localhost:8080/file/upload", uploadData, { headers: { "Content-Type": "multipart/form-data" } }).then(function (response: any) { console.log(response.data); }).catch(function (error: any) { console.log(error.response); }) } function handleClean() { setUploadData(undefined); inputRef.current && (inputRef.current.value = ""); } return <div> <input ref={inputRef} type="file" onChange={handleChange} /> <button onClick={handleUpload}>upload</button> <button onClick={handleClean}>clean</button> </div> } function MainApp(props: any) { return <FileUpload /> } export default MainApp;
后台代码:
简单的Dto:
package com.example.myservice.dto; import org.springframework.web.multipart.MultipartFile; import lombok.Data;
// lombok注解,可以省略写getter, setter方法的步骤 @Data public class FileUploadDto { private String fileInfo; private MultipartFile file; }
Controller:
package com.example.myservice.controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.example.myservice.dto.FileUploadDto; @RestController @CrossOrigin("*") @RequestMapping("/file") public class FileController { @RequestMapping(value = "/test", method = RequestMethod.GET) public String test() { return "hello, this file controller"; } @RequestMapping(value = "/upload", method = RequestMethod.POST, produces = "multipart/form-data") public String upload(FileUploadDto dto) { System.out.println("fileInfo: " + dto.getFileInfo()); System.out.println("fileSize: " + dto.getFile().getSize()); return "upload successfully!"; } }
上传文件运行截图:
后台log:
项目结束。
由于水平有限,文中难免有错误遗漏之处,请大家多多指正批评。