注意!!!!!!!!该方法在多图的情况下并不实用!!!更方便的方法请转移至该链接☞https://blog.csdn.net/DRNB666/article/details/120362318?spm=1001.2014.3001.5501
需求:前端需要上传多张图片文件,所以用的是el-upload的上传组件,稍微改了一下组件。
思路:前端使用FormData,将每个file存到一个数组里面,然后以文件数组的形式一次性请求到服务,后端使用MultipartFile[]数组类型进行接收,然后保存到本地。
效果:
以下是前端代码:
<template>
<!-- 图片上传(支持多图) -->
<div>
<main-head> </main-head>
<main-content>
<el-row :gutter="20">
<el-col :span="4">
<span style="font-size: 10px">宝贝卡片背景图</span>
<el-image :src="src" />
</el-col>
<el-col :span="12">
<el-upload
class="upload-demo"
ref="upload"
action="string"
accept="image/jpeg,image/png,image/jpg"
list-type="picture-card"
:before-upload="onBeforeUploadImage"
:on-change="fileChange"
:on-remove="removeFile"
:file-list="fileList"
:auto-upload="false"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">
只能上传jpg/jpeg/png文件,且不超过500kb
</div>
</el-upload>
<el-button type="primary" plain @click="sumbit()">上传</el-button>
</el-col>
</el-row>
</main-content>
</div>
</template>
<script>
export default {
data() {
return {
//文件数组
fileArr: [],
//页面显示的图片文件数组
fileList: [],
src: "https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg",
};
},
methods: {
//上传之前的钩子,自定义上传后,该钩子失效
onBeforeUploadImage(file) {},
//文件改变钩子
fileChange(file, fileList) {
if (this.fileArr.length > 0) {
//写的是多图上传,但是这个模块只用到了单图,所以加个判断,多图的可以留着后面用
this.$message.error("当前背景图只支持单张上传");
fileList = fileList.pop();
return;
}
const isIMAGE = file.type === "image/jpeg" || "image/jpg" || "image/png";
const isLt1M = file.size / 1024 / 1024 < 1;
if (!isIMAGE) {
this.$message.error("上传文件只能是图片格式!");
}
if (!isLt1M) {
this.$message.error("上传文件大小不能超过 1MB!");
}
//将文件存到数组中
this.fileArr.push(file.raw);
},
//提交事件
sumbit() {
const formData = new FormData();
//这一步要特别注意!!!如果直接formData.append("files",this.fileArr),那么后端将会收不到参数,一定一定要遍历这个数组然后一个个重新append formdata中
for (var i = 0; i < this.fileArr.length; i++) {
formData.append("files",this.fileArr[i]);
}
this.$request.post({
url: "system/params/bannerUpdate",
params: formData,
success: (result) => {},
finally: () => {},
});
},
//移除文件的钩子
removeFile(file, fileList) {
for (var i = 0; i < this.fileArr.length; i++) {
//如果传入的文件uid和即将提交的图片数组中的某个uid一致,那么移除此图片
if (file.raw.uid == this.fileArr[i].uid) {
this.fileArr.splice(this.fileArr[i], 1);
}
}
},
},
};
</script>
<style>
</style>
后端代码:
controller层
@ApiOperation("背景图片更换")
@PostMapping("bannerUpdate")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "query", dataTypeClass = Long.class, name = "id", value = "id", required = false),
})
public String bannerUpdate(MultipartFile[] files) throws IOException {
//保存图片文件到本地并返回相对路径
List<String> image = FileUtil.uploads("/planCat_file/", files, "image");
//拿着图片路径存储到数据库或者做其他处理,这里就先不多写了,自行发挥
return ReturnBody.success();
}
工具类方法
package com.mmx.baseservice.common.utils;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class FileUtil {
private static JSONObject typeObj;
private static String BASE_PATH = "/files";
/**
* 上传单个文件
* @param relativePath 相对路径
* @param file 文件
* @param fileType 文件类型
* @return 文件路径
*/
public static String upload(String relativePath, MultipartFile file, String fileType, HttpServletRequest request) {
relativePath = BASE_PATH + relativePath;
String basePath = PathUtil.getFullRealPath(request) + relativePath;
File dir = new File(basePath);
if (!dir.exists()) {
dir.mkdirs();
}
String fileName;
if (!file.isEmpty()) {
try {
String name = file.getOriginalFilename();
fileName = checkFile(name, fileType);
//判断文件类型并返回文件名
if (fileName != null) {
File realFile = new File(basePath + fileName);
file.transferTo(realFile);
} else {
return null;
}
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
return null;
}
return relativePath + fileName;
} else {
return null;
}
}
/**
* 上传多个文件
*
* @param relativePath 相对路径
* @param files 文件
* @return 完整路径名列表
*/
public static List<String> uploads(String relativePath, MultipartFile[] files, String fileType) {
String basePath = PathUtil.getFullRealPath() + relativePath;
List<String> list = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
if (!files[i].isEmpty()) {
try {
String name = files[i].getOriginalFilename(); //获取原文件名
String fileName = checkFile(name, fileType); //获取新文件名
//判断文件类型并返回文件名
if (fileName != null) {
File realFile = new File(basePath + fileName);
files[i].transferTo(realFile);
list.add(relativePath + fileName);
} else {
return null;
}
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
}
} else {
return null;
}
}
return list;
}
/**
* 单文件删除
* @param fileName 文件名
* @return 返回boolean 删除成功或失败
*/
public static boolean delete(String fileName) {
String basePath = PathUtil.getFullRealPath() + fileName;
LogUtil.info("删除单个文件,路径:{}", basePath);
File file = new File(basePath);
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
LogUtil.info("删除单个文件" + fileName + "成功!");
return true;
} else {
LogUtil.info("删除单个文件" + fileName + "失败!");
return false;
}
} else {
LogUtil.info("删除单个文件失败:" + fileName + "不存在!");
return false;
}
}
/**
* 判断是否为允许的上传文件类型
*
* @return null或文件名
*/
public static String checkFile(String fileName, String type) {
if (typeObj == null) {
typeObj = new JSONObject();
typeObj.put("image", "jpg,gif,png,ico,bmp,jpeg");
typeObj.put("file", "txt,doc,docx,xlsx,xls,pdf,jpg,gif,png,ico,bmp,jpeg");
}
String suffixList = (String) typeObj.get(type);
// 获取文件后缀
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
if (suffixList.contains(suffix.trim().toLowerCase())) {
return UUIDUtil.getCode() + "." + suffix.trim().toLowerCase();
}
return null;
}
/**
* 下载
*
* @param request 文件名(相对路径)
* @param response
* @return
*/
public static boolean downloadFile(HttpServletRequest request, HttpServletResponse response) {
String fileName = request.getParameter("fileName");
if (fileName != null) {
File file = new File(PathUtil.getFullRealPath(), fileName);
if (file.exists()) {
response.setContentType("application/force-download");// 设置强制下载不打开
response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名
byte[] buffer = new byte[1024];
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
OutputStream os = response.getOutputStream();
int i = bis.read(buffer);
while (i != -1) {
os.write(buffer, 0, i);
i = bis.read(buffer);
}
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} else {
return false;
}
} else {
return false;
}
return true;
}
/**
* FileWriter类文件写入
*
* @throws IOException
*/
public static void writeFile(String fileName, List<String> fileContent) throws IOException {
FileWriter fileWriter = null;
try {
//使用这个构造函数时,如果存在fileName文件,
//则先把这个文件给删除掉,然后创建新的fileName
fileWriter = new FileWriter(fileName);
for (int i = 0; i < fileContent.size(); i++) {
fileWriter.write(fileContent.get(i) + "\n");
}
} finally {
try {
if (fileWriter != null) {
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
*File转MultipartFile
*/
public static MultipartFile createFileItem(File file) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item = factory.createItem("textField", "text/plain", true, file.getName());
int bytesRead = 0;
byte[] buffer = new byte[8192];
try {
FileInputStream fis = new FileInputStream(file);
OutputStream os = item.getOutputStream();
while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
return new CommonsMultipartFile(item);
}
}
总结:
1、前端方面需要注意每次图片删除的时候,记得把对应的需要上传到后台的file数组中的图片元素也删除掉,因为前端图片上的删除只是删除fileList这个显示在页面的数组图片
2、上传formdata的时候,文件数组不能直接append到表单里面,需要遍历后一个一个append到一个属性里面,不然后端会报空指针