Commit 962fbd42 by zhangxingmin

通用导出

parent da06d17c
......@@ -3,6 +3,8 @@ package com.yd.oss.api.controller;
import com.yd.common.result.Result;
import com.yd.oss.api.service.ApiExcelService;
import com.yd.oss.feign.client.ApiExcelFeignClient;
import com.yd.oss.feign.dto.ExportResult;
import com.yd.oss.feign.request.ApiExportRequest;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
......@@ -47,4 +49,13 @@ public class ApiExcelController implements ApiExcelFeignClient {
return apiExcelService.parse(file,sheetClassNames);
}
/**
* 导出excel(通用)
* @return
*/
@Override
public Result<ExportResult> export(ApiExportRequest request) {
return apiExcelService.export(request.getDataList(),request.getExportParam(),request.getEntityClass());
}
}
package com.yd.oss.api.service;
import com.yd.common.result.Result;
import com.yd.oss.feign.dto.ExportParam;
import com.yd.oss.feign.dto.ExportResult;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface ApiExcelService {
Result<ApiOssExportAppointmentExcelResponse> exportAppointment(ApiOssExportAppointmentExcelRequest request);
Result<ApiOssExcelParseResponse> parse(MultipartFile file, String[] sheetClassNames);
Result<ExportResult> export(List<?> dataList, ExportParam exportParam, Class<?> entityClass);
}
......@@ -6,12 +6,17 @@ import com.yd.oss.api.service.ApiExcelService;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
import com.yd.oss.feign.dto.ExportParam;
import com.yd.oss.feign.dto.ExportResult;
import com.yd.oss.service.service.AppointmentExcelService;
import com.yd.oss.service.service.ExcelExportService;
import com.yd.oss.service.service.ExcelParserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
@Slf4j
......@@ -24,6 +29,9 @@ public class ApiExcelServiceImpl implements ApiExcelService {
@Autowired
private ExcelParserService excelParserService;
@Autowired
private ExcelExportService excelExportService;
/**
* 导出excel-预约信息
* @param request
......@@ -65,4 +73,17 @@ public class ApiExcelServiceImpl implements ApiExcelService {
}
}
/**
* 通用-Excel导出参数(如果传dataList附加数据,不传单纯导出表头参数)
* @param dataList
* @param exportParam
* @param entityClass
* @return
*/
@Override
public Result<ExportResult> export(List<?> dataList, ExportParam exportParam, Class<?> entityClass) {
ExportResult exportResult = excelExportService.exportAndUploadToOss(dataList,exportParam,entityClass);
return Result.success(exportResult);
}
}
......@@ -6,8 +6,10 @@ import com.yd.oss.api.service.ApiOssService;
import com.yd.oss.feign.response.ApiFileMetadataResponse;
import com.yd.oss.feign.response.ApiUploadResponse;
import com.yd.oss.service.dto.FileMetadata;
import com.yd.oss.service.dto.OssUploadFileDto;
import com.yd.oss.service.dto.UploadResult;
import com.yd.oss.service.service.OssService;
import com.yd.oss.service.utils.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
......@@ -44,10 +46,11 @@ public class ApiOssServiceImpl implements ApiOssService {
}
// 上传文件
String fileKey = ossService.uploadFile(file.getInputStream(), file.getOriginalFilename(), bucket, uploadUser);
OssUploadFileDto ossUploadFileDto = ossService.uploadFile(file.getInputStream(), file.getOriginalFilename(),
bucket, uploadUser, FileUtil.getFileType(file.getOriginalFilename()));
// 获取上传结果(包含文件信息和访问URL)
UploadResult result = ossService.getUploadResult(fileKey, Duration.ofHours(1));
UploadResult result = ossService.getUploadResult(ossUploadFileDto.getFileKey(), Duration.ofHours(1));
BeanUtils.copyProperties(result,response);
......
package com.yd.oss.feign.client;
import com.yd.common.result.Result;
import com.yd.oss.feign.dto.ExportResult;
import com.yd.oss.feign.fallback.ApiExcelFeignFallbackFactory;
import com.yd.oss.feign.request.ApiExportRequest;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
......@@ -16,7 +18,7 @@ import org.springframework.web.multipart.MultipartFile;
/**
* Excel信息Feign客户端
*/
@FeignClient(name = "yd-oss-api", fallbackFactory = ApiExcelFeignFallbackFactory.class)
@FeignClient(name = "yd-oss-api",path = "/oss/api/excel",fallbackFactory = ApiExcelFeignFallbackFactory.class)
public interface ApiExcelFeignClient {
/**
......@@ -33,4 +35,11 @@ public interface ApiExcelFeignClient {
@PostMapping(value = "/parse-excel", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Result<ApiOssExcelParseResponse> parse(@RequestPart("file") MultipartFile file,
@RequestPart("sheetClassNames") String[] sheetClassNames);
/**
* 导出excel(通用)
* @return
*/
@PostMapping("/export")
Result<ExportResult> export(@Validated @RequestBody ApiExportRequest request);
}
package com.yd.oss.feign.dto;
import lombok.Data;
import java.util.List;
@Data
public class ExportParam {
/**
* 要导出的字段名列表
*/
private List<String> fieldNames;
/**
* 导出的文件名(不含扩展名)
*/
private String fileName;
/**
* 是否上传到OSS
*/
private Boolean uploadToOss = false;
/**
* OSS存储路径(如:exports/excel/)
*/
private String ossPath = "exports/excel/";
}
\ No newline at end of file
package com.yd.oss.feign.dto;
import lombok.Data;
@Data
public class ExportResult {
/**
* 导出是否成功
*/
private Boolean success;
/**
* 错误信息
*/
private String errorMsg;
/**
* 文件大小(字节)
*/
private Long fileSize;
/**
* OSS文件URL(如果上传到OSS)
*/
private String ossUrl;
/**
* 本地文件路径(如果不上传OSS)
*/
private String localFilePath;
public static ExportResult success(String ossUrl, Long fileSize) {
ExportResult result = new ExportResult();
result.setSuccess(true);
result.setOssUrl(ossUrl);
result.setFileSize(fileSize);
return result;
}
public static ExportResult error(String errorMsg) {
ExportResult result = new ExportResult();
result.setSuccess(false);
result.setErrorMsg(errorMsg);
return result;
}
}
\ No newline at end of file
......@@ -2,6 +2,8 @@ package com.yd.oss.feign.fallback;
import com.yd.common.result.Result;
import com.yd.oss.feign.client.ApiExcelFeignClient;
import com.yd.oss.feign.dto.ExportResult;
import com.yd.oss.feign.request.ApiExportRequest;
import com.yd.oss.feign.request.ApiOssExcelParseRequest;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
......@@ -30,6 +32,11 @@ public class ApiExcelFeignFallbackFactory implements FallbackFactory<ApiExcelFei
return null;
}
@Override
public Result<ExportResult> export(ApiExportRequest request) {
return null;
}
};
}
}
package com.yd.oss.feign.request;
import com.yd.oss.feign.dto.ExportParam;
import lombok.Data;
import java.util.List;
@Data
public class ApiExportRequest {
/**
* 需要导出的数据列表
*/
private List<?> dataList;
/**
* 导出参数配置
*/
private ExportParam exportParam;
/**
* 实体类类型
*/
private Class<?> entityClass;
}
package com.yd.oss.service.dto;
import lombok.Data;
/**
* 提供OSS上传文件返回的DTO
*/
@Data
public class OssUploadFileDto {
/**
* 文件元数据表业务ID唯一标识
*/
private String fileBizId;
/**
* 文件唯一标识
*/
private String fileKey;
/**
* 原始文件名
*/
private String originalName;
/**
* 完整的访问路径
*/
private String url;
}
package com.yd.oss.service.service;
import com.yd.oss.feign.dto.ExportParam;
import com.yd.oss.feign.dto.ExportResult;
import java.util.List;
public interface ExcelExportService {
ExportResult exportAndUploadToOss(List<?> dataList, ExportParam exportParam, Class<?> entityClass);
}
package com.yd.oss.service.service;
import com.yd.oss.service.dto.FileMetadata;
import com.yd.oss.service.dto.OssUploadFileDto;
import com.yd.oss.service.dto.UploadResult;
import com.yd.oss.service.model.OssProvider;
import java.io.InputStream;
......@@ -12,7 +13,7 @@ import java.time.Duration;
public interface OssService {
// 上传文件
String uploadFile(InputStream inputStream, String fileName, String bucketName, String uploadUser);
OssUploadFileDto uploadFile(InputStream inputStream, String fileName, String bucketName, String uploadUser,String type);
// 上传文件(使用默认存储桶)
String uploadFile(InputStream inputStream, String fileName, String uploadUser);
......
package com.yd.oss.service.service.impl;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.yd.oss.feign.dto.ExportParam;
import com.yd.oss.feign.dto.ExportResult;
import com.yd.oss.service.dto.OssUploadFileDto;
import com.yd.oss.service.service.ExcelExportService;
import com.yd.oss.service.service.OssService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* excel导出实现类
*/
@Slf4j
@Service
public class ExcelExportServiceImpl implements ExcelExportService {
// 注入OSS服务,用于文件上传
@Autowired
private OssService ossService;
/**
* 导出Excel并上传到OSS
* @param dataList 需要导出的数据列表
* @param exportParam 导出参数配置
* @param entityClass 实体类类型
* @return 导出结果
*/
@Override
public ExportResult exportAndUploadToOss(List<?> dataList, ExportParam exportParam, Class<?> entityClass) {
// 声明输出流和工作簿变量,用于后续资源关闭
ByteArrayOutputStream outputStream = null;
Workbook workbook = null;
try {
// 根据实体类字段和导出参数构建Excel导出列配置
List<ExcelExportEntity> entityList = buildExportEntities(exportParam.getFieldNames(), entityClass);
// 将数据列表转换为Map结构,便于EasyPOI处理
List<Map<String, Object>> dataMapList = buildDataMapList(dataList, exportParam.getFieldNames(), entityClass);
// 创建字节数组输出流,用于将Excel数据写入内存
outputStream = new ByteArrayOutputStream();
// 设置导出参数:无标题、工作表名称为sheet1、使用XSSF格式(支持.xlsx)
ExportParams params = new ExportParams(null, "sheet1", ExcelType.XSSF);
// 使用EasyPOI导出Excel到工作簿
workbook = ExcelExportUtil.exportExcel(params, entityList, dataMapList);
// 将工作簿内容写入输出流
workbook.write(outputStream);
// 获取Excel文件的字节数组和文件大小
byte[] excelBytes = outputStream.toByteArray();
long fileSize = excelBytes.length;
// 根据参数决定是否上传到OSS
if (Boolean.TRUE.equals(exportParam.getUploadToOss())) {
// 将字节数组转换为输入流,供OSS上传使用
ByteArrayInputStream inputStream = new ByteArrayInputStream(excelBytes);
// 生成包含时间戳的文件名,避免重复
String fileName = generateExcelFileName(exportParam.getFileName());
// 调用OSS服务上传文件到云端存储
OssUploadFileDto uploadResult = ossService.uploadFile(
inputStream, // Excel文件输入流
fileName, // 生成的文件名
"", // 存储桶名称(空字符串表示使用默认存储桶)
"", // 上传用户标识(空字符串表示匿名或系统用户)
"excel" // 文件分类类型,对应OSS文件夹目录
);
// 返回成功结果,包含文件URL和大小信息
return ExportResult.success(uploadResult.getUrl(), fileSize);
} else {
// 如果不需要上传到OSS,仅返回文件大小信息
return ExportResult.success(null, fileSize);
}
} catch (Exception e) {
// 打印异常堆栈,便于调试和问题排查
e.printStackTrace();
// 返回错误结果,包含异常信息
return ExportResult.error("导出失败: " + e.getMessage());
} finally {
// 资源清理块,确保工作簿和输出流正确关闭
try {
// 关闭工作簿,释放内存资源
if (workbook != null) {
workbook.close();
}
// 关闭输出流,释放系统资源
if (outputStream != null) {
outputStream.close();
}
} catch (Exception e) {
// 打印资源关闭时的异常信息
e.printStackTrace();
}
}
}
/**
* 生成Excel文件名(包含时间戳)
* @param baseName 基础文件名
* @return 生成的文件名
*/
private String generateExcelFileName(String baseName) {
// 如果基础文件名为空,使用默认文件名
if (StringUtils.isBlank(baseName)) {
baseName = "export_data";
}
// 去除已有文件扩展名,确保统一使用.xlsx格式
if (baseName.contains(".")) {
baseName = baseName.substring(0, baseName.lastIndexOf('.'));
}
// 生成时间戳,格式为年月日_时分秒
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
// 组合基础文件名、时间戳和文件扩展名
return baseName + "_" + timestamp + ".xlsx";
}
/**
* 构建导出列实体配置
* @param fieldNames 字段名称列表
* @param entityClass 实体类类型
* @return Excel导出列配置列表
*/
private List<ExcelExportEntity> buildExportEntities(List<String> fieldNames, Class<?> entityClass) {
// 创建导出列配置列表
List<ExcelExportEntity> entityList = new ArrayList<>();
// 获取实体类字段的注解映射(字段名->Excel列名)
Map<String, String> fieldAnnotationMap = getFieldAnnotations(entityClass);
// 遍历所有需要导出的字段
for (String fieldName : fieldNames) {
// 检查字段是否存在于注解映射中
if (fieldAnnotationMap.containsKey(fieldName)) {
// 创建Excel导出列实体:参数1为Excel列标题,参数2为实体字段名
ExcelExportEntity entity = new ExcelExportEntity(fieldAnnotationMap.get(fieldName), fieldName);
// 将列配置添加到列表
entityList.add(entity);
}
}
return entityList;
}
/**
* 获取字段注解映射(字段名->Excel列名)
* @param entityClass 实体类类型
* @return 字段注解映射表
*/
private Map<String, String> getFieldAnnotations(Class<?> entityClass) {
// 创建字段注解映射表
Map<String, String> fieldAnnotationMap = new HashMap<>();
// 获取实体类声明的所有字段
Field[] fields = entityClass.getDeclaredFields();
// 遍历所有字段
for (Field field : fields) {
// 获取字段上的Excel注解配置
cn.afterturn.easypoi.excel.annotation.Excel excelAnnotation =
field.getAnnotation(cn.afterturn.easypoi.excel.annotation.Excel.class);
// 如果字段有Excel注解,记录映射关系
if (excelAnnotation != null) {
// key: 字段名, value: Excel列名
fieldAnnotationMap.put(field.getName(), excelAnnotation.name());
}
}
return fieldAnnotationMap;
}
/**
* 构建数据Map列表,将对象列表转换为EasyPOI所需的Map结构
* @param dataList 数据对象列表
* @param fieldNames 需要导出的字段名称列表
* @param entityClass 实体类类型
* @return 数据Map列表
*/
private List<Map<String, Object>> buildDataMapList(List<?> dataList, List<String> fieldNames, Class<?> entityClass) {
// 创建数据Map列表
List<Map<String, Object>> dataMapList = new ArrayList<>();
// 遍历数据列表中的每个对象
for (Object data : dataList) {
// 为每个对象创建字段-值的映射
Map<String, Object> map = new HashMap<>();
// 遍历所有需要导出的字段
for (String fieldName : fieldNames) {
try {
// 通过反射获取字段对象
Field field = entityClass.getDeclaredField(fieldName);
// 设置字段可访问(突破private限制)
field.setAccessible(true);
// 将字段值放入Map,key为字段名,value为字段值
map.put(fieldName, field.get(data));
} catch (Exception e) {
// 如果获取字段值失败,设置为空字符串
map.put(fieldName, "");
}
}
// 将当前对象的字段映射添加到列表
dataMapList.add(map);
}
return dataMapList;
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="ExternalSystem" externalSystem="Maven" />
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment