随着业务的不断壮大发展,需要导出的数据量也越来越大!普通的EXCEL导出导出一份上万条的数据可能会用几分钟,十万条和百万条的数据量更是不敢想象,可能直接就OOM了。
所以我们需要找到更快速,减少内存开销的方法来处理导出。
我这里会介绍一种流式处理导出的方法,自己写成了一个通用工具,以便不同的服务调用。
一、获取数据处理成可用的数据
1、实现类需要实现 ExportProcessor
2、查询条件需要继承ExportQuery
API接口:
public interface ExportProcessor<Query extends ExportQuery> {
ExportResult exectue(Query query);
default boolean hasNext(Pager page) {
if (page == null) {
return false;
}
Pager.PageData pageData = page.getPage();
if (pageData == null) {
return false;
}
return pageData.getTotalPage() > pageData.getCurPage();
}
}
@Data
public class ExportResult {
private boolean hasNext;
private List> data;
}
ExportResult result = exportResultDataAdapt(mainOrderDataList);
result.setHasNext(hasNext(workOrderDataPager)); // 需要设置是否有下一页
private final static String WORK_ORDER_FILE_NAME = "工单详情列表";
private final static List HEADS = Lists
.newArrayList("工单ID", "日期", "城市", "销售点code", "销售点名称", "配送蜂房Code", "配送蜂房", "工单类型", "计划完成时间", "工单状态", "对接OP1",
"取消时间", "取消原因Code", "取消原因", "取消备注");
ExportFactory.doExport( HttpServletResponse response, WORK_ORDER_FILE_NAME, HEADS, exportQuery, workOrderExportProcessor);
使用简单的符号标识不同的标题,将某些文字标记为粗体或者斜体,创建一个链接等,详细语法参考帮助?。
本编辑器支持 Markdown Extra , 扩展了很多好用的功能。具体请参考[Github][2].
/**
* csv流式导出
*
* @param response
* @param fileName
* @param heads
* @param query
* @param processor
*/
public static void doExport(
HttpServletResponse response, String fileName, List heads, ExportQuery query,
ExportProcessor processor) throws IOException {
initResponseHead(response, fileName);
PrintWriter print = response.getWriter();
//打印表头head
println(print, heads);
while (true) {
ExportResult exportResult = processor.exectue(query);
if (exportResult == null) {
break;
}
List> data = exportResult.getData();
//打印每行
Safes.of(data).forEach(item -> {
println(print, item);
});
if (!exportResult.isHasNext()) {
break;
}
}
print.flush();
print.close();
}
public static void println(PrintWriter print, List data) {
logger.info("characters获取到的信息:{}", JsonUtils.toJsonString(characters));
StringBuilder tmp = new StringBuilder();
if (CollectionUtils.isEmpty(data)) {
print.print(tmp.append("\r\n").toString());
return;
}
for (int i = 0; i < data.size(); i++) {
if (i > 0) {
tmp.append(",");
}
String val = data.get(i);
if (NumberUtils.isNumber(val) && val.length() > 15) {
val += "\t";
}
if (StringUtils.isNotBlank(val) && CollectionUtils.isNotEmpty(characters)) {
for (String character : characters) {
val = StringUtils.replace(val, character, " ");
}
}
tmp.append(StringUtils.isBlank(val) ? "" : StringUtils.replace(val, ",", "."));
}
print.print(tmp.append("\r\n").toString());
}
/**
* 设置头
*
* @return
*/
private static void initResponseHead(HttpServletResponse response, String fileName) {
if (!StringUtils.endsWith(fileName, ".csv")) {
fileName += ".csv";
}
response.setContentType("application/csv;charset=gb18030");
try {
response.setHeader("Content-Disposition",
"attachment;filename=\"" + new String(fileName.getBytes(), "ISO8859-1") + "\"");
} catch (UnsupportedEncodingException e) {
}
}
后面会基于注解的方式处理再写一篇~