增加导出功能

This commit is contained in:
wuweihua
2026-10-21 18:06:21 +08:00
parent c04191c316
commit 92000956fc
15 changed files with 1181 additions and 21 deletions
@@ -0,0 +1,157 @@
package com.bms.price.task;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import com.bms.common.config.BmsConfig;
import com.bms.common.core.redis.RedisCache;
import com.bms.common.utils.StringUtils;
import com.bms.common.utils.poi.ExcelUtil;
import com.bms.price.domain.PrcOrderBill;
import com.bms.price.domain.PrcOrderBillExportTask;
import com.bms.price.domain.vo.PrcBillingBillListExportRow;
import com.bms.price.domain.vo.PrcOrderBillListExportRow;
import com.bms.price.service.IPrcOrderBillService;
import com.bms.price.service.support.OrderBillExportSupport;
/**
* Async Excel export for order list / billing list.
* Writes under download path; poll task then download by taskId.
*/
@Component
public class PrcOrderBillExportAsyncRunner
{
private static final Logger log = LoggerFactory.getLogger(PrcOrderBillExportAsyncRunner.class);
public static final String CACHE_KEY_PREFIX = "price:billing:export:task:";
public static final int TTL_MINUTES = 60;
public static final String REL_DIR = "orderBillExport";
@Autowired
@Lazy
private IPrcOrderBillService orderBillService;
@Autowired
private RedisCache redisCache;
/**
* @param authentication login from request thread; required because {@code selectBillList} uses {@code @DataScope}
*/
@Async("threadPoolTaskExecutor")
public void run(String taskId, String exportType, PrcOrderBill query, String fileName,
Authentication authentication)
{
Path file = null;
SecurityContext previous = SecurityContextHolder.getContext();
try
{
// Async pool threads have no JWT filter; restore caller login for DataScope.
if (authentication != null)
{
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
}
put(taskId, PrcOrderBillExportTask.STATUS_RUNNING, 5, "querying", null,
exportType, fileName, null, 0);
List<PrcOrderBill> list = orderBillService.selectBillList(query == null ? new PrcOrderBill() : query);
int rows = list == null ? 0 : list.size();
put(taskId, PrcOrderBillExportTask.STATUS_RUNNING, 40, "building excel", null,
exportType, fileName, null, rows);
Path dir = Paths.get(BmsConfig.getDownloadPath(), REL_DIR).toAbsolutePath().normalize();
Files.createDirectories(dir);
file = dir.resolve(taskId + ".xlsx").normalize();
if (!file.startsWith(dir))
{
throw new IllegalStateException("invalid export path");
}
try (OutputStream out = Files.newOutputStream(file))
{
if (PrcOrderBillExportTask.TYPE_BILLING.equals(exportType))
{
List<PrcBillingBillListExportRow> exportRows = OrderBillExportSupport.toBillingListRows(list);
new ExcelUtil<PrcBillingBillListExportRow>(PrcBillingBillListExportRow.class)
.exportExcelToStream(exportRows, "\u8ba1\u8d39\u5217\u8868", out);
}
else
{
List<PrcOrderBillListExportRow> exportRows = OrderBillExportSupport.toOrderListRows(list);
new ExcelUtil<PrcOrderBillListExportRow>(PrcOrderBillListExportRow.class)
.exportExcelToStream(exportRows, "\u8ba2\u5355\u5217\u8868", out);
}
}
String storageKey = REL_DIR + "/" + taskId + ".xlsx";
put(taskId, PrcOrderBillExportTask.STATUS_SUCCESS, 100, "done", null,
exportType, fileName, storageKey, rows);
}
catch (Exception e)
{
log.error("order bill export failed taskId={}", taskId, e);
if (file != null)
{
try { Files.deleteIfExists(file); } catch (Exception ignore) { }
}
put(taskId, PrcOrderBillExportTask.STATUS_FAIL, 100, "failed", errorMessage(e),
exportType, fileName, null, 0);
}
finally
{
if (previous == null)
{
SecurityContextHolder.clearContext();
}
else
{
SecurityContextHolder.setContext(previous);
}
}
}
public void put(String taskId, String status, int percent, String message, String error,
String exportType, String fileName, String storageKey, int rowCount)
{
PrcOrderBillExportTask task = new PrcOrderBillExportTask();
task.setTaskId(taskId);
task.setStatus(status);
task.setPercent(percent);
task.setMessage(message);
task.setError(error);
task.setExportType(exportType);
task.setFileName(fileName);
task.setStorageKey(storageKey);
task.setRowCount(rowCount);
redisCache.setCacheObject(CACHE_KEY_PREFIX + taskId, task, TTL_MINUTES, TimeUnit.MINUTES);
}
public PrcOrderBillExportTask get(String taskId)
{
return redisCache.getCacheObject(CACHE_KEY_PREFIX + taskId);
}
private static String errorMessage(Exception e)
{
String msg = e.getMessage();
if (StringUtils.isEmpty(msg))
{
msg = e.getClass().getSimpleName();
}
if (msg.length() > 500)
{
msg = msg.substring(0, 500);
}
return msg;
}
}