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>
數據填充
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);
//queryUser()爲數據獲取的方法
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;
// imports omitted for brevity
public class HomePage extends AbstractExcelView {
protected void buildExcelDocument(Map model,
HSSFWorkbook wb, HttpServletRequest req,
HttpServletResponse resp) throws Exception {
HSSFSheet sheet;
HSSFRow sheetRow;
HSSFCell cell;
// Go to the first sheet
// getSheetAt: only if wb is created from an existing document
// sheet = wb.getSheetAt(0);
sheet = wb.createSheet("Spring");
sheet.setDefaultColumnWidth((short) 12);
// write a text at A1
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));
}
}
}
我們可以看到上面的例子中,我們需要對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();
}
}
請求處理
@RequestMapping(value = "/test")
public ModelAndView export() {
Map<String, Object> model = new HashMap<>();
model.put("report_year", 2015);
model.put("report_month", 8);
//queryUser()爲數據獲取的方法
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的格式問題
- 數據遍歷時,集合爲空問題