我用的是原生的poi,没有使用easyExcel和hutool,因为是作为学习使用,了解原生代码
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxmlartifactId>
<version>4.1.2version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poiartifactId>
<version>4.1.2version>
dependency>
最主要的是,有时候我们有些业务需要导出表格:
- 比如我需要导出所有的数据,这个时候直接导出,都不需要通过SQL过滤
- 但是如果用户先通过搜索再导出数据呢?所以需要一个表单来控制,当有用户搜索后,点击导出按钮,我们可以将前端搜索框中的表单数据一并通过导出按钮事件传给后端
/**
* 导出操作日志excel导出操作日志excel
* @param pageQuerySysLogOperationModel
* @param response
* @throws IOException
*/
@ApiOperation("导出操作日志excel")
@PostMapping("/export")
public void export(@RequestBody @Valid PageQuerySysLogOperationModel pageQuerySysLogOperationModel, HttpServletResponse response) throws IOException {
List<SysLogOperation> list = sysLogOperationService.selectSysLogOperationList(pageQuerySysLogOperationModel);
// 新建一个工作表
XSSFWorkbook workbook = new XSSFWorkbook();
// 新建一个表单
XSSFSheet sheet = workbook.createSheet("操作日志");
// 第一行,也是标题行
XSSFRow rowTitle = sheet.createRow(0);
rowTitle.createCell(0).setCellValue("操作序号");
rowTitle.createCell(1).setCellValue("操作描述");
rowTitle.createCell(2).setCellValue("请求地址");
rowTitle.createCell(3).setCellValue("请求方式");
rowTitle.createCell(4).setCellValue("请求参数");
rowTitle.createCell(5).setCellValue("请求时长");
rowTitle.createCell(6).setCellValue("操作地址");
rowTitle.createCell(7).setCellValue("操作人员");
rowTitle.createCell(8).setCellValue("状态");
rowTitle.createCell(9).setCellValue("操作时间");
// 数据从第一行开始
int rowNum = 1;
for (SysLogOperation sysLogOperation : list) {
Row row = sheet.createRow(rowNum);
row.createCell(0).setCellValue(sysLogOperation.getId());
row.createCell(1).setCellValue(sysLogOperation.getOperation());
row.createCell(2).setCellValue(sysLogOperation.getRequestUri());
row.createCell(3).setCellValue(sysLogOperation.getRequestMethod());
row.createCell(4).setCellValue(sysLogOperation.getRequestParams());
row.createCell(5).setCellValue(sysLogOperation.getRequestTime());
row.createCell(6).setCellValue(sysLogOperation.getIp());
row.createCell(7).setCellValue(sysLogOperation.getUsername());
row.createCell(8).setCellValue(sysLogOperation.getStatus() == 0 ? "成功":"失败");
row.createCell(9).setCellValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date.from(sysLogOperation.getCreateTime().atZone(ZoneId.systemDefault()).toInstant())));
rowNum++;
}
String fileName = "操作日志_"+ String.valueOf(System.currentTimeMillis()) +".xlsx";
response.setCharacterEncoding("UTF-8");
response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
response.setHeader("Content-Type", "application/vnd.ms-excel");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setCharacterEncoding("UTF-8");
OutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.flush();
outputStream.close();
workbook.close();
}
浏览器下载最主要的一部分代码
String fileName = "操作日志_"+ String.valueOf(System.currentTimeMillis()) +".xlsx";
response.setCharacterEncoding("UTF-8");
response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
response.setHeader("Content-Type", "application/vnd.ms-excel");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setCharacterEncoding("UTF-8");
OutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.flush();
因为前端代码太多了,只整些核心关键代码
<el-button type="primary" @click="handleExport"
>导出<i class="el-icon-top">i
>el-button>
<script>
export default {
methods:{
handleExport() {
this.request
.post("/manager/sys/operation/export", this.queryForm, {
responseType: "blob",
})
.then((res) => {
if (!res.data) {
return;
}
const blob = new Blob([res.data], {
type: "application/vnd.ms-excel",
}); // 构造一个blob对象来处理数据,并设置文件类型
const href = URL.createObjectURL(blob); //创建新的URL表示指定的blob对象
const a = document.createElement("a"); //创建a标签
a.style.display = "none";
a.href = href; // 指定下载链接
let fileName = res.headers["content-disposition"];
fileName = fileName.split("=")[1];
a.download = decodeURIComponent(fileName); //指定下载文件名
a.click(); //触发下载
URL.revokeObjectURL(a.href); //释放URL对象
});
},
}
}
script>
难点在于excel中数据的格式,在转换中可能会报错
public R<String> importData(@RequestParam("file") MultipartFile multipartFile) throws IOException, ParseException {
// 获取io输入流
InputStream inputStream = multipartFile.getInputStream();
// 将输入流读取到workbook中
Workbook workbook = new XSSFWorkbook(inputStream);
for (Sheet sheet : workbook) {
int lastRowNum = sheet.getLastRowNum();
List<SysLogOperation> sysLogOperations = new ArrayList<>();
for (int i = 1; i <= lastRowNum; i++) {
SysLogOperation sysLogOperation = new SysLogOperation();
Row row = sheet.getRow(i);
String operation = row.getCell(1).getStringCellValue();
sysLogOperation.setOperation(operation);
String requestURI = row.getCell(2).getStringCellValue();
sysLogOperation.setRequestUri(requestURI);
String requestMethod = row.getCell(3).getStringCellValue();
sysLogOperation.setRequestMethod(requestMethod);
String requestParams = row.getCell(4).getStringCellValue();
sysLogOperation.setRequestParams(requestParams);
double requestTime = row.getCell(5).getNumericCellValue();
sysLogOperation.setRequestTime((int) requestTime);
String ip = row.getCell(6).getStringCellValue();
sysLogOperation.setIp(ip);
String username = row.getCell(7).getStringCellValue();
sysLogOperation.setUsername(username);
String status = row.getCell(8).toString();
sysLogOperation.setStatus(status.equals("成功")?(short)0:(short)1);
String createTime = row.getCell(9).getStringCellValue();
sysLogOperation.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(createTime).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
sysLogOperations.add(sysLogOperation);
}
Assert.isTrue(sysLogOperationService.saveBatch(sysLogOperations),"添加失败");
}
return R.ok();
}
<el-upload
class="upload-demo"
action="http://localhost:8080/manager/sys/operation/import"
:on-success="handleUploadSuccess"
accep=".xlsx"
:show-file-list="false"
:before-upload="beforeUpload"
style="display: inline-block; margin-right: 10px"
>
<el-button type="primary">导入<i class="el-icon-bottom">i>el-button>
el-upload>
<script>
export default {
methods:{
beforeUpload(file) {
const isLimit = file.size / 1024 / 1024 < 10;
if (file.type.indexOf("application/vnd") === -1) {
this.$message.error("上传的文件格式不对吧,亲!");
return false;
}
if (!isLimit) {
this.$message.error("上传的文件不能大于10M!");
return false;
}
},
handleUploadSuccess(res, file, fileList) {
let formData = new FormData();
formData.append("file", file);
this.$message.success(res.msg);
},
},
}
}
script>
这里有一些配置需要结合ElementUI官方文档
因为我在项目中的日期类型是LocalDateTime类型所以他的值是这样的:2022-09-13T17:09:07
每次中间会有一个‘T’,所以我们可以使用@JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”)把他的格式转换一下
然后就是时间格式的问题可以使用SimpleDateFormat(“这里写格式”)
LocalDateTime 转为Date类型
public static Date localDateTimeToDate(LocalDateTime localDateTime) {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zdt = localDateTime.atZone(zoneId);
Date date = Date.from(zdt.toInstant());
return date;
}
Date类型转换为LocalDateTime
public static LocalDateTime dateToLocalDateTime(Date date) {
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
return localDateTime;
}
在进行文件通过浏览器下载的时候,后端传给前端一个文件名,文件名是中文的,会出现乱码,是如何解决的呢?
后端代码
String fileName = "操作日志_"+ String.valueOf(System.currentTimeMillis()) +".xlsx";
response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(fileName,"UTF-8"));
前端代码:
handleExport() {
this.request
.post("/manager/sys/operation/export", this.queryForm, {
responseType: "blob",
})
.then((res) => {
if (!res.data) {
return;
}
const blob = new Blob([res.data], {
type: "application/vnd.ms-excel",
}); // 构造一个blob对象来处理数据,并设置文件类型
const href = URL.createObjectURL(blob); //创建新的URL表示指定的blob对象
const a = document.createElement("a"); //创建a标签
a.style.display = "none";
a.href = href; // 指定下载链接
let fileName = res.headers["content-disposition"];
fileName = fileName.split("=")[1];
a.download = decodeURIComponent(fileName); //指定下载文件名
a.click(); //触发下载
URL.revokeObjectURL(a.href); //释放URL对象
});
},
后端通过: URLEncoder.encode(fileName,“UTF-8”);
前端通过: decodeURIComponent(fileName);