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到底孰强孰弱暂未可知。

希望有过研究的同学,分享一些已知的研究成果。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值