Excel导出功能是业务系统比较常见的功能,我们可以使用POI、Jexcel等来进行Excel的操作,然后再结合Spring MVC对两者的支持进行导出。但此方法的不足之处在于我们需要不厌其烦的进行Excel表格的操作。经过一番寻觅,发现了Jxls开源框架,使用模版生成导出文件。
初识Jxls
模版制作
如下为制作好的模版,【A1:D1】处的注解用来标识模版的边界,使用${}来标识我们需要填充的数据。【A4】处理的注解来用遍历一个集合,我们对集合的每个元素取名为item,每个元素的又可以使用${item.属性}来进行获取
包依赖
我们使用Maven来进行包依赖管理
<dependency> <groupId>org.jxls</groupId> <artifactId>jxls</artifactId> <version>2.2.7</version></dependency><dependency> <groupId>org.jxls</groupId> <artifactId>jxls-poi</artifactId> <version>1.0.6</version></dependency><dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.13</version></dependency>
注意
使用Maven的 maven-resources-plugin
插件管理 resources
时,Maven会对模版进行转码处理,因此需要对xls格式的文件进行过滤,使其不处理。
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <configuration> <nonFilteredFileExtensions> <nonFilteredFileExtension>pdf</nonFilteredFileExtension> <nonFilteredFileExtension>swf</nonFilteredFileExtension> <nonFilteredFileExtension>data</nonFilteredFileExtension> <nonFilteredFileExtension>xls</nonFilteredFileExtension> </nonFilteredFileExtensions> </configuration> </plugin> </plugins></build>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
数据填充
try (InputStream is = Demo.class.getClassLoader().getResourceAsStream("template.xls")) { try (OutputStream os = new FileOutputStream("output.xls")) { Context context = new Context(); context.putVar("report_year", 2015); context.putVar("report_month", 8); List<User> userList = queryUser(); context.putVar("users", userList); JxlsHelper.getInstance().processTemplate(is, os, context); } catch (IOException e) { e.printStackTrace(); }} catch (IOException e) { e.printStackTrace();}
效果展示
与Spring MVC结合
Spring提供了 AbstractExcelView
对提供对Excel导出的支持,继承该类的子类仅需要做Excel的处理。我们来看看Spring官网为我们提供的一个示例:
package excel;public class HomePage extends AbstractExcelView { protected void buildExcelDocument(Map model, HSSFWorkbook wb, HttpServletRequest req, HttpServletResponse resp) throws Exception { HSSFSheet sheet; HSSFRow sheetRow; HSSFCell cell; sheet = wb.createSheet("Spring"); sheet.setDefaultColumnWidth((short) 12); cell = getCell(sheet, 0, 0); setText(cell, "Spring-Excel test"); List words = (List) model.get("wordList"); for (int i=0; i < words.size(); i++) { cell = getCell(sheet, 2+i, 0); setText(cell, (String) words.get(i)); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
我们可以看到上面的例子中,我们需要对Excel进行一个个单元格的数据填充,这是一项很烦锁的工作。现在让我们来看下,Jxls与Spring MVC的结合如何优雅的完成Excel的导出。我们依旧使用上面所述的模版。
编写View
我们继承Spring提供的 AbstractView
抽象类。
import org.jxls.common.Context;import org.jxls.util.JxlsHelper;import org.springframework.web.servlet.view.AbstractView;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.util.Map;public class JxlsExcelView extends AbstractView { private static final String CONTENT_TYPE = "application/vnd.ms-excel"; private String templatePath; private String exportFileName; /** * @param templatePath 模版相对于当前classpath路径 * @param exportFileName 导出文件名 */ public JxlsExcelView(String templatePath, String exportFileName) { this.templatePath = templatePath; if (exportFileName != null) { try { exportFileName = URLEncoder.encode(exportFileName, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } this.exportFileName = exportFileName; setContentType(CONTENT_TYPE); } @Override protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { Context context = new Context(model); response.setContentType(getContentType()); response.setHeader("content-disposition", "attachment;filename=" + exportFileName + ".xls"); ServletOutputStream os = response.getOutputStream(); InputStream is = getClass().getClassLoader().getResourceAsStream(templatePath); JxlsHelper.getInstance().processTemplate(is, os, context); is.close(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
请求处理
@RequestMapping(value = "/test")public ModelAndView export() { Map<String, Object> model = new HashMap<>(); model.put("report_year", 2015); model.put("report_month", 8); List<User> userList = queryUser(); model.put("users", userList); return new ModelAndView(new JxlsExcelView("template.xls","output"), model);}
至此一个完整的Excel导出功能完成。是不是相当的简单及清晰?
相关及其它
其它支持
- 支持
jx:if
语法 - 支持Excel 公式
- Jxls同时还提供了对Excel读取封装
坑
以下为本人遇到过的问题,而本人实际使用的模版又较为复杂,有些问题需要跟踪代码来解决,因为错误提示有时不够友好。
- 数据没办法解析,编写模版时要格外仔细
- 数据遍历时Shift Row的格式问题
- 数据遍历时,集合为空问题