From 37c0639dc89d574cb64b6a06d52ce277e32c79a9 Mon Sep 17 00:00:00 2001 From: Derran Date: Wed, 4 Dec 2024 17:33:59 +0800 Subject: [PATCH] easy exlsx --- dating-agency-mall-server/pom.xml | 6 + .../user/DownloadUserCommandController.java | 35 ++++ .../service/download/DownloadService.java | 76 ++++++++ .../easyexcel/EasyExcelUtil.java | 123 +++++++++++++ .../converter/CustomBigDecimalConverter.java | 67 +++++++ .../converter/CustomImageConverter.java | 90 +++++++++ .../converter/CustomLongConverter.java | 64 +++++++ .../converter/CustomerLocalDateConverter.java | 69 +++++++ .../CustomerLocalDateTimeConverter.java | 69 +++++++ .../easyexcel/handler/ImageModifyHandler.java | 94 ++++++++++ .../easyexcel/listener/ExportListener.java | 172 ++++++++++++++++++ .../src/main/resources/application.yml | 5 +- 12 files changed, 869 insertions(+), 1 deletion(-) create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/api/query/download/user/DownloadUserCommandController.java create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/download/DownloadService.java create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/EasyExcelUtil.java create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomBigDecimalConverter.java create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomImageConverter.java create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomLongConverter.java create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateConverter.java create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateTimeConverter.java create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/handler/ImageModifyHandler.java create mode 100644 dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/listener/ExportListener.java diff --git a/dating-agency-mall-server/pom.xml b/dating-agency-mall-server/pom.xml index 5507d12..d5dae71 100644 --- a/dating-agency-mall-server/pom.xml +++ b/dating-agency-mall-server/pom.xml @@ -107,6 +107,12 @@ auto_1479188381469-20191226 1.0.0 + + + com.alibaba + easyexcel + 3.0.0-beta3 + diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/api/query/download/user/DownloadUserCommandController.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/api/query/download/user/DownloadUserCommandController.java new file mode 100644 index 0000000..c6f6b71 --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/api/query/download/user/DownloadUserCommandController.java @@ -0,0 +1,35 @@ +package com.qniao.dam.api.query.download.user; + +import com.qniao.dam.application.service.download.DownloadService; +import com.qniao.framework.annotation.IgnoreResponseAdvice; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; + +/** + * @author Zpj + * @date 2022/7/15 + */ +@Api(tags = "下载") +@RequestMapping("user") +@RestController +public class DownloadUserCommandController { + + @Resource + private DownloadService downloadService; + + @ApiOperation("用户下载临时生成的导出文件") + @IgnoreResponseAdvice + @GetMapping("/download/temp/{fileName}") + public void userDownloadTempFile(@ApiParam("文件名") @PathVariable String fileName, + HttpServletResponse response) { + downloadService.downloadTempFile(fileName, response); + } +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/download/DownloadService.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/download/DownloadService.java new file mode 100644 index 0000000..1133a39 --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/download/DownloadService.java @@ -0,0 +1,76 @@ +package com.qniao.dam.application.service.download; + +import com.qniao.framework.exception.BizException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URLEncoder; + +/** + * @author Zpj + * @date 2022/2/18 + */ +@Service +@Slf4j +public class DownloadService { + + @Value("${server-file-path}") + private String serverFilePath; + + /** + * 下载临时文件 + * + * @param fileName 文件名 + * @param response 响应 + */ + public void downloadTempFile(String fileName, HttpServletResponse response) { + File f = new File(serverFilePath + "/temp/" + fileName); + + ServletOutputStream out = null; + FileInputStream is = null; + try { + is = new FileInputStream(f); + byte[] b = new byte[is.available()]; + is.read(b); + + //解决中文文件名下载后乱码的问题 + String fName = URLEncoder.encode(fileName, "utf-8"); + + response.setContentType("application/octet-stream"); + response.setCharacterEncoding("utf-8"); + response.setHeader("Content-Disposition", "attachment; filename=" + fName + ""); + //获取响应报文输出流对象 + out = response.getOutputStream(); + out.write(b); + out.flush(); + } catch (IOException e) { + throw new BizException(-1, "未知错误:" + e.getLocalizedMessage()); + } finally { + //删除临时文件 + if (f.exists()) { + f.delete(); + } + + if (out != null) { + try { + out.close(); + } catch (IOException eOut) { + log.error("输出流关闭异常", eOut); + } + } + if (is != null) { + try { + is.close(); + } catch (IOException eIs) { + log.error("输入流关闭异常", eIs); + } + } + } + } +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/EasyExcelUtil.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/EasyExcelUtil.java new file mode 100644 index 0000000..9eeeceb --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/EasyExcelUtil.java @@ -0,0 +1,123 @@ +package com.qniao.dam.infrastructure.easyexcel; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.qniao.dam.infrastructure.easyexcel.converter.CustomBigDecimalConverter; +import com.qniao.dam.infrastructure.easyexcel.converter.CustomLongConverter; +import com.qniao.dam.infrastructure.easyexcel.converter.CustomerLocalDateConverter; +import com.qniao.dam.infrastructure.easyexcel.converter.CustomerLocalDateTimeConverter; +import com.qniao.dam.infrastructure.easyexcel.handler.ImageModifyHandler; +import com.qniao.framework.exception.BizException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Lzk + * @date 2022/12/08 + */ +@Component +public class EasyExcelUtil { + + @Value("${server-file-path:/}") + private String sFilePath; + + public String writeToFilePath(InputStream templateFileInputStream, Object data) { + String finalXlsxPath = sFilePath + "/temp/"; + File file = new File(finalXlsxPath); + if (!file.exists()) { + if (!file.mkdir()) { + throw new BizException("文件目录生成失败"); + } + } + String fileName; + long timeMillis = System.currentTimeMillis(); + fileName = timeMillis + ".xlsx"; + finalXlsxPath += fileName; + ExcelWriter excelWriter = EasyExcel.write(finalXlsxPath) + .registerConverter(new CustomBigDecimalConverter()) + .registerConverter(new CustomLongConverter()) + .registerConverter(new CustomerLocalDateTimeConverter()) + .registerConverter(new CustomerLocalDateConverter()) + .withTemplate(templateFileInputStream) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + excelWriter.fill(data, writeSheet); + excelWriter.finish(); + // 返回下载相对路径 + return fileName; + } + + public String exportTemplate(InputStream templateFileInputStream, List data) { + String finalXlsxPath = sFilePath + "/temp/"; + File file = new File(finalXlsxPath); + if (!file.exists()) { + if (!file.mkdir()) { + throw new BizException("文件目录生成失败"); + } + } + String fileName; + long timeMillis = System.currentTimeMillis(); + fileName = timeMillis + ".xlsx"; + finalXlsxPath += fileName; + ExcelWriter excelWriter = EasyExcel.write(finalXlsxPath) + .registerConverter(new CustomBigDecimalConverter()) + .registerConverter(new CustomLongConverter()) + .registerConverter(new CustomerLocalDateTimeConverter()) + .registerConverter(new CustomerLocalDateConverter()) + .registerWriteHandler(new ImageModifyHandler()) + .withTemplate(templateFileInputStream) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + // 单表多数据导出 模板格式为 {.属性} + for (Object d : data) { + excelWriter.fill(d, writeSheet); + } + + excelWriter.finish(); + // 返回下载相对路径 + return fileName; + } + + /** + * 通过模板文件名获取模板的输入流 + *

模板文件必须放置在resource/templates下

+ * + * @param templateFileName 模板文件名 + * @return 对应文件的输入流 + */ + public InputStream getTemplateFileAsStream(String templateFileName) { + //如果采用getPath方法获取文件地址本地环境可以获取到,上传到服务器后会失效,采用流可以都生效。 + return EasyExcelUtil.class.getClassLoader().getResourceAsStream("templates/" + templateFileName + ".xlsx"); + } + + + /** + * 浏览器写入excel + * + * @param downloadFileName 下载文件名字 + * @param pojoClass pojo类 + * @param response 响应 + */ + public void writeToExcelForResponse(String downloadFileName, Class pojoClass, HttpServletResponse response) { + // 这里注意 使用swagger 会导致各种问题,easyexcel官方文档推荐直接用浏览器或者用postman测试 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + try { + // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 + String fileName = URLEncoder.encode(downloadFileName, "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); + EasyExcel.write(response.getOutputStream(), pojoClass).sheet(downloadFileName).doWrite(new ArrayList<>()); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomBigDecimalConverter.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomBigDecimalConverter.java new file mode 100644 index 0000000..29e132a --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomBigDecimalConverter.java @@ -0,0 +1,67 @@ +package com.qniao.dam.infrastructure.easyexcel.converter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * 自定义BigDecimal类型处理器 + * + * @author nicemorning + * @date 2021/9/17 16:37 + */ +public class CustomBigDecimalConverter implements Converter { + /** + * Back to object types in Java + * + * @return Support for Java class + */ + @Override + public Class supportJavaTypeKey() { + return BigDecimal.class; + } + + /** + * Back to object enum in excel + * + * @return Support for {@link CellDataTypeEnum} + */ + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + /** + * Convert excel objects to Java objects + * + * @param cellData Excel cell data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Java object + * @throws Exception Exception. + */ + @Override + public BigDecimal convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { + return new BigDecimal(cellData.getNumberValue().toPlainString()).setScale(3, RoundingMode.HALF_UP); + } + + /** + * Convert Java objects to excel objects + * + * @param value Java Data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Excel + * @throws Exception Exception. + */ + @Override + public WriteCellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { + return new WriteCellData<>(value.setScale(3, RoundingMode.HALF_UP).toPlainString()); + } +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomImageConverter.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomImageConverter.java new file mode 100644 index 0000000..90a9e4c --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomImageConverter.java @@ -0,0 +1,90 @@ +package com.qniao.dam.infrastructure.easyexcel.converter; + + + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.IoUtils; +import com.alibaba.excel.util.StringUtils; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; + +public class CustomImageConverter implements Converter { + @Override + public Class supportJavaTypeKey() + { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() + { + return CellDataTypeEnum.RICH_TEXT_STRING; + } + + @Override + public String convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) + { + throw new UnsupportedOperationException("Cannot convert images to string"); + } + + // 图片失效处理 + @Override + public WriteCellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) + throws IOException + { + InputStream inputStream = null; + try + { + if(StringUtils.isEmpty(value)) + { + return new WriteCellData<>("图片路径为空"); + } + URL urlValue = new URL(value); + // 开启连接 + URLConnection uc = urlValue.openConnection(); + // 获取响应状态 + int statusCode = ((HttpURLConnection)uc).getResponseCode(); + switch (statusCode) + { + case 200: + inputStream = urlValue.openStream(); + break; + default: + return new WriteCellData<>("无法加载图片"); + } + byte[] bytes = IoUtils.toByteArray(inputStream); + WriteCellData cellData = new WriteCellData<>(bytes); + cellData.setType(CellDataTypeEnum.NUMBER); + return cellData; + } + catch (ConnectException exception) + { + return new WriteCellData<>("无法加载图片"); + } + catch (FileNotFoundException fileNotFoundException) + { + return new WriteCellData<>("无法加载图片"); + } + finally + { + if (inputStream != null) + { + inputStream.close(); + } + } + } + +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomLongConverter.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomLongConverter.java new file mode 100644 index 0000000..0fb09d4 --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomLongConverter.java @@ -0,0 +1,64 @@ +package com.qniao.dam.infrastructure.easyexcel.converter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * 自定义Long类型处理器 + * + * @author nicemorning + * @date 2021/9/17 14:56 + */ +public class CustomLongConverter implements Converter { + /** + * Back to object types in Java + * + * @return Support for Java class + */ + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + /** + * Back to object enum in excel + * + * @return Support for {@link CellDataTypeEnum} + */ + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + /** + * Convert excel objects to Java objects + * + * @param cellData Excel cell data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Java object + * @throws Exception Exception. + */ + @Override + public Long convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { + return null; + } + + /** + * Convert Java objects to excel objects + * + * @param value Java Data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Excel + * @throws Exception Exception. + */ + @Override + public WriteCellData convertToExcelData(Long value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { + return new WriteCellData<>(String.valueOf(value)); + } +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateConverter.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateConverter.java new file mode 100644 index 0000000..a12fd2c --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateConverter.java @@ -0,0 +1,69 @@ +package com.qniao.dam.infrastructure.easyexcel.converter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * 自定义LocalDate类型处理器 + * + * @author nicemorning + * @date 2021/9/24 19:59 + */ +public class CustomerLocalDateConverter implements Converter { + private final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + /** + * Back to object types in Java + * + * @return Support for Java class + */ + @Override + public Class supportJavaTypeKey() { + return LocalDate.class; + } + + /** + * Back to object enum in excel + * + * @return Support for {@link CellDataTypeEnum} + */ + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + /** + * Convert excel objects to Java objects + * + * @param cellData Excel cell data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Java object + * @throws Exception Exception. + */ + @Override + public LocalDate convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { + return LocalDate.parse(cellData.getStringValue(), DATE_TIME_FORMATTER); + } + + /** + * Convert Java objects to excel objects + * + * @param value Java Data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Excel + * @throws Exception Exception. + */ + @Override + public WriteCellData convertToExcelData(LocalDate value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { + return new WriteCellData<>(DATE_TIME_FORMATTER.format(value)); + } +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateTimeConverter.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateTimeConverter.java new file mode 100644 index 0000000..c98cabd --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateTimeConverter.java @@ -0,0 +1,69 @@ +package com.qniao.dam.infrastructure.easyexcel.converter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 自定义LocalDateTime类型处理器 + * + * @author nicemorning + * @date 2021/9/24 19:54 + */ +public class CustomerLocalDateTimeConverter implements Converter { + private final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + /** + * Back to object types in Java + * + * @return Support for Java class + */ + @Override + public Class supportJavaTypeKey() { + return LocalDateTime.class; + } + + /** + * Back to object enum in excel + * + * @return Support for {@link CellDataTypeEnum} + */ + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + /** + * Convert excel objects to Java objects + * + * @param cellData Excel cell data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Java object + * @throws Exception Exception. + */ + @Override + public LocalDateTime convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { + return LocalDateTime.parse(cellData.getStringValue(), DATE_TIME_FORMATTER); + } + + /** + * Convert Java objects to excel objects + * + * @param value Java Data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Excel + * @throws Exception Exception. + */ + @Override + public WriteCellData convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { + return new WriteCellData<>(DATE_TIME_FORMATTER.format(value)); + } +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/handler/ImageModifyHandler.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/handler/ImageModifyHandler.java new file mode 100644 index 0000000..ecbb466 --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/handler/ImageModifyHandler.java @@ -0,0 +1,94 @@ +package com.qniao.dam.infrastructure.easyexcel.handler; + +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.data.ImageData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Objects; + +/** + * 修改图像处理程序 + * + * @author admin + * @date 2023/01/16 + */ +public class ImageModifyHandler implements CellWriteHandler { + /** + * 后单元格数据转换 + * + * @param writeSheetHolder 写单夹 + * @param writeTableHolder 写表夹 + * @param cellData 单元格数据 + * @param cell 细胞 + * @param head 头 + * @param relativeRowIndex 相对行索引 + * @param isHead 是头 + */ + @Override + public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + WriteCellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + boolean noImageValue = Objects.isNull(cellData) || CollectionUtils.isEmpty(cellData.getImageDataList()); + if (Objects.equals(Boolean.TRUE, isHead) || noImageValue) { + return; + } + Sheet sheet = cell.getSheet(); + int mergeColumNum = getMergeColumNum(cell, sheet); + int mergeRowNum = getMergeRowNum(cell, sheet); + ImageData imageData = cellData.getImageDataList().get(0); + imageData.setRelativeLastRowIndex(mergeRowNum - 1); + imageData.setRelativeLastColumnIndex(mergeColumNum - 1); + CellWriteHandler.super.afterCellDataConverted(writeSheetHolder, writeTableHolder, cellData, cell, head, relativeRowIndex, isHead); + } + + + /** + * 得到合并行num + * + * @param cell 细胞 + * @param sheet 表 + * @return int + */ + public static int getMergeRowNum(Cell cell, Sheet sheet) { + int mergeSize = 1; + List mergedRegions = sheet.getMergedRegions(); + for (CellRangeAddress cellRangeAddress : mergedRegions) { + if (cellRangeAddress.isInRange(cell)) { + //获取合并的行数 + mergeSize = cellRangeAddress.getLastRow() - cellRangeAddress.getFirstRow() + 1; + break; + } + } + return mergeSize; + } + + /** + * 得到合并列num + * + * @param cell 细胞 + * @param sheet 表 + * @return int + */ + public static int getMergeColumNum(Cell cell, Sheet sheet) { + int mergeSize = 1; + List mergedRegions = sheet.getMergedRegions(); + for (CellRangeAddress cellRangeAddress : mergedRegions) { + if (cellRangeAddress.isInRange(cell)) { + //获取合并的列数 + mergeSize = cellRangeAddress.getLastColumn() - cellRangeAddress.getFirstColumn() + 1; + break; + } + } + return mergeSize; + } + +} + + diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/listener/ExportListener.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/listener/ExportListener.java new file mode 100644 index 0000000..ffd5266 --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/listener/ExportListener.java @@ -0,0 +1,172 @@ +package com.qniao.dam.infrastructure.easyexcel.listener; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.qniao.domain.QnPage; +import com.qniao.framework.exception.BizException; +import com.qniao.framework.utils.PageUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +/** + * R: 需要传入查询SQL接收的DTO(也是设置了excel的格式内容的DTO) + * + * @author Lzk + * @date 2022/3/24 + **/ +@Slf4j +@Component +public class ExportListener { + + /** + * 设置一次存的条数 + */ + private static final Integer PAGE_SIZE = 2500; + + + @Value("${server-file-path:/}") + private String sFilePath; + + private static String serverFilePath; + + @PostConstruct + public void init() { + serverFilePath = this.sFilePath; + } + + /** + * 导出excel + * + * @param sheetName excel页名称 + * @param pojoClass 导出对应的Dto对象 + * @param pageUtil 分页参数(用于设置分页参数,更改分页的结果) + * @param selectFunction 按照传入的分页参数,查询每次的结果 + * @return excel的服务器下载地址 + */ + public String exportExcel(String sheetName, Class pojoClass, PageUtil pageUtil, Function> selectFunction) { + // 导出的excel名称 + String fileName; + try { + String finalXlsxPath = serverFilePath + "/temp/"; + File file = new File(finalXlsxPath); + if (!file.exists()) { + file.mkdir(); + } + fileName = String.valueOf(System.currentTimeMillis()); + finalXlsxPath += fileName + ".xlsx"; + + // 这里 需要指定写用哪个class去写 + ExcelWriter excelWriter = EasyExcel.write(finalXlsxPath, pojoClass).build(); + // 这里注意 如果同一个sheet只要创建一次 + WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build(); + + // 开始下标 + int startIndex = 1; + // 去调用写入,根据数据库分页的总的页数来 + while (true) { + // 已经查询到的数据量 + int startParam = (startIndex - 1) * PAGE_SIZE; + // 计算现在是第几页 + int pageNumber = (int) Math.ceil((double) startParam / (double) PAGE_SIZE + 1); + + // 设置需要查询的页数和每页的大小 + pageUtil.setPageNum(pageNumber); + pageUtil.setPageSize(PAGE_SIZE); + // 再次回调查询 + QnPage cityPage = selectFunction.apply(pageUtil); + List pageList = cityPage.getRecords(); + if (CollectionUtils.isEmpty(pageList)) { + break; + } + // 下标+1 + startIndex++; + excelWriter.write(pageList, writeSheet); + } + + // 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } catch (Exception e) { + log.error("excel导出异常:", e); + throw new BizException("excel导出异常"); + } + return fileName + ".xlsx"; + } + + /** + * 动态导出excel(自定义选择要导出的字段) + * 注:如果需要重复的N行时,需要屏蔽的其他行数据时,展示字段必填 + * + * @param sheetName sheet页名称 + * @param pojoClass 导出的模板 + * @param pageUtil 分页对象 + * @param selectExport 选择要导出的字段index(从0开始,必填) + * @param selectFunction 按照传入的分页参数,查询每次的结果 + * @return excel服务器下载地址 + */ + public String dynamicExportExcel(String sheetName, + Class pojoClass, + PageUtil pageUtil, + Set selectExport, + Function> selectFunction) { + + if (CollectionUtils.isEmpty(selectExport)) { + throw new BizException("要导出的字段不能为空!"); + } + + // 导出的excel名称 + String fileName; + try { + String finalXlsxPath = serverFilePath + "/temp/"; + File file = new File(finalXlsxPath); + if (!file.exists()) { + file.mkdir(); + } + fileName = String.valueOf(System.currentTimeMillis()); + finalXlsxPath += fileName + ".xlsx"; + + // 把自定义的表头设置为模板 + ExcelWriter excelWriter = EasyExcel.write(finalXlsxPath, pojoClass).includeColumnIndexes(selectExport).build(); + + // 这里注意 如果同一个sheet只要创建一次 + WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build(); + + // 开始下标 + int startIndex = 1; + // 去调用写入,根据数据库分页的总的页数来 + while (true) { + // 已经查询到的数据量 + int startParam = (startIndex - 1) * PAGE_SIZE; + // 计算现在是第几页 + int pageNumber = (int) Math.ceil((double) startParam / (double) PAGE_SIZE + 1); + // 设置需要查询的页数和每页的大小 + pageUtil.setPageNum(pageNumber); + pageUtil.setPageSize(PAGE_SIZE); + // 再次回调查询 + QnPage cityPage = selectFunction.apply(pageUtil); + List pageList = cityPage.getRecords(); + if (CollectionUtils.isEmpty(pageList)) { + break; + } + // 下标+1 + startIndex++; + excelWriter.write(pageList, writeSheet); + } + + // 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } catch (Exception e) { + log.error("excel导出异常:", e); + throw new BizException("excel导出异常"); + } + return fileName + ".xlsx"; + } +} diff --git a/dating-agency-mall-server/src/main/resources/application.yml b/dating-agency-mall-server/src/main/resources/application.yml index 5aa584b..5ef290a 100644 --- a/dating-agency-mall-server/src/main/resources/application.yml +++ b/dating-agency-mall-server/src/main/resources/application.yml @@ -103,4 +103,7 @@ snow-flake: ding-talk-alarm-robot-access-token: 1 logging: - config: classpath:logback.xml \ No newline at end of file + config: classpath:logback.xml + +# 服务器文件存放路径 +server-file-path: /home/files/ \ No newline at end of file