问题描述:项目中导出execl数据量非常大,导致了页面长时间得不到响应而崩溃掉了,所以导出execl失败!
处理方案:前端采用定时刷新+进度条方式,后端导出采用缓存线程实现导出,导出改用每次请求后端直接返回进度条数值,开启一个线程让它去执行查询与导出操作。当导出执行完成将进度条写成100返回给前端,前端判断100后关闭进度条加载后端一个下载接口,将数据写出到浏览器
代码参考:
后端代码参考:
/**
* 获取进度查询
*
* @param uuid
* @return
*/
@RequestMapping(value = "/progress", method = RequestMethod.POST)
public @ResponseBody Result progress(@RequestParam String uuid) {
Result result = new Result();
result.setData(cacheManager.get(uuid));
result.setSuccess(true);
return result;
}
/**
* 获取进度查询
*
* @param uuid
* @return
*/
@RequestMapping(value = "/progress", method = RequestMethod.POST)
public @ResponseBody Result progress(@RequestParam String uuid) {
Result result = new Result();
result.setData(cacheManager.get(uuid));
result.setSuccess(true);
return result;
}
/**
* 导出
*
* @param request
* @param response
* @return
*/
@SuppressWarnings({ "static-access", "unchecked" })
@RequestMapping(value = "/excelExport", method = RequestMethod.POST)
public @ResponseBody Result exportData(@RequestParam String exportdata,
HttpServletRequest request, HttpServletResponse response) {
Result result = new Result();
String uuid = UUID.randomUUID().toString();
result.setData(uuid);
cacheManager.setex(uuid, 0, 600);
executor.submit(new Runnable() {
@Override
public void run() {
try {
Map> exportMap = new LinkedHashMap>();
PageVO pageVO = JSONObject.parseObject(exportdata,
PageVO.class);
if (pageVO.getSearchParams() == null) {
ExceptionUtils.wrapBusinessException("当前参数数据有误");
}
List testvos = resultMapper
.getTestResultList(pageVO.getSearchParams());
cacheManager.setex(uuid, 7, 600);
for (TestResultVO vo : testvos) {
List resultVOs = vo.getResults();
StringBuffer sb = new StringBuffer(
"{'sampleno':'样品编号','samplename':'样品名称','sampledatestr':'取样日期','uploadtime':'上传时间','batch':'批次','furnaceno':'炉号','furnacetimes':'炉次'");
if (vo.getSampledate() != null) {
vo.setSampledatestr(new SimpleDateFormat(
"yyyy-MM-dd").format(vo.getSampledate()));// 将取样日期转化为yyyy-MM-dd格式导出
}
if (resultVOs != null && resultVOs.size() > 0) {
Field fields[] = vo.getClass().getDeclaredFields();
for (int i = 0; i < resultVOs.size(); i++) {
if (i == resultVOs.size() - 1) {
sb.append(",'element")
.append(i + 1)
.append("':'")
.append(resultVOs.get(i)
.getItemname()
+ "("
+ resultVOs.get(i)
.getMeasdocname()
+ ")").append("'}");
} else {
sb.append(",'element")
.append(i + 1)
.append("':'")
.append(resultVOs.get(i)
.getItemname()
+ "("
+ resultVOs.get(i)
.getMeasdocname()
+ ")").append("'");
}
// 将子表元素值反射到主表自定义字段,以便导出使用
for (Field field : fields) {
String lastzf = null;
if (i > 8) {// 将子表元素根据下标+1与主表截取最后两位相同的赋值
lastzf = field.getName().substring(
field.getName().length() - 2);
} else {// 将子表元素根据下标+1与主表截取最后一位相同的赋值
lastzf = field.getName().substring(
field.getName().length() - 1);
}
if (NumberUtils.isDigits(lastzf)) {// 判断该类型是否为整数字符串
if (Integer.valueOf(lastzf) == i + 1) {
field.setAccessible(true);
field.set(vo, resultVOs.get(i)
.getConfirmvalue());
field.setAccessible(false);
}
}
}
}
} else {
sb.append("}");
}
List list = new ArrayList();
list.add(vo);
Boolean falg = true;// 这段逻辑处理不同元素名称,相同元素个数的情况
for (Map.Entry> enMap : exportMap
.entrySet()) {
if (enMap.getKey().contains(sb.toString())) {
falg = false;
enMap.getValue().addAll(list);
}
}
if (falg) {
exportMap.put(sb.toString(), list);
}
}
// }
// 获取浏览器信息,对文件名进行重新编码
String fileName = "化验结果查询"+uuid+".xlsx";
File directory = new File("");// 参数为空
String courseFile = directory.getCanonicalPath();
isDirExist(courseFile + "/export");
String path = courseFile
+ "/export/" + fileName;
OutputStream os = new FileOutputStream(path);
ExcelExportImportUtils.ListtoExecl(exportMap, os,uuid);
//因为分布式原因将流转成二进制存入缓存,进度条100时直接取缓存值
FileInputStream input = new FileInputStream(path);
byte[] b = InputStreamToByte(input);
cacheManager.setex(qcTestResultURL+uuid,b, 600);
cacheManager.setex(uuid, 100, 600);
File file = new File(path);
input.close();
//删除服务器文件
file.delete();
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();