使用vue+element-ui+axios+springboot实现文件的上传和下载功能。点击"文件上传"按钮,弹出一个文件上传的弹框,然后在里面操作文件上传。点击"下载",就下载文件,后端将文件转为二进制流传到前端,然后前端使用js-file-download库来接收实现下载。
一、封装axios
先封装一个axios实例,方便以后调用,要用到里面的网络请求方法时,导入就行了。
import axios from 'axios'
function request(config){
// 创建axios的实例
const instance = axios.create({
baseURL: 'http://localhost:8081', // 这个是后端的ip地址
});
return instance(config);
}
export function uploadResult(){ // 上传文件的方法
return axios.create({
withCredentials: true,
});
}
export function getResult(resultfile){
return request({
url: 'comp/getCompResult',
method: 'post',
responseType: 'arraybuffer',
data: {
resultfile
}
});
}
二、上传功能的实现
1. 前端部分
前端上传功能使用element-ui的upload模块来实现上传功能,这里不需要upload默认的上传功能,因此要重写一下上传的函数。为了后端处理方便,前端就限制只能上传一个文件。
el-dialog
visible.sync
用来显示和隐藏对话框,它是一个boolean
类型,设置为true
就是显示对话框,false
就是隐藏对话框
。因此,实现显示和隐藏对话框功能,只需要控制visible.sync
的true
和false
就行了。
close
是对话框关闭的回调,如果用户什么都没做,没有点击上传就关闭对话框的话,应该清空选取的文件。
el-upload
fileList
是用来存储的选取的文件列表,其类型是数组。
auto-upload
是设置是否在选取文件后立即上传,false
则表示选取文件后不上传。
http-request
用来覆盖默认的上传行为,可以自定义上传文件的实现,uploadHttpRequest
是自己自定义的上传文件的方法。
on-change
是文件状态改变时的函数钩子,添加文件、上传成功和上传失败时都会被调用,它默认会传入file
和fileList
两个参数,前者是当前所操作的文件,后者是文件列表。
action
设置为#
,因为我们要重写上传方法,在上传方法里再写接收文件的后端接口地址。
<el-dialog width="400px" top="8vh" title="上传比赛结果" @close="closeUpload" :visible.sync="upload_visible">
<el-upload :file-list="fileList"
:auto-upload="false"
:http-request="uploadHttpRequest"
class="upload-demo"
:on-change="fileChange"
ref="upload"
drag
action="#">
<i class="el-icon-upload"/>
<div class="el-upload__text">将文件拖到此处,或<em>点击选取文件</em></div>
<div slot="tip" class="el-upload__tip">一次只能上传一个文件</div>
</el-upload>
<el-button type="success" @click="submitUpload" style="margin-left: 30px; margin-top: 20px">上传</el-button>
</el-dialog>
上传的样式应该是这样子的:
data
data里面,添加fileList
来存取选取的文件,使用数组来存取。(使用数组来存取可以方便以后选取多个文件时的存取情况)。
data(){
return{
fileList: [],
upload_visible: false // 对话框默认不显示。需要上传时,点击按钮让该值改为true就能显示。
}
},
method
fileChange(file, fileList) {
// 因为是限制为只能上传一个文件,所以前端选取文件时,如果选取第二个文件时,要把第一个文件给覆盖掉。
this.fileList = [fileList[fileList.length - 1]];
// 也可以这样写:
// this.fileList = [file];
},
closeUpload(){
// 当对话框关闭时,清空已上传的文件列表,同时fileList重新设置为空数组
this.$refs.upload.clearFiles(); // 这个是el-upload自带的清空文件列表方法
this.fileList = [];
},
uploadHttpRequest(){
// 检验用户是否未选取文件就上传
if(this.fileList.length === 0){
this.$message.warning('请添加文件');
return
}
const formData = new FormData();
formData.append('file', this.fileList[0].raw); // 要上传的文件
// ${server.url}/comp/uploadResult 这个是后端接收的接口
// withCredentials: true一定要设置,否则可能会上传不成功,这是个坑
uploadResult().post(`${server.url}/comp/uploadResult`, formData).then(res =>{
let {status, msg, data} = res.data;
if(status === 200){
this.$message.success('上传成功');
this.fileList = []; // 上传成功就初始化文件列表
this.upload_visible = false; // 然后关闭对话框
}else{
this.$message.error(msg); // 上传失败就输出失败信息
}
}).catch(err =>{
this.$message.error(err);
});
},
// 自定义上传功能
submitUpload(){
this.$refs.upload.submit(); // 这个会触发upload的http-request,手动上传文件
},
2. 后端部分
JSONResult是我自定义的JSON格式类,用来将后端数据以JSON的格式返回给前端接收。
@RequestMapping("/uploadResult")
public JSONResult upload(@RequestParam("file") MultipartFile file){
String fileName = file.getOriginalFilename(); // 获取文件名
File dest = new File(fileName);
try{
file.transferTo(dest);
}catch(Exception e){
return JSONResult.errorMsg(e.toString()); // 上传失败就返回前端上传失败的信息
}
return JSONResult.ok(); // 上传成功就返回前端上传成功的信息。
}
三、下载功能的实现
下载功能就容易实现了,后端获取文件,然后将文件用二进制流的形式传递给前端接收,前端接收到二进制流后,就用js-file-download
来下载。
1. 下载和导入js-file-download
在vue项目所在的文件目录终端运行:
npm install js-file-download --save
然后导入:
import fileDownload from "js-file-download";
2. 前端部分
downloadResult(resultfile){
getResult(resultfile).then(res =>{
fileDownload(res.data, resultfile); // 使用js-file-download来接收二进制流然后下载
}).catch(err =>{
this.$message.error(err);
});
},
3. 后端部分
@PostMapping("getResult")
public void getCompResult(@RequestBody Map<String, String> map, HttpServletResponse response) throws Exception {
String path = "---"; // 这里的path是文件存储的路径
InputStream inputStream = new FileInputStream(path);
response.reset();
response.setContentType("application/octet-stream");
response.setHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(map.get("resultfile"), "UTF-8"));
ServletOutputStream outputStream = response.getOutputStream();
byte[] b = new byte[1024];
int len;
while((len = inputStream.read(b)) > 0){
outputStream.write(b, 0, len);
}
inputStream.close();
}