文件上传与下载是比较常见的功能,比如上传附件和头像等等,本篇博客主要讲前后端分离的情况下,如何实现文件上传下载,写的是demo,新增文件上传下载的功能,都是在它的基础之上完成的。这里会用到elementUI的组件:
el-upload
一、文件上传:
先看前端代码:
(1)利用el-upload实现文件上传
<el-upload class="upload-demo"
:action="uploadUrl"
:before-upload="handleBeforeUpload"
:on-error="handleUploadError"
:before-remove="beforeRemove"
multiple
:limit="5"
:on-exceed="handleExceed"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
(2)在vue的data里面声明对应的属性和方法
uploadUrl: 'http://192.168.43.152:8089/file/upload',
fileList: [],
第一个是上传的路径,第二个是上传文件的数组
下面是处理文件上传的方法,主要看handleBeforeUpload(file)这个方法,其实方法都是做一些限制和提示:
handleExceed(files, fileList) {
this.$message.warning(`当前限制选择 5 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${ file.name }?`);
},
handleUploadError(error, file) {
console.log("文件上传出错:"+error)
// this.$notify.error({
// title: 'error',
// message: '上传出错:' + error,
// type: 'error',
// position: 'bottom-right'
// })
},
//测试上传文件(注意web的上下文)
handleBeforeUpload(file){
this.uploadUrl = 'http://192.168.43.152:8089/file/upload'
console.log("开始上传,上传的文件为:"+file)
let formData = new FormData();
formData.append("multipartFiles", file);
axios({
method: 'post',
url: 'http://192.168.43.152:8089/file/upload',
data: formData,
headers: {'Content-Type': 'multipart/form-data' }
}).then((res) => {
console.log("文件上传返回:"+res)
}).catch(error => {
console.log("文件上传异常:"+error)
})
// this.uploadUrl ='http://192.168.43.152:8089/file/upload'
},
使用handleBeforeUpload(file)来实现文件上传,主要是因为elementUI的action用不了,我测试的时候是这样,不知道是不是bug
现在看后端代码:
private final static String rootPath = "D:/attachment/";
@RequestMapping("/upload")
public Object uploadFile(MultipartFile[] multipartFiles){
File fileDir = new File(rootPath);
if (!fileDir.exists() && !fileDir.isDirectory()) {
fileDir.mkdirs();
}
try {
if (multipartFiles != null && multipartFiles.length > 0) {
for(int i = 0;i<multipartFiles.length;i++){
try {
//以原来的名称命名,覆盖掉旧的,这里也可以使用UUID之类的方式命名,这里就没有处理了
String storagePath = rootPath+multipartFiles[i].getOriginalFilename();
System.out.println("上传的文件:" + multipartFiles[i].getName() + "," + multipartFiles[i].getContentType() + "," + multipartFiles[i].getOriginalFilename()
+",保存的路径为:" + storagePath);
// 3种方法: 第1种
// Streams.copy(multipartFiles[i].getInputStream(), new FileOutputStream(storagePath), true);
// 第2种
// Path path = Paths.get(storagePath);
// Files.write(path,multipartFiles[i].getBytes());
// 第3种
multipartFiles[i].transferTo(new File(storagePath));
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
//前端可以通过状态码,判断文件是否上传成功
return ResultUtil.result(EnumCode.OK.getValue(),"文件上传成功");
}
后端主要的转换为流写入。
二、文件下载
文件下载,其实用个a标签就可以了,将上传成功的文件名返回给前端就可以了:
<a href="http://192.168.43.152:8089/file/download?fileName=11.xls">下载附件</a>
这里,因为是测试,我就直接写死了文件名
后端代码:
/**
*
* @param fileName 文件名
* @param response
* @return
*/
@RequestMapping("/download")
public Object downloadFile(@RequestParam String fileName, HttpServletResponse response){
OutputStream os = null;
InputStream is= null;
try {
// 取得输出流
os = response.getOutputStream();
// 清空输出流
response.reset();
response.setContentType("application/x-download;charset=utf-8");
//Content-Disposition中指定的类型是文件的扩展名,并且弹出的下载对话框中的文件类型图片是按照文件的扩展名显示的,点保存后,文件以filename的值命名,
// 保存类型以Content中设置的为准。注意:在设置Content-Disposition头字段之前,一定要设置Content-Type头字段。
//把文件名按UTF-8取出,并按ISO8859-1编码,保证弹出窗口中的文件名中文不乱码,中文不要太多,最多支持17个中文,因为header有150个字节限制。
response.setHeader("Content-Disposition", "attachment;filename="+ new String(fileName.getBytes("utf-8"),"ISO8859-1"));
//读取流
File f = new File(rootPath+fileName);
is = new FileInputStream(f);
if (is == null) {
System.out.println("下载附件失败,请检查文件“" + fileName + "”是否存在");
return ResultUtil.result(EnumCode.INTERNAL_SERVER_ERROR.getValue(),"下载附件失败,请检查文件“" + fileName + "”是否存在");
}
//复制
IOUtils.copy(is, response.getOutputStream());
response.getOutputStream().flush();
} catch (IOException e) {
return ResultUtil.result(EnumCode.INTERNAL_SERVER_ERROR.getValue(),"下载附件失败,error:"+e.getMessage());
}
//文件的关闭放在finally中
finally
{
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//其实,这个返回什么都不重要
return ResultUtil.result(EnumCode.OK.getValue(),"下载成功");
}