SpringMVC+JXLS讓excel匯出更便捷
工作中,我們經常會遇到一些excel匯入,匯出的需求。我們通常可以使用poi等提供的api來處理。但是處理起來,程式碼十分臃腫很不優雅。
不經意的一次,檢視很久之前的程式碼,看到以前一位同事前輩,針對此問題就已經對excel匯出做出了一次比較好的封裝,使用到的技術AbstractView+Jxls,對於jxls,網上有許多資料,不瞭解的同學可以先找些資料瞭解下。
http://jxls.sourceforge.net/getting_started.html
廢話不多說直接上程式碼:
1.controller接收web請求
@RequestMapping("/xls") public ModelAndView xls() { List<PostDiagnoseInfoResponseBean> infoList = homeAppService.getPostDiagnoseInfo("W9432503"); ModelMap modelMap = new ModelMap(); String fileName = "DiagnoseInfo檔案.xls"; modelMap.put("list", infoList); modelMap.put("ExcelExportFileName", fileName); modelMap.put("ExcelTemplateFileName", "diagnose-template.xls"); modelMap.put("fileName", fileName); return new ModelAndView(new JXLSExcelView(), modelMap); }
2.JXLSExcelView整合AbstractView,程式碼如下:
public class JXLSExcelView extends AbstractView { public static final String EXCEL_EXPORT_FILE_NAME = "ExcelExportFileName"; public static final String EXCEL_TEMPLATE_FILE_NAME = "ExcelTemplateFileName"; public static final String EXCEL_SHEET_NAMES = "ExcelSheetNames"; /** The content type for an Excel response */ private static final String CONTENT_TYPE = "application/vnd.ms-excel"; private XLSTransformerExt transformer; /** * Default Constructor. * Sets the content type of the view to "application/vnd.ms-excel". */ public JXLSExcelView() { transformer = new XLSTransformerExt(); setContentType(CONTENT_TYPE); } @Override protected boolean generatesDownloadContent() { return true; } @SuppressWarnings("rawtypes") @Override protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { String fileName = (String)model.get(EXCEL_EXPORT_FILE_NAME); String templateName = (String)model.get(EXCEL_TEMPLATE_FILE_NAME); List newSheetNames = (List)model.get(EXCEL_SHEET_NAMES); response.setHeader("content-disposition","attachment; filename="+new String(fileName.getBytes("gb2312"),"ISO8859-1")); String srcFilePath = "/resources/excel/" + templateName; ServletOutputStream out = response.getOutputStream(); transformer.transformXLS(request.getSession().getServletContext(), srcFilePath, model, out); out.flush(); } }
3.XLSTransformerExt繼承XLSTransformer,程式碼如下:
public class XLSTransformerExt extends XLSTransformer { @SuppressWarnings("rawtypes") public void transformXLS(ServletContext servletContext, String srcFilePath, Map beanParams, OutputStream os) { try { ServletContextResource resource = new ServletContextResource(servletContext, srcFilePath); Workbook workbook = transformXLS(resource.getInputStream(), beanParams); workbook.write(os); } catch (Exception e) { e.printStackTrace(); } } }
4.excel模板
5.maven依賴
<properties>
<jxls.version>1.0</jxls.version>
</properties>
<!-- excel 匯出或讀取 -->
<dependency>
<groupId>net.sf.jxls</groupId>
<artifactId>jxls-core</artifactId>
<version>${jxls.version}</version>
</dependency>
<dependency>
<groupId>net.sf.jxls</groupId>
<artifactId>jxls-reader</artifactId>
<version>${jxls.version}</version>
</dependency>
對於上述的需求,相信應該能滿足大多數的excel匯出需求了。但是相信還是有不少人遇到過這種需求,匯出的excel列是動態變化的,即使是同一張報表匯出,針對不同的人需要匯出不同的列。這種場景下,上述的解決方法就無法滿足需求了。
如何解決這種需求呢,大致的解決思路應該都差不多,無非是接收一個表頭header[]陣列,取值key[]陣列,以及資料list即可,正當磨拳擦掌準備大幹一場的時候,仔細翻閱了jxls的最新版本,發現已經支援博主的類似需求,請查閱:http://jxls.sourceforge.net/samples/dynamic_grid.html,有了這個指導性檔案,實現起來就很簡單了:
1.controller接收web請求
@RequestMapping("/xls2")
public ModelAndView xls2() {
ModelMap modelMap = new ModelMap();
modelMap.put(JXLSExcelViewDynamicColumns.EXCEL_EXPORT_FILE_NAME, "dynamic-columns檔案-20170622.xls");
modelMap.addAttribute(JXLSExcelViewDynamicColumns.EXCEL_TEMPLATE_DATA_NAME, homeAppService.getPostDiagnoseInfo("W9432503"));
modelMap.put(JXLSExcelViewDynamicColumns.EXCEL_TEMPLATE_HEADERS_NAME, new String[]{"模型id", "模型名稱", "因子型別"});
modelMap.put(JXLSExcelViewDynamicColumns.EXCEL_TEMPLATE_INDEXS_NAME, new String[]{"modelId", "modelName", "modelType"});
return new ModelAndView(new JXLSExcelViewDynamicColumns(), modelMap);
}
2.JXLSExcelViewDynamicColumns繼承AbstractView
public class JXLSExcelViewDynamicColumns extends AbstractView {
public static final String EXCEL_EXPORT_FILE_NAME = "ExcelExportFileName";
public static final String EXCEL_TEMPLATE_FILE_NAME = "ExcelTemplateFileName";
public static final String EXCEL_DEFAULT_TEMPLATE_FILE = "dynamic-columns.xls";
/** The content type for an Excel response */
private static final String CONTENT_TYPE = "application/vnd.ms-excel";
public static final String EXCEL_TEMPLATE_HEADERS_NAME = "headers";
public static final String EXCEL_TEMPLATE_INDEXS_NAME = "indexs";
public static final String EXCEL_TEMPLATE_DATA_NAME = "data";
/**
* Default Constructor.
* Sets the content type of the view to "application/vnd.ms-excel".
*/
public JXLSExcelViewDynamicColumns() {
setContentType(CONTENT_TYPE);
}
@Override
protected boolean generatesDownloadContent() {
return true;
}
@SuppressWarnings("rawtypes")
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String fileName = (String)model.get(EXCEL_EXPORT_FILE_NAME);
response.setHeader("content-disposition","attachment; filename="+new String(fileName.getBytes("gb2312"),"ISO8859-1"));
String templateName = model.get(EXCEL_TEMPLATE_FILE_NAME) == null ? EXCEL_DEFAULT_TEMPLATE_FILE : model.get(EXCEL_TEMPLATE_FILE_NAME).toString() ;
String srcFilePath = "/resources/excel/" + templateName;
ServletOutputStream out = response.getOutputStream();
ServletContextResource resource = new ServletContextResource(request.getSession().getServletContext(), srcFilePath);
List headers = Arrays.asList((String[])model.get(EXCEL_TEMPLATE_HEADERS_NAME));
List indexs = Arrays.asList((String[])model.get(EXCEL_TEMPLATE_INDEXS_NAME));
String objectProps = StringUtils.join(indexs,",");
Context context = new Context();
context.putVar(EXCEL_TEMPLATE_HEADERS_NAME, headers);//headers是list
context.putVar(EXCEL_TEMPLATE_DATA_NAME, model.get(EXCEL_TEMPLATE_DATA_NAME));
JxlsHelper.getInstance().processGridTemplate(resource.getInputStream(), out, context,objectProps );//objectProps “a,b,c”字串
out.flush();
}
}
3.excel-template模板
差點忘了,最新版本jxls的maven依賴:
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-poi</artifactId>
<version>1.0.9</version>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-jexcel</artifactId>
<version>1.0.6</version>
</dependency>
未盡事宜
1.對於大資料量的匯出使用分sheet頁匯出,暫時沒有研究。(目前遇到大資料量匯出只是很簡單的增加伺服器記憶體,使得程式儘可能的讀取更多的資料&&保證不存溢位)
2.對於大資料量的匯出效能與poi到底孰強孰弱暫未可知。
希望有過研究的同學,分享一些已知的研究成果。