项目中经常会涉及到,需要导入数据表单和图片的组合需求时;采用表格嵌入图片的方式,需要考验业务人员的插入方式方法,服务器接收的准确度就会受到影响。
此文档提供另一个操作较为简单的方法,将文件和图片放置在一个文件夹内,全选后上传:
例如:
前端代码
<el-upload
:show-file-list="false"
:multiple="true"
:limit="20"
:auto-upload="true"
:on-change="filechange"
:http-request="customRequest"
ref="uploadRef">
<el-button type="primary" plain>导入</el-button>
</el-upload>
//存放选中的文件
const fileList = ref<Array<UploadFile>>([])
//upload组件
const uploadRef = ref<any>(null)
//监听upload组件在文件状态变化时的钩子函数
//主要是将监听到的文件存入fileList (去重了)
const filechange = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
if (fileList.value.length == 0) {
fileList.value.push(uploadFile)
}
let contain = false
for (const key in fileList.value) {
const element = fileList.value[key]
if (element.name === uploadFile.name && element.size === uploadFile.size) {
contain = true
}
}
if (!contain) {
fileList.value.push(uploadFile)
}
//删除upload组件上文件的缓存
uploadRef.value.handleRemove(uploadFile, uploadFiles)
}
//自定义的上传请求
const customRequest = (options: UploadRequestOptions) => {
if (fileList.value.length > 0) {
//http 请求
submit()
//每次上传之后将文件清空,多个文件上传时,upload组件会多次调用customRequest方法,如果不清空会导致文件多次上传
fileList.value = []
}
}
//上传,uploadFiles是用axios实现的文件上传,函数定义往下看
const submit = () => {
//fileList是UploadFile数组,真正上传时不需要他,而是uploadFile.raw
const files = fileList.value.map(uploadFile => uploadFile.raw)
uploadFiles(files)
}
const uploadFiles = (option: Array<File>) => {
console.log('set', option)
//浏览器对于文件上传默认会将文件拆分,分多次http请求服务器,
//如果想要一次上传所有的文件,需要借助FormData对象,
//同时此对象可以添加其他的参数,
const formData = new FormData()
option.forEach(file => {
console.log(file)
formData.append('files', file)
})
return upload({
baseURL: 'http://192.168.3.6:8000',
url: '/logistics/order/management/imports',
formData
})
}
//axios请求
const upload = (option: any) => {
return axios.post(option.url, option.formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
baseURL: option.baseURL
})
}
后端代码
获取到批量文件开始分类
public void exports(MultipartFile[] files) {
//此时jvm的使用情况
System.out.println("此时jvm的使用情况" + Runtime.getRuntime().freeMemory());
List<String> urls = new ArrayList<>();
for (MultipartFile file : files) {
String originalFilename = file.getOriginalFilename();
// 判断是excel文件还是图片文件
if (originalFilename.endsWith(".xlsx")) {
// 读取Excel文件
processExcelFile(file);
} else if (originalFilename.endsWith(".jpg") || originalFilename.endsWith(".png")) {
// 处理图片文件
processImageFile(file, urls);
}
System.out.println(urls);
}
System.out.println(urls);
}
读取文本表单后 存储
private void processExcelFile(MultipartFile file) {
ExcelUtils.readAnalysis(file, LogisticsOrderExcelVO.class, new ExcelFinishCallBack<LogisticsOrderExcelVO>() {
@Override
public void doAfterAllAnalysed(List<LogisticsOrderExcelVO> result) {
saveData(result);
}
@Override
public void doSaveBatch(List<LogisticsOrderExcelVO> result) {
saveData(result);
}
private void saveData(List<LogisticsOrderExcelVO> result) {
if (CollectionUtils.isEmpty(result)) {
return;
}
System.out.println("正常存储excel数据");
// 此处添加实际保存逻辑
}
});
}
读取到图片上传 存储
private void processImageFile(MultipartFile file, List<String> urls) {
try {
System.out.println("文件的全名称: " + file.getOriginalFilename());
// 假设storageFeign.upload是一个阻塞调用,可能导致内存消耗
StorageDTO upload = storageFeign.upload(file);
urls.add(upload.getUrl());
} catch (IOException e) {
System.out.println("上传图片失败: " + e.getMessage());
}
}
业务逻辑完善
由于图片与表单中的数据需要根据实际业务找到唯一关键字 对应 图片地址 再根据唯一关键字 存入数据库对应字段;( 例如 人员身份证号作为唯一值,那么照片就应该命名为人员的身份证号 )
注意事项
文件导入会根据文件大小影响到程序运行 ,需要根据服务器情况 jar包运行情况来给业务人员提供 所选批量文件的总大小。