12 changed files with 869 additions and 1 deletions
Unified 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