前言:
网上有很多使用el-upload上传多个文件的文章,但是百度了一下,要么就是代码贴的不完整,要么就是完全不能使用的。找了一圈,最后竟然找不到一个可用的。所以最后只能选择自己造轮子了。
一:我的方案
1.1 现成的方案:
网上通用的方案是放弃本身的action上传,通过指定http-request方法。这样点击提交后就不会发起action请求。然后通过form表单的方式拼接参数,添加文件然后进行请求。
我尝试了这种方式,发现后台无法正常的接受前端发过来的请求,发过来的请求都是只包含文件名,但是不包含文件内容。所以只能无奈放弃这种方案了。
1.2 我的方案:
我的方案是这样的,支持多文件上传,这样多文件,点击上传的时候会触发多次action请求。
在成功回调里面计数,如果成功的次数等于待上传的个数,那就是成功,否则是失败。
二:实现-VUE部分
首先是布局的部分,就是正常的使用el-upload上传。
<template>
<div class="login-view">
<div class="login-form">
...无用代码略过
<el-form ref="form" label-position="left" :model="form" class="el-form">
<el-form-item label="上传文件:" prop="excelFile">
<el-upload
class="el-upload"
ref="upload"
multiple
:action="this.SERVE_URL + 'upload_img'"
name="excelFile"
drag
:data="upData"
:on-change="onUploadChange"
:file-list="fileList"
:on-error="uploadFalse"
:on-success="uploadSuccess"
:auto-upload="false"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<!-- <el-button slot="trigger" size="small" >选取文件</el-button> -->
</el-upload>
</el-form-item>
</el-form>
<div class="button-view">
<!-- <p>头像: <input type="file" id="files" ref="refFile" multiple="multiple" v-on:change="fileLoad" /></p> -->
<button @click="submitUpload">提交</button>
<button @click="closePage">关闭</button>
</div>
</div>
</div>
</template>
几个参数详细解释下,方便小白理解:
1.multiple代表支持多文件上传,选择了这个选项后,点击提交如果有多个文件,会触发多次action的请求。
2.action是上传的服务器地址接口名。
3.on-change代表选择文件后的回调方法,请注意,不仅仅是选择文件后,上传成功时也会触发这个方法。
4.file-list对应的是文件清单
5.on-success代表上传成功时回调的接口
6.au-upload="false"代表不自动上传
然后是js部分:
<script>
export default {
components: {},
props: {},
data() {
return {
baseUrl: this.SERVE_URL + 'upload_img',
isJump: false,
accountInfo: {},
imageUrl: '',
imageFile: {},
form: {},
fileList: [],//等待上传的集合
uploadSucessList: []//上传成功的集合
}
},
computed: {
upData: function () {
return this.form
}
},
created() {
var accountInfo = this.$route.params
this.accountInfo = accountInfo
},
mounted() {},
methods: {
onUploadChange(file) {
if (file.status != 'ready') {
return
}
this.fileList.push(file)
},
//文件上传成功触发
uploadSuccess(response) {
console.log(response)
if (response.data.status == 200) {
this.uploadSucessList = this.uploadSucessList.concat(response.data.imgList)
if (this.uploadSucessList.length == this.fileList.length) {
this.requestRegister(this.uploadSucessList)
}
} else {
this.$message({
message: '导入失败',
type: 'error'
})
}
},
//文件上传失败触发
uploadFalse() {
this.$message({
message: '文件上传失败!',
type: 'error'
})
},
//表单取消
onCancel() {
this.$refs.form.resetFields()
},
requestRegister(imgUrlList) {
//注册新用户的逻辑
debugger
var that = this
var imgUrl = '';
imgUrlList.forEach(function (img) {
imgUrl = imgUrl + img.imgUrl+";"
})
this.accountInfo.imgUrl = imgUrl
const data = {
accountInfo: JSON.stringify(this.accountInfo)
}
//这里
console.log('account:' + JSON.stringify(data))
//请求登录
this.$apis.user
.requestSet(data)
.then(response => {
debugger
console.log(response.message)
this.$message({
message: response.message
})
setTimeout(() => {
that.$router.go(-1)
}, 1000)
})
.catch(err => {
console.log(err)
})
.finally(() => {
this.showLoading = false
})
},
//表单提交
submitUpload() {
if (this.fileList.length == 0) {
this.requestRegister([])
return
}
//触发组件的action
this.$refs.upload.submit() //主要是这里
},
closePage() {
this.$router.go(-1)
}
}
}
</script>
最后是CSS部分:
<style lang="scss" scoped>
.login-view {
width: 100%;
height: 100%;
box-sizing: border-box;
text-align: center;
// background-color: rgb(51, 51, 51);
background-color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
justify-items: center;
align-items: center;
}
.login-form {
display: flex;
flex-direction: column;
justify-content: left;
justify-items: left;
width: 50%;
border: 1px solid #000;
padding: 50px;
p {
display: flex;
flex-direction: row;
justify-content: left;
label {
width: 100px;
text-align: right;
}
input {
width: 400px;
}
b {
width: 100%;
}
}
.el-form {
padding-left: 30px;
margin-top: 10px;
}
.avatar-uploader el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
}
.button-view {
display: flex;
flex-direction: row;
padding-left: 20%;
padding-right: 20%;
width: 100%;
align-content: flex-start;
justify-content: space-between;
align-items: flex-start;
button {
font-size: 15px;
padding: 10px 30px 10px 30px;
}
}
</style>
三:实现后台部分
后台我使用的是comons-fileupload框架。
核心代码如下,想看完整代码可以直接跳到第四章。
request转换成FileItem对象
public List<FileItem> readAllParams(HttpServletRequest request) throws Exception {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> fileItems = upload.parseRequest(request);
return fileItems;
}
保存图片到本地,并返回生成的链接。(我图片直接放到了项目目录下了)
public JSONObject saveImage(ImageModel imageModel, String realPath) throws Exception {
JSONObject data = new JSONObject();
String path = realPath + "img/";
String url = Config.SERVE_URL_RELEASE + "/img/";
if (realPath.contains("out")) {
//开发环境
path = realPath + "img/";
url = Config.SERVE_URL_DEBUG + "/img/";
}
if (imageModel.fileItems.size() > 0) {
for (ImgFile imgFile : imageModel.fileItems) {
imgFile.imgPath = path + imgFile.imgName;
imgFile.imgUrl = url + imgFile.imgName;
File saveImgFile = new File(imgFile.imgPath);
if (!saveImgFile.getParentFile().exists()) {
saveImgFile.getParentFile().mkdirs();
}
imgFile.fileItem.write(saveImgFile);
}
JSONArray imgList = new JSONArray();
for (ImgFile imgFile : imageModel.fileItems) {
JSONObject imgJson = new JSONObject();
imgJson.put("imgName", imgFile.imgName);
imgJson.put("imgPath", imgFile.imgPath);
imgJson.put("imgUrl", imgFile.imgUrl);
imgList.add(imgJson);
}
data.put("status", 200);
data.put("imgList", imgList);
} else {
data.put("status", 500);
}
return data;
}
四:代码完整链接
项目地址: