Jxls+Spring MVC實現Excel導出

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的格式問題
  • 數據遍歷時,集合爲空問題

源碼

引用

Spring 官方文檔
Jxls 官網文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章