前言
项目使用的是dva+antd完成文件上传的功能,因为公司代码不能粘贴,就自行写了一个demo。
正文
1、方式一把文件包装在form表单中提交到后端。
关键部分代码逻辑如下:
routes/Products.js
<Modal
title="Basic Modal"
visible={this.props.addVisible}
onOk={this.addaOk.bind(this)}
onCancel={this.handleCancel}
>
<Form layout="inline">
<FormItem>
<Input name='name'
prefix={<Icon type="user" style={{color: 'rgba(0,0,0,.25)'}}/>}
placeholder="Username" onChange={this.onInputChange.bind(this)}
/>
</FormItem>
<FormItem>
<Upload
{...uploadProps}>
<Button>
<Icon type="upload"/>上传头像
</Button>
</Upload>
</FormItem>
</Form>
</Modal>
//antd上传组件Upload的属性
const uploadProps= {
onRemove: (file) => {
this.setState((state) => {
const index = state.fileList.indexOf(file);
const newFileList = state.fileList.slice();
newFileList.splice(index, 1);
return {
fileList: newFileList,
};
});
},
beforeUpload: (file) => {
this.setState(state => ({
fileList: [...state.fileList, file],
}));
return false;
},
};
//发送请求
addaOk() {
let {fileList} = this.state;
let that = this;
let formData = new FormData();
// 批量上传
for(let item of fileList){
formData.append('files', item)
}
// 单个上传
// formData.append('files', fileList[0]);
formData.append("name",this.state.name);
this.props.dispatch({
type:'products/mockAddUser',
payload:formData
});
this.props.dispatch({
type: 'products/changeValue',
payload: {
addVisible: false
}
});
}
在models/Products.js中则主要是通过fetch向后端发送请求,关键部分代码如下:
* mockAddUser({payload},{select,call,put}){
let data = yield call(mockAddUser,payload);
if(data.success){
message.success("新增成功。");
}else{
message.error("新增失败。");
}
}
/**
* 包含文件上传的form表单提交
* @param param
* @returns {Promise<*>}
*/
async function mockAddUser(param) {
return new Promise((resolve,reject) => {
let url = `http://127.0.0.1:8080/user/mockAddUser`;
request(url,{
method: "POST",
// model:"no-cors",
// withCredentials: false,
// headers:{
// credentials: 'same-origin'
// },
body:param
}).then(res=>{
resolve(res.data);
});
})
}
后端使用springboot,代码如下所示:
/**
* 使用form表单提交的数据在后端接收
* @param name
* @param files
* @return
*/
@RequestMapping("/mockAddUser")
public Result uploadWord( @RequestParam("name")String name,@RequestParam("files") MultipartFile[] files){
Result result = new Result();
System.out.println("request name:"+name);
System.out.println("request files:"+files.length);
if(files.length>0){
String originalFilename = files[0].getOriginalFilename();
System.out.println(originalFilename);
}
result.setSuccess(true);
return result;
}
这种方式需要注意的就是,要保证upload组件的beforeUpload方法返回false,这样在选择完成文件后,就不会向后端提交。
方式二:选择完成文件立即上传
前端代码如下所示:
{/* 渲染文件上传组件 */}
<Upload {...this.getPdfURL()} showUploadList={true}>
<Button>
<Icon type="upload"/> 上传文件
</Button>
</Upload>
getPdfURL = () => {
const props = {
name: 'file',
action: 'http://127.0.0.1:8080/user/uploadWord',
// accept:"application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document",
headers: {
authorization: 'authorization-text',
},
// 拦截文件上传
beforeUpload(file) {
return true;
},
//上传文件改变时的状态
onChange(info) {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (info.file.status === 'done') {
message.success(`${info.file.name} 上传成功!`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} 上传失败!`);
}
},
};
return props;
}
后端代码如下所示:
@RequestMapping("/uploadWord")
public Result uploadWord(@RequestParam("file") MultipartFile file){
Result result = new Result();
System.out.println("receive:"+file.getOriginalFilename());
System.out.println("receive:"+file.getSize());
result.setSuccess(true);
return result;
}
需要注意到此时在Upload组件的属性配置中,beforeUpload返回true,在action中配置了后端请求地址。如果需要附加其它参数,可以放在upload组件的data中。
后记
本文记录的,后端发送请求方式是fetch。如果想要通过ajax发送请求,首先需要在react项目中引入jQuery组件(jQuery对ajax有封装)。