最近业务遇到的需求:
需求1. 前端上传excel文件,后端接收文件并读取处理,最后返回处理完成的数据;
需求2. 再次和其他参数一块儿上传,后端完成处理,并生成excel文件并发送邮件到客户留的邮箱。
本文只完成了需求1;
需求2:java springboot使用企业微信公共邮箱发带附件Excel文件的邮件
1. 正常使用element-plus的el-upload
1.1 html
<el-upload
drag
:limit="limitNum"
:auto-upload="false"
:action="UploadUrl()"
:before-upload="beforeUploadFile"
:on-change="fileChange"
:on-exceed="exceedFile"
:on-success="handleSuccess"
:on-error="handleError"
:file-list="fileList"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<template #tip>只能上传xlsx文件,且不超过10M</template>
</el-upload>
<el-button size="small" type="primary" @click="uploadFile">立即上传</el-button>
<el-button size="small">取消</el-button>
1.2 ts
methods: {
//上传from表单
async submitForm() {
if (this.formInline.excelData.length == 0) {
return ElMessage({
message: "请先按照格式上传文件!",
type: "error",
duration: 3 * 1000,
});
} else if (
this.formInline.companyAddress == "" ||
this.formInline.companyName == "" ||
this.formInline.companyEmail == ""
) {
return ElMessage({
message: "请填写公司信息",
type: "error",
duration: 3 * 1000,
});
}
//判断邮箱和公司名称
const res = await post("/scheme/upload-data", this.formInline);
if (res.state) {
console.log(res, res.data);
}
},
// 文件超出个数限制时的钩子
exceedFile(files, fileList) {
ElMessage({
message: `只能选择 ${this.limitNum} 个文件,当前共选择了 ${
files.length + fileList.length
} 个`,
type: "warning",
duration: 5 * 1000,
});
},
// 文件状态改变时的钩子
fileChange(file) {
console.log(file.raw);
let extension = file.name.split(".")[1];
let size = file.size / 1024 / 1024;
if (extension !== "csv" && extension !== "xlsx" && extension !== "xls") {
return ElMessage.warning("只能上传后缀是csv/xlsx/xls的文件");
}
console.log(size);
if (size > 10) {
console.log(this.fileList);
return ElMessage.warning("文件大小不得超过10M");
} else {
this.fileList.push(file.raw);
}
},
// 文件上传成功时的钩子
handleSuccess(res, fileList) {
ElMessage({
message: "文件上传成功,请填写下面参数",
type: "success",
duration: 3 * 1000,
});
},
// 文件上传失败时的钩子
handleError(err, fileList) {
ElMessage({
message: "文件上传失败,请按照格式重新上传文件!",
type: "error",
duration: 3 * 1000,
});
},
UploadUrl() {
// 因为action参数是必填项,我们使用二次确认进行文件上传时,直接填上传文件的url会因为没有参数导致api报404,
// 所以这里将action设置为一个返回为空的方法就行,避免抛错
return "";
},
async uploadFile() {
if (this.fileList.length === 0) {
ElMessage({
message: "请上传文件",
type: "warning",
duration: 3 * 1000,
});
} else {
let form = new FormData();
form.append("file", this.fileList[0]);
console.log(form.get("file"));
await upload({
method: "post",
url: "/scheme/upload",
headers: {
"Content-type": "multipart/form-data",
},
data: form,
}).then(
(res) => {
if (res.state && res.data.length > 0) {
this.handleSuccess(res, this.fileList);
this.formInline.excelData = [];
this.formInline.excelData = res.data;
} else {
this.handleError(res, this.fileList);
this.fileList = [];
}
},
(err) => {
this.handleError(res, this.fileList);
this.fileList = [];
}
);
}
},
},
1.3 api.ts
import axios from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
// const getToken=()=>{
// let url = window.location.href
// let urlStr = url.split('?')[1].split("=")[1];
// return urlStr;
// }
const DEV_BASE_API = "http://localhost:8088";
// const PRO_BASE_API = "";
// create an axios instance
const service = axios.create({
baseURL: DEV_BASE_API, // api 的 base_url
timeout: 60000, // request timeout
withCredentials: true
})
// request interceptor
service.interceptors.request.use(
config => {
// Do something before request is sent
config.headers['tenantId'] = "10001"
// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
config.headers['uni-token'] = ""
config.headers['x-client-type'] = ''
config.withCredentials = true
return config
},
error => {
// Do something with request error
console.warn(error) // for debug
Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
/**
* 下面的注释为通过在response里,自定义code来标示请求状态
* 当code返回如下情况则说明权限有问题,登出并返回到登录页
* 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
* 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
*/
response => {
const res = response.data
if (response.status == 200 && response.config.responseType == 'blob') {
return response
}
if (res.code !== 200 || response.status != 200) {
ElMessage({
message: res.message,
type: 'error',
duration: 5 * 1000
})
// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
if (res.code === 1001 || res.code === 1002 || res.code === 1003 || res.code === 1000) {
// 请自行在引入 MessageBox
// import { Message, MessageBox } from 'element-ui'
ElMessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('LogOut').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug
})
})
}
return Promise.reject('error')
} else {
return response.data
}
},
error => {
console.log(error)
ElMessage({
message: '服务端异常',
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export const post =(url, data) =>{
return service({
url: url,
method: 'post',
data: {
...data
}
})
}
export const get = (url) =>{
return service({
url: url,
method: 'get'
})
}
export const upload = (file)=>{
return service(file)
}
1.4 前端效果
2. java (springboot)
2.1 api
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
// 请原谅我把和公司项目目录的包名删除;
import java.io.*;
import java.lang.reflect.Array;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping(value = "/scheme", name = "上传方案Excel")
public class EmsUploadExcelApi {
private final EmsExcelService excelService;
public EmsUploadExcelApi(EmsExcelService excleService) {
this.excelService = excleService;
}
@ResponseBody
@PostMapping(value = "/upload", name = "上传方案Excel")
public Object upload(@RequestParam("file") MultipartFile multiFile) {
if (multiFile != null) {
List result = null;
File file = null;
try {
file = MultipartFileToFile.multipartFileToFile(multiFile);
ExcelUtil<EmsUploadExcel> excelUtil = new ExcelUtil<>();
List<EmsUploadExcel> models = excelUtil.excelReadForFile(file, null, EmsUploadExcel.class);
// 处理文件
result = this.excelGetPower(models);
//最后删除掉 因为multipartFile-->File而产生的 存在项目根路径下的 缓存文件
MultipartFileToFile.delteTempFile(file);
} catch (Exception e) {
e.printStackTrace();
} finally {
File f = new File(file.toURI());
f.delete();
}
return R.ok().setData(result);
} else {
return R.fail("文件上传错误");
}
}
// 处理excel
public List excelGetPower(List<EmsUploadExcel> emsExcel) throws ParseException {
List result = new ArrayList<>();
for (int i = 0; i < emsExcel.size(); i++) {
String date = emsExcel.get(i).getDate();
if (i == emsExcel.size() - 1) {
if (date == null || "".equals(date + ""))
continue;
}
// 判断空值排除
if (emsExcel.get(i).getPower() == null)
continue;
Double a;
a = emsExcel.get(i).getPower();
JSONObject o = new JSONObject();
o.put("rate", a * emsExcel.get(i).getMultiple());
o.put("date", emsExcel.get(i).getDate());
result.add(o);
}
result = filterExcelData(result);
return result;
}
/*
* 过滤数据
*
* @param list
*
* */
public List filterExcelData(List list) throws ParseException {
List<ArrayList> result = new ArrayList<>(4);
// 过滤数据部分省略
return result;
}
/**
* 通过秒毫秒数判断两个时间的间隔的秒数
* @param date1
* @param date2
* @return
*/
public static boolean differentDaysByMillisecond(Date date1,Date date2,int len)
{
boolean times = Math.abs(date2.getTime() - date1.getTime()) < (len / 4) * 3600*1000 ;
return times;
}
}
2.2 读文件 excelUtil
参考: 真忘记了,CSDN一个大牛写的;如果谁知道请告诉我
import au.com.bytecode.opencsv.CSVReader;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class ExcelUtil<T> {
public static final String CSV_SUFFIX = ".csv";
public static final String XLS_SUFFIX = ".xls";
public static final String XLSX_SUFFIX = ".xlsx";
/**
* 转换特定类型的集合
*
* @param file
* @param requestId
* @param t
* @return
*/
@SuppressWarnings("unchecked")
public List<T> excelRead(MultipartFile file, String requestId, T t) {
List<JSONObject> jsonObjects = transExcelForMultipartFile(file, requestId);
String objs = JSON.toJSONString(jsonObjects);
return (List<T>) JSONObject.parseArray(objs, t.getClass());
}
/**
* 转换特定类型的集合
*
* @param file
* @param requestId
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public List<T> excelReadForFile(File file, String requestId, Class<T> clazz) {
List<JSONObject> jsonObjects = transExcelForFile(file, requestId);
String objs = JSON.toJSONString(jsonObjects);
List a = JSONObject.parseArray(objs,clazz);
return a;
}
/**
* 读取上传Excel文件
*
* @param file
* @param requestId
* @return
*/
private static List<JSONObject> transExcelForMultipartFile(MultipartFile file, String requestId) {
List<JSONObject> resultList = null;
// 获取文件名
String fileName = file.getOriginalFilename();
// 获取文件后缀名,截取.后面的类容
assert fileName != null;
String suffix = fileName.substring(fileName.lastIndexOf("."));
try (InputStream inputStream = file.getInputStream()) {
resultList = transExcel(requestId, inputStream, suffix);
} catch (IOException e) {
log.error("【黑名单导入】导入文件解析异常,requestId:{},message:{}", requestId, e.getMessage());
e.printStackTrace();
}
return resultList;
}
/**
* 读取Excel文件
*
* @param file
* @param requestId
* @return
*/
private static List<JSONObject> transExcelForFile(File file, String requestId) {
List<JSONObject> resultList = null;
// 获取文件名
String fileName = file.getName();
// 获取文件后缀名,截取.后面的类容
String suffix = fileName.substring(fileName.lastIndexOf("."));
try (InputStream inputStream = new FileInputStream(file)) {
resultList = transExcel(requestId, inputStream, suffix);
} catch (IOException e) {
log.error("【黑名单导入】导入文件解析异常,requestId:{},message:{}", requestId, e.getMessage());
}
return resultList;
}
/**
* 根据文件后缀名区分读取Excel表格方法
*
* @param requestId
* @param inputStream
* @param suffix
* @return
*/
private static List<JSONObject> transExcel(String requestId, InputStream inputStream, String suffix) {
List<JSONObject> resultList = null;
if (XLS_SUFFIX.equals(suffix)) {
// .xls文件
resultList = readXlsFile(requestId, inputStream);
} else if (XLSX_SUFFIX.equals(suffix)) {
// .xlsx文件
resultList = readXlsxFile(requestId, inputStream);
} else if (CSV_SUFFIX.equals(suffix)) {
// .csv文件
resultList = readCsvFile(requestId, inputStream);
} else {
// 不支持格式,抛出异常
}
return resultList;
}
/**
* 读取xls文件
*
* @param requestId
* @param in
* @return
*/
private static List<JSONObject> readXlsFile(String requestId, InputStream in) {
List<JSONObject> resultList = new ArrayList<>();
HSSFWorkbook hssfWorkbook;
try {
hssfWorkbook = new HSSFWorkbook(in);
// 获取Excel中所有的sheet
// int sheetNum = hssfWorkbook.getNumberOfSheets();
// 获取导入之前Excel文档中的选中页
int activeSheetIndex = hssfWorkbook.getActiveSheetIndex();
// 获取选中页中的表格数据
HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(activeSheetIndex);
//获取该页有多少行数据
int rowNum = hssfSheet.getLastRowNum();
//处理列名数据、自动转化表格标题名为列名
List<WorkBookTitleVO> WorkBookTitleVOS = analysisWorkBookForXls(hssfSheet);
for (int i = 1; i <= rowNum; i++) {
// 获取第i行数据
HSSFRow hssfRow = hssfSheet.getRow(i);
JSONObject obj = new JSONObject();
int finalI = i;
WorkBookTitleVOS.forEach(vo -> {
// 将所有字段都默认以字符串的格式读取
// hssfRow.getCell(vo.getCellIndex()).setCellType(CellType.STRING);
// obj.put(vo.getColumnName(), hssfRow.getCell(vo.getCellIndex()).toString());
try {
hssfRow.getCell(vo.getCellIndex()).setCellType(CellType.STRING);
obj.put(vo.getColumnName(), hssfRow.getCell(vo.getCellIndex()).toString());
} catch (Exception e) {
log.info("第" + finalI + "行");
e.printStackTrace();
}
});
resultList.add(obj);
}
} catch (IOException e) {
log.error("Xls文件解析异常,requestId:{},message:{}", requestId, e.getMessage());
}
return resultList;
}
/**
* 读取xlsx文件
*
* @param requestId
* @param in
* @return
*/
private static List<JSONObject> readXlsxFile(String requestId, InputStream in) {
List<JSONObject> resultList = new ArrayList<>();
XSSFWorkbook xssfWorkbook = null;
try {
//将InputStream转XLSX对象(即表格对象)
xssfWorkbook = new XSSFWorkbook(in);
// 获取导入之前Excel文档中的选中页
int activeSheetIndex = xssfWorkbook.getActiveSheetIndex();
// 获取选中页中的表格数据
XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(activeSheetIndex);
//获取该页有多少行数据
int rowNum = xssfSheet.getLastRowNum();
//处理列名数据、自动转化表格标题名为列名
List<WorkBookTitleVO> WorkBookTitleVOS = analysisWorkBookForXlsx(xssfSheet);
//遍历列表中的每一行数据,并将之封装为JSONObject对象
for (int i = 1; i <= rowNum; i++) {
// 获取第i行数据
XSSFRow xssfRow = xssfSheet.getRow(i);
JSONObject objx = new JSONObject();
int finalI = i;
WorkBookTitleVOS.forEach(vo -> {
// 将所有字段都默认以字符串的格式读取
try {
xssfRow.getCell(vo.getCellIndex()).setCellType(CellType.STRING);
objx.put(vo.getColumnName(), xssfRow.getCell(vo.getCellIndex()).toString());
} catch (Exception e) {
log.info("第" + finalI + "行无数据");
e.printStackTrace();
}
});
resultList.add(objx);
}
} catch (IOException e) {
log.error("Xlsx文件解析异常,requestId:{},message:{}", requestId, e.getMessage());
}
return resultList;
}
/**
* 读取csv文件
*
* @param requestId
* @param in
* @return
*/
private static List<JSONObject> readCsvFile(String requestId, InputStream in) {
List<JSONObject> resultList = new ArrayList<>();
InputStreamReader reader = new InputStreamReader(in);
CSVReader csvReader = new CSVReader(reader);
List<String[]> list = null;
try {
//将InputStream转XLSX对象(即表格对象)
list = csvReader.readAll();
//处理列名数据、自动转化表格标题名为列名
List<WorkBookTitleVO> WorkBookTitleVOS = analysisWorkBookForCsv(list);
//遍历列表中的每一行数据,并将之封装为JSONObject对象
for (int i = 1; i < list.size(); i++) {
// 获取第i行数据
String[] csvRow = list.get(i);
JSONObject obj = new JSONObject();
WorkBookTitleVOS.forEach(vo -> {
obj.put(vo.getColumnName(), csvRow[vo.getCellIndex()]);
});
resultList.add(obj);
}
} catch (IOException e) {
log.error("Xlsx文件解析异常,requestId:{},message:{}", requestId, e.getMessage());
}
return resultList;
}
/**
* 分析xls文件选中页表格标题栏
*
* @return
*/
private static List<WorkBookTitleVO> analysisWorkBookForXls(HSSFSheet hssfSheet) {
// 获取该页有多少列数据
int cellNum = hssfSheet.getRow(0).getPhysicalNumberOfCells();
// 遍历取出每一列的第一行数据作为标题存入集合中
List<WorkBookTitleVO> titleList = new ArrayList<>();
for (int i = 0; i < cellNum; i++) {
// 取出第一行数据
HSSFRow hssfRow = hssfSheet.getRow(0);
// 存入表格title实体类中
WorkBookTitleVO vo = new WorkBookTitleVO();
vo.setCellIndex(i);
vo.setColumnName(hssfRow.getCell(i).toString() + "");
titleList.add(vo);
}
return titleList;
}
/**
* 分析xlsx文件选中页表格标题栏
*
* @return
*/
private static List<WorkBookTitleVO> analysisWorkBookForXlsx(XSSFSheet xssfSheet) {
// 获取该页有多少列数据
int cellNum = xssfSheet.getRow(0).getPhysicalNumberOfCells();
// 遍历取出每一列的第一行数据作为标题存入集合中
List<WorkBookTitleVO> titleList = new ArrayList<>();
for (int i = 0; i < cellNum; i++) {
// 取出第一行数据
XSSFRow xssfRow = xssfSheet.getRow(0);
// 存入表格title实体类中
WorkBookTitleVO vo = new WorkBookTitleVO();
vo.setCellIndex(i);
vo.setColumnName(xssfRow.getCell(i).toString());
titleList.add(vo);
}
return titleList;
}
/**
* 分析csv文件选中页表格标题栏
*
* @return
*/
private static List<WorkBookTitleVO> analysisWorkBookForCsv(List<String[]> list) {
// 获取该页有多少列数据
int cellNum = list.get(0).length;
// 遍历取出每一列的第一行数据作为标题存入集合中
List<WorkBookTitleVO> titleList = new ArrayList<>();
for (int i = 0; i < cellNum; i++) {
// 取出第一行数据
String[] row = list.get(0);
// 存入表格title实体类中
WorkBookTitleVO vo = new WorkBookTitleVO();
vo.setCellIndex(i);
vo.setColumnName(row[i]);
titleList.add(vo);
}
return titleList;
}
/**
* 生成excel文件
* @param fileName excel文件路径
* @param dataList 数据列表
* @param clazz 导出对象类
* @param <T>
* @return
* @throws IOException
*/
public static <T> File generateExcel(String fileName, List<T> dataList, Class<T> clazz) throws IOException {
// 生成文件
File excel = new File(fileName);
// excel写入
EasyExcel.write(excel,clazz).sheet(0).doWrite(dataList);
return excel;
}
}
2.3 EmsUploadExcel (上传的文件第一行标题必须是date,power,multiple)
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@EqualsAndHashCode
@Data
public class EmsUploadExcel implements Serializable{
@ExcelProperty("日期")
private String date;
@ExcelProperty("瞬时有功")
private Double power;
@ExcelProperty("倍率")
private Integer multiple;
}
如有错误,请指正!
最后如果帮到你了,点个赞