12 changed files with 869 additions and 1 deletions
Split View
Diff Options
-
6dating-agency-mall-server/pom.xml
-
35dating-agency-mall-server/src/main/java/com/qniao/dam/api/query/download/user/DownloadUserCommandController.java
-
76dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/download/DownloadService.java
-
123dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/EasyExcelUtil.java
-
67dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomBigDecimalConverter.java
-
90dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomImageConverter.java
-
64dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomLongConverter.java
-
69dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateConverter.java
-
69dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/converter/CustomerLocalDateTimeConverter.java
-
94dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/handler/ImageModifyHandler.java
-
172dating-agency-mall-server/src/main/java/com/qniao/dam/infrastructure/easyexcel/listener/ExportListener.java
-
5dating-agency-mall-server/src/main/resources/application.yml
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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<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()) |
|||
.registerWriteHandler(new ImageModifyHandler()) |
|||
.withTemplate(templateFileInputStream) |
|||
.build(); |
|||
WriteSheet writeSheet = EasyExcel.writerSheet().build(); |
|||
// 单表多数据导出 模板格式为 {.属性} |
|||
for (Object d : data) { |
|||
excelWriter.fill(d, writeSheet); |
|||
} |
|||
|
|||
excelWriter.finish(); |
|||
// 返回下载相对路径 |
|||
return fileName; |
|||
} |
|||
|
|||
/** |
|||
* 通过模板文件名获取模板的输入流 |
|||
* <p><strong>模板文件必须放置在resource/templates下</strong></p> |
|||
* |
|||
* @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(); |
|||
} |
|||
} |
|||
} |
|||
@ -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<BigDecimal> { |
|||
/** |
|||
* Back to object types in Java |
|||
* |
|||
* @return Support for Java class |
|||
*/ |
|||
@Override |
|||
public Class<BigDecimal> 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<BigDecimal> convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { |
|||
return new WriteCellData<>(value.setScale(3, RoundingMode.HALF_UP).toPlainString()); |
|||
} |
|||
} |
|||
@ -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<String> { |
|||
@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<Object> 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<Object> 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(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -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<Long> { |
|||
/** |
|||
* Back to object types in Java |
|||
* |
|||
* @return Support for Java class |
|||
*/ |
|||
@Override |
|||
public Class<Long> 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<String> convertToExcelData(Long value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { |
|||
return new WriteCellData<>(String.valueOf(value)); |
|||
} |
|||
} |
|||
@ -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<LocalDate> { |
|||
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<LocalDate> 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<String> convertToExcelData(LocalDate value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { |
|||
return new WriteCellData<>(DATE_TIME_FORMATTER.format(value)); |
|||
} |
|||
} |
|||
@ -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<LocalDateTime> { |
|||
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<LocalDateTime> 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<String> convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception { |
|||
return new WriteCellData<>(DATE_TIME_FORMATTER.format(value)); |
|||
} |
|||
} |
|||
@ -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<CellRangeAddress> 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<CellRangeAddress> mergedRegions = sheet.getMergedRegions(); |
|||
for (CellRangeAddress cellRangeAddress : mergedRegions) { |
|||
if (cellRangeAddress.isInRange(cell)) { |
|||
//获取合并的列数 |
|||
mergeSize = cellRangeAddress.getLastColumn() - cellRangeAddress.getFirstColumn() + 1; |
|||
break; |
|||
} |
|||
} |
|||
return mergeSize; |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
@ -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<R> { |
|||
|
|||
/** |
|||
* 设置一次存的条数 |
|||
*/ |
|||
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<R> pojoClass, PageUtil pageUtil, Function<PageUtil, QnPage<R>> 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<R> cityPage = selectFunction.apply(pageUtil); |
|||
List<R> 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<R> pojoClass, |
|||
PageUtil pageUtil, |
|||
Set<Integer> selectExport, |
|||
Function<PageUtil, QnPage<R>> 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<R> cityPage = selectFunction.apply(pageUtil); |
|||
List<R> 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"; |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save