需求描述: 多个文件上传,展示已上传文件列表, 对已上传文件列表可以勾选进行多文件下载.
原型:
1.后端代码
注意:FileUploadUtils.upload2(filePath, file)很关键
@PostMapping("/upload/file")
@PreAuthorize("@ss.hasPermi('report:upload:file')")
public AjaxResult uploadFile(@RequestParam("file") MultipartFile file)
{
// 获取当前的用户
LoginUser loginUser = SecurityUtils.getLoginUser();
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
// 改造ruoyi基线方法,返回一个map,需要包含现在的本地路径(eg: /home/rms/uploadPath/upload/2022/06/23/中文测试文件_20220623230505A018.docx)
Map<String, String> pathMap = FileUploadUtils.upload2(filePath, file);
// 上传并返回新文件名称
String fileName = pathMap.get("path");
String url = serverConfig.getUrl() + fileName;
//保存文件信息
M06 m06 = new M06();
m06.setName(file.getOriginalFilename());
m06.setUrl(url);
m06.setLocalPath(pathMap.get("localPath"));
// 返回上传文件的信息
return AjaxResult.success(m06);
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
public static final Map<String, String> upload2(String baseDir, MultipartFile file) throws IOException
{
try
{
return upload2(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
}
catch (Exception e)
{
throw new IOException(e.getMessage(), e);
}
}
public static final Map<String, String> upload2(String baseDir, MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException
{
int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
{
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}
assertAllowed(file, allowedExtension);
String fileName = extractFilename(file);
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
file.transferTo(Paths.get(absPath));
Map<String, String> pathMap = new HashMap<>();
pathMap.put("path", getPathFileName(baseDir, fileName));
pathMap.put("localPath", baseDir + "/" + fileName);
return pathMap;
}
/**
* 文件打包下载
* @param response
* @param files
*/
@GetMapping ("/zip")
public void downloadZip(HttpServletResponse response, String files){
LoginUser loginUser = SecurityUtils.getLoginUser();
String zipname=loginUser.getUser().getDept().getDeptName();
String[] filesPsths = Convert.toStrArray(files);
String fileName = zipname + ".zip";
response.setContentType("application/zip");
response.setHeader("content-disposition", "attachment;filename=" + fileName);
ZipOutputStream zos = null;
BufferedInputStream bis = null;
try{
zos = new ZipOutputStream(response.getOutputStream());
byte[] buf = new byte[8192];
int len;
for (int i = 0; i < filesPsths.length; i++) {
File file = new File(filesPsths[i]);
if (!file.isFile()) {
continue;
}
ZipEntry ze = new ZipEntry(file.getName());
zos.putNextEntry(ze);
bis = new BufferedInputStream(new FileInputStream(file));
while ((len = bis.read(buf)) > 0) {
zos.write(buf, 0, len);
}
zos.closeEntry();
}
zos.closeEntry();
}catch(Exception ex){
ex.printStackTrace();
}finally {
if(bis != null){
try{
bis.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(zos != null){
try{
zos.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
2. vue代码
注意:this.$download.zip("/report/zip?files=" + files, zipName);方法
<template>
<div class="app-container">
<div>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-upload
ref="upload"
:before-upload="handleBeforeUpload"
:on-error="handleUploadError"
:on-success="handleUploadSuccess"
:show-file-list="false"
accept=".doc, .docx, .pdf, .xlsx, .xls"
:action="upload.url"
:headers="upload.headers"
:file-list="upload.fileList"
multiple
>
<el-button
type="success"
plain
icon="el-icon-upload"
size="mini"
>上传文件</el-button>
</el-upload>
</el-col>
<el-col :span="1.5">
<div v-cloak>
<el-button
type="warning"
plain
size="mini"
@click="downloadZip"
><svg-icon icon-class="download2" style="margin-right: 5px;"/>下载文件</el-button>
</div>
</el-col>
</el-row>
<el-row :gutter="10" class="mb8" v-if="editEnable">
<el-col>
<div class="el-upload__tip">
请上传
<template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
<template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
的文件
</div>
</el-col>
</el-row>
</div>
<el-table
border
:data="report.reportData"
@selection-change="handleSelectionChange"
style="width: 100%">
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column
align="center"
header-align="center"
type="index"
label="序号">
</el-table-column>
<el-table-column
header-align="center"
prop="name"
label="文件名称">
<template slot-scope="scope">
<el-button type="text" @click="download(scope.row)">{{ scope.row.name }}</el-button>
</template>
</el-table-column>
<el-table-column
align="center"
width="100">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-delete" plain circle @click="del(scope.$index)"></el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
export default {
name: "M06",
dicts: [],
components: { },
props: {
report: {
type: Object
}
},
data() {
return {
// 遮罩层
loading: true,
reportObject: null,
fileSize: 5,
fileType:['doc', 'docx', 'pdf', 'xlsx','xls'],
fileList: [],
multipleSelection: [],
filePaths: [],
editEnable: true,
// 用户导入参数
upload: {
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: "",
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: process.env.VUE_APP_BASE_API + "/report/upload/file"
},
};
},
computed: {
},
created() {
},
methods: {
// 上传前校检格式和大小
handleBeforeUpload(file) {
// 校检文件类型
if (this.fileType) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
const isTypeOk = this.fileType.some((type) => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
if (!isTypeOk) {
this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
return false;
}
}
// 校检文件大小
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
return false;
}
}
return true;
},
// 上传成功回调
handleUploadSuccess(res, file) {
if(res.code === 500) {
this.$message.error(res.msg);
} else {
console.log(res.data)
this.report.reportData.push(res.data);
}
//this.$refs.upload.clearFiles(); //上传成功之后清除历史记录
},
// 上传失败
handleUploadError(err) {
this.$message.error("上传失败, 请重试");
},
del(index) {
this.report.reportData.splice(index, 1);
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
download(file) {
let name = file.name;
let url = file.url;
let suffix = url.substring(url.lastIndexOf("."), url.length);
const a = document.createElement('a')
a.setAttribute('download', name + suffix)
a.setAttribute('target', '_blank')
a.setAttribute('href', url)
a.click()
},
downloadZip() {
if (this.multipleSelection.length < 1) {
this.$message.warning("请选择要下载的文件!");
} else {
let files = this.multipleSelection.map(item => {
return item.localPath;
});
let zipName = this.$store.state.user.dept.deptName;
this.$download.zip("/report/zip?files=" + files, zipName);
}
}
}
};
</script>
<style scoped>
</style>
3. 验证
撒花~~~