一、分析
原生的poi导出,最麻烦的就是导出excel样式的设置,十分麻烦。于是有一种想法,就是以导入的思路做导出,就像我们知道的那样,导入excel进内存也必然对象化了,那么我们只要替换对应的业务数据不就可以了吗?
正如所想的那样,可以实现的,只是有人做到了,也就是有现成的工具类可以使用,说道本文的主角,那就是jxls-poi.看名字也知道必然依赖poi,没错必须依赖poi,只是poi的很多版本存在兼容的问题,略微有点坑。
jxls是一个简单的、轻量级的excel导出库,使用特定的标记在excel模板文件中来定义输出格式和布局,底层应该是利用反射做的映射,这里本文不针对jxls的具体实现原理做探究,本文重点在于记录一下jxls的使用。(有空再做研究,有空的话或者需要的话)。
jxls-poi的使用相对来说,是比较简单的,但是其功能是比较强大的。最关键的是对jxls的标记语言的熟悉与使用,当然不熟悉也没关系,因为我也不是很熟悉的。本文记录的使用案例是基本对导出excel来说是通用的,多sheet页,当然还没用多行遍历集合数据。重在在使用中进行摸索,不采坑不进步~
二、导出模板
批注的使用
//指定模板的范围
jx:area(lastCell="L56")
//items对导出数据进行遍历,var遍历出的每一项数据,lastCell指定模板的范围,multisheet多sheet的对应sheet名称集合
jx:each(items="aiFormulaResultData", var="data", lastCell="L56" multisheet="aiFormulaResultDataSheetNames")
三、业务代码
@RequestMapping("/downloadExcel.action")
public void downloadExcel(HttpServletRequest request, HttpServletResponse response)throws IOException {
List data =dataService.getData();
List dataSheetNames =new ArrayList<>(data .size());
//sheetName
String templateSheetName1 = ConstVar.SHEET_DATA1;
String templateSheetName2 = ConstVar.SHEET_DATA2;
for (int i =0; i < data.size(); i++) {
dataSheetNames.add((String)data.get(i).get("code"));
}
Map bindDataMap =new HashMap<>();
bindDataMap.put("aiChemicalDataSheetNames", aiChemicalDataSheetNames);
bindDataMap.put("aiChemicalDataList", chemicalData);
//获取获取模板 国际化
String templateFileName = RequestContextUtils.getLocale(request).equals(Locale.SIMPLIFIED_CHINESE) ? ConstVar.AI_EXCEL_CHINESE_NAME : ConstVar.AI_EXCEL_ENGLISH_NAME;
File tempTargetFile =new File(CommonUtil.getGuid() +".xlsx");
InputStream inputStreamClassPath =null;
InputStream inputStream =null;
try {
inputStreamClassPath =new ClassPathResource("downloadTemplateExcel/" + templateFileName).getInputStream();
//读取模板-写入数据-删除模板sheet
JxlsExportTemplateExcelUtils.exportExcelAndDeleteTemplateSheet(inputStreamClassPath, tempTargetFile, bindDataMap, templateSheetName1, templateSheetName2);
inputStream =new FileInputStream(tempTargetFile);
//设置response头信息
response.reset();
String title = CommonUtil.encodingFileName(I18nUtils.getMessage("chemical.pdfTitleName"));
response.setContentType("application/octet-stream");
response.setHeader("Content-Length", String.valueOf(inputStream.available()));
response.setHeader("Content-Disposition","attachment;filename=" + title + CommonUtil.getCurrentDate() +".xlsx");
OutputStream out = response.getOutputStream();
//创建缓冲区
FileCopyUtils.copy(new BufferedInputStream(inputStream),new BufferedOutputStream(out));
}catch (Exception e) {
logger.error("下载EXCEL出现异常 " + CommonUtil.getExceptionDetail(e));
}finally {
if (inputStream !=null) {
inputStream.close();
}
if (inputStreamClassPath !=null) {
inputStreamClassPath.close();
}
if (tempTargetFile !=null && tempTargetFile.exists()) {
tempTargetFile.delete();
}
}
}
四、工具类
JxlsExportTemplateExcelUtils
//对外提供
public static void exportExcelAndDeleteTemplateSheet(InputStream templateFileInputStreamn, File tempTargetFile, Map bindDataMap, String... templateSheetNames)throws FileNotFoundException, IOException {
exportExcel(templateFileInputStreamn, tempTargetFile, bindDataMap, templateSheetNames);
}
//多种重载
private static void exportExcel(InputStream is, File out, Map model, String... sheetNames)throws IOException {
OutputStream os =new FileOutputStream(out);
Context context = PoiTransformer.createInitialContext();
if (model !=null) {
for (Map.Entry entry : model.entrySet()) {
context.putVar(entry.getKey(), entry.getValue());
}
}
JxlsHelper jxlsHelper = JxlsHelper.getInstance();
//必须要这个,否者表格函数统计会错乱
jxlsHelper.getInstance().setUseFastFormulaProcessor(false).processTemplate(context, jxlsHelper.createTransformer(is, os));
//删除对应的模板sheet页
deleteSheet(out, sheetNames);
}
//删除对应的模板sheet页
public static void deleteSheet(File file, String... sheetNames) {
try {
FileInputStream fis =new FileInputStream(file);
XSSFWorkbook wb =new XSSFWorkbook(fis);
fileWrite(file, wb);
//删除Sheet
for (String sheetName : sheetNames) {
wb.removeSheetAt(wb.getSheetIndex(sheetName));
}
fileWrite(file, wb);
fis.close();
}catch (Exception e) {
//e.printStackTrace();
}
}
五、maven依赖
<!--项目中已使用poi,此处排除-->
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-poi</artifactId>
<version>1.1.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--POI-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
六、总结
整体来说,是相对简单的,思路与想法很重要,只要你能想到的,一般就已经有人做到了,而且做得还不错。但是需要在实践中发现问题,解决问题。