利用POI導出excel帶下載框

聲明:

研究了好幾天,一開始使用工具類在本地可以導出,部署到服務器上就沒有文件,真是醉了.我把過程寫出來,希望可以讓小夥伴們增加個思路.

 

依賴:

導入導出都可以用,如果嫌少的話,可以去別的小夥伴文章多沾點哈哈

同一的版本
<poi.version>3.15</poi.version>
 
<!-- POI依賴 ,處理EXCEL WORD  PDF-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>${poi.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>stax-api</artifactId>
                    <groupId>stax</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlbeans</groupId>
            <artifactId>xmlbeans</artifactId>
            <version>2.6.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>stax-api</artifactId>
                    <groupId>stax</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- POI依賴 ,處理EXCEL WORD  PDF-->

 

工具類: 

我把整個工具類的代碼都放在裏面了,別閒多,粘貼過去你就能用,我保你的哈哈,實在用不了那也沒轍了哈哈

package com.platform.utils.excel;

import com.platform.utils.RRException;
import com.platform.utils.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.util.*;

/**
 * 導出EXCEL功能包主類
 * 使用POI進行EXCEL導出的功能類。
 * 目前簡單處理,未設置內存優化。 數據量偏大,出現性能問題時再處理。
 *
 * @author lipengjun
 * @email [email protected]
 * @date 2017年10月28日 13:11:27
 */
public class ExcelExport {

    /**
     * EXCEL 2003 擴展名
     */
    public static final String EXCEL03_EXTENSION = ".xls";

    /**
     * EXCEL 2007 擴展名
     */
    public static final String EXCEL07_EXTENSION = ".xls";

    /**
     * 工作表
     */
    private Workbook workBook;

    /**
     * 導出文件名
     */
    private String exportFileName;

    /**
     * 日誌
     */
    private Log logger = LogFactory.getLog(ExcelExport.class);

    /**
     * 默認構造方法。
     * 自動生成工作表。
     */
    public ExcelExport() {

        this("workbook.xlsx");

    }

    /**
     * 指定導出文件名的構造方法
     * 指定導出文件名。 同時根據指定文件名的擴展名確定導出格式是03或是07 。
     * 不帶擴展名默認爲07格式。(POI 07格式支持內存優化)
     *
     * @param exportFileName 要導出的文件名(帶擴展名。不帶擴展名默認爲07)
     */
    public ExcelExport(String exportFileName) {

        if (StringUtils.isNullOrEmpty(exportFileName)) {
            exportFileName = "workbook.xlsx";
        }

        String fileName = exportFileName.toLowerCase();

        // 根據文件名擴展名生成EXCEL格式。
        if (fileName.endsWith(ExcelExport.EXCEL03_EXTENSION)) {
            workBook = new HSSFWorkbook();
        } else if (exportFileName.endsWith(ExcelExport.EXCEL07_EXTENSION)) {
            workBook = new XSSFWorkbook();
        } else {
            workBook = new XSSFWorkbook();
            fileName += ".xlsx";
            // 按正則替換? 處理文件名最後一個字符爲“.” 的問題
            // fileName = fileName.replaceAll("..", ".");
        }

        // 最後按小寫文件名輸出
        this.exportFileName = fileName;
    }

    /**
     * 主要功能: 導出EXCEL到response
     * 注意事項:無
     *
     * @param response HttpServletResponse
     */
    public void export(HttpServletResponse response) {

        // response.setHeader("Content-Disposition","attachment;filename=totalExcel.xls");
        response.reset();
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
        // response.setContentType("text/html;charset=UTF-8");
        // response.setContentType("APPLICATION/*");
        String fileName = null;

        // 處理編碼
        try {

            //modify by ld 2017年4月10日19:04:37 根據瀏覽器編碼文件名
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String userAgent = request.getHeader("User-Agent");
            //針對IE或者以IE爲內核的瀏覽器:
            if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
                fileName = URLEncoder.encode(exportFileName, "UTF-8");
            } else {
                //非IE瀏覽器的處理:
                fileName = new String(exportFileName.getBytes("UTF-8"), "ISO-8859-1");
            }
        } catch (UnsupportedEncodingException e) {

            fileName = "export.xls";
        }

        response.setHeader("Content-Disposition", "attachment;filename="
                + fileName);

        ServletOutputStream output;

        try {
            output = response.getOutputStream();
            workBook.write(output);
            output.flush();
            output.close();
        } catch (IOException e) {
            logger.error("導出文件出錯了", e);
            throw new RRException("文件導出錯誤");
        }

    }

    /**
     * 主要功能: 在EXCEL中添加一個Sheet
     * 注意事項:添加Sheet 並將List<Object[]> 中的數據填充
     *
     * @param sheetName  表單名字
     * @param list       要填充的數據  以Object[] 表示單條記錄
     * @param colCaption 要生成的表頭
     */
    public void addSheetByArray(String sheetName, List<Object[]> list,
                                String[] colCaption) {

        // 創建表單
        Sheet sheet;

        if (StringUtils.isNullOrEmpty(sheetName)) {
            sheet = workBook.createSheet();
        } else {
            sheet = workBook.createSheet(sheetName);
        }

        // 生成標題行 (表頭)
        createCaptionRow(colCaption, sheet);
        // 記錄列數
        int colNum = 0;
        // 從第二行開始
        int startRow = 1;
        for (Object[] obj : list) {

            Row row = sheet.createRow(startRow++);
            int cols = createRowData(row, Arrays.asList(obj));
            row.setHeight((short) 400);
            colNum = colNum > cols ? colNum : cols;
        }

        adjustCellWidth(colNum, startRow, sheet);

    }

    /**
     * 主要功能:在EXCEL中添加一個Sheet
     * 注意事項:添加Sheet 並將List<Object[]> 中的數據填充
     *
     * @param sheetName  表單名字
     * @param list       要填充的數據  以Map<String,Object> 表示單條記錄
     * @param colCaption 要生成的表頭
     */
    public void addSheetByMap(String sheetName, List<Map<String, Object>> list,
                              String[] colCaption) {

        // 創建表單
        Sheet sheet;

        if (StringUtils.isNullOrEmpty(sheetName)) {
            sheet = workBook.createSheet();
        } else {
            sheet = workBook.createSheet(sheetName);
        }

        // 生成標題行 (表頭)
        createCaptionRow(colCaption, sheet);

        int colNum = 0;
        // 轉換數據
        // 從第二行開始
        int startRow = 1;
        for (Map<String, Object> map : list) {
            Row row = sheet.createRow(startRow++);
            int cols = createRowData(row, map.values());
            row.setHeight((short) 400);
            colNum = colNum > cols ? colNum : cols;
        }

        adjustCellWidth(colNum, startRow, sheet);

        // 處理寬度

    }

    /**
     * 主要功能: 判斷fiel
     * 注意事項:無
     *
     * @param name    要判斷的字符
     * @param ignores 要忽略的數組
     * @return 存在返回true
     */
    private boolean isInIgnors(String name, String[] ignores) {

        for (String ignore : ignores) {
            if (name.equals(ignore)) {
                return true;
            }
        }

        return false;

    }

    /**
     * 主要功能: 生成每一行的數據
     * 注意事項:無
     *
     * @param row  要處理的行
     * @param coll 集合類型(List Map.values) 要處理的數據
     * @return int  列數
     */
    private int createRowData(Row row, Collection<Object> coll) {

        int cellNum = 0;
        for (Object obj : coll) {

            // 空值 按照 "" 字符串處理
            if (obj == null) {
                obj = "";
            }
            // 轉換一個字符串值, 以方便判斷
            String strValue = obj.toString();

            // 創建單元格
            Cell cell = row.createCell(cellNum);

            // 根據單元格的類型設置值
            // 公式型(普通BEAN和MAP中暫時並不存在)
            if (strValue.startsWith("FORMULA:")) {

            } else {
                // 處理寬度

                // 設置單元格的值
                setCellValue(cell, obj);

            }

            // 處理下一個單元格
            cellNum++;

        }

        return cellNum;

    }

    /**
     * 主要功能: 設置某單元格的值
     * 注意事項: 同時根據值類型設置樣式
     * TODO: 對數字類型做進一步解析和判斷。 對需要按%顯示的進行處理。 %可以從表頭中獲取?
     * 對於CellType 和CellValue 的設置還需要詳細參考文檔,避免產生不必要的錯誤轉換
     * 日期類型格式以通用格式。 待替換爲全局變量
     * 數字保留小數和顯示百分比格式暫時未設置
     *
     * @param cell 單元格
     * @param obj  原始值( null已轉換爲"" 空字符串)
     */
    private void setCellValue(Cell cell, Object obj) {

        CreationHelper createHelper = workBook.getCreationHelper();
        String strValue = obj.toString();

        // 時間戳類型 要先判斷時間戳類型再判斷時期類型
        if (obj instanceof Timestamp) {
            // 轉換爲Date後賦值
            Date dt = (Timestamp) obj;
            // String value = DateUtil.format(dt, "yyyy-MM-dd HH:mm:ss");
            CellStyle cellStyle = workBook.createCellStyle();
            cellStyle.setDataFormat(createHelper.createDataFormat().getFormat(
                    "yyyy-MM-dd HH:mm:ss"));

            cell.setCellValue(dt);
            cell.setCellStyle(cellStyle);

        }
        // 日期型
        else if (obj instanceof Date) {

            // String value = DateUtil.format((Date)obj, "yyyy-MM-dd");
            // cell.setCellValue(value);

            CellStyle cellStyle = workBook.createCellStyle();
            cellStyle.setDataFormat(createHelper.createDataFormat().getFormat(
                    "yyyy-MM-dd"));

            cell.setCellValue((Date) obj);
            cell.setCellStyle(cellStyle);

        }

        /*
         * 由於數字類型有int、long、double、BigDecimal 多種類型 輸出格式可能要求數字、百分比、保留幾位小數等多種格式. 目前僅按照數字格式輸出
         */
        else if (obj instanceof Integer) {
            cell.setCellType(CellType.NUMERIC);
            DecimalFormat df = new DecimalFormat("0");
            String value = df.format(obj);
            cell.setCellValue(value);

        } else if (obj instanceof Long) {
            cell.setCellType(CellType.NUMERIC);
            DecimalFormat df = new DecimalFormat("0");
            String value = df.format(obj);
            cell.setCellValue(value);
        } else if (obj instanceof Float) {
            cell.setCellType(CellType.NUMERIC);
            DecimalFormat df = new DecimalFormat("0.0000");
            String value = df.format(obj);
            cell.setCellValue(value);
        } else if (obj instanceof Double) {
            cell.setCellType(CellType.NUMERIC);
            DecimalFormat df = new DecimalFormat("0.0000");
            String value = df.format(obj);
            cell.setCellValue(value);

        }
        // BigDecimal
        else if (obj instanceof BigDecimal) {
            cell.setCellType(CellType.STRING);

            cell.setCellValue(strValue);

        }

        // 數字 //數字型要判斷 對於百分比顯示 、單位是萬元等的顯示細節要處理
        // else if (StringUtil.isFloatNumeric(strValue)) {

        // cell.setCellType(CellType.NUMERIC);

        // 暫時未處理BigDecimal 類型的數據,如果有問題,只能使用String
        // cell.setCellValue(Double.valueOf(strValue));

        // modi by zhang @2016年11月14日14:13:11 處理浮點小數格式 暫時無法統一位數
        // DecimalFormat df = new DecimalFormat("0.0000");
        // String whatYourWant = df.format();
        // 按String 方式輸出數字
        // BigDecimal bd = new BigDecimal(strValue);
        // cell.setCellValue(bd.toPlainString());

        // 主要處理小數的位數格式,暫時不好判斷,輸出原值
        // cell.setCellValue(strValue);

        // CellStyle style = workBook.createCellStyle();
        // style.setDataFormat(workBook.createDataFormat().getFormat("0.00%"));

        // }
        // 字符串類型
        else if (obj instanceof String) {
            // modi at 2016年11月14日14:27:51 by zhang
            // 補充設置單元格類型,避免編碼類被當作數字類型
            cell.setCellType(CellType.STRING);
            // end modi

            cell.setCellValue(strValue);

        } else {
            cell.setCellType(CellType.STRING);
            cell.setCellValue(strValue);
        }

    }

    /**
     * 主要功能: 生成EXCEL的第一行表頭
     * 注意事項: 默認按第一行生成表頭。
     *
     * @param colCaption 表頭字符數組
     * @param sheet      表單
     */
    private void createCaptionRow(String[] colCaption, Sheet sheet) {
        // 默認第一行
        Row row = sheet.createRow(0);
        row.setHeight((short) 400);

        if (colCaption == null) {
            return;
        }
        // 按列生成表頭
        for (int i = 0; i < colCaption.length; i++) {
            Cell cell = row.createCell(i);
            cell.setCellStyle(getStyle("title"));
            cell.setCellType(CellType.STRING);
            cell.setCellValue(colCaption[i]);

        }

    }

    /**
     * 主要功能: 調整列寬
     * 注意事項:無
     *
     * @param cols  列數
     * @param rows  行數
     * @param sheet sheet
     */
    private void adjustCellWidth(int cols, int rows, Sheet sheet) {

        int[] cellWidth = new int[cols];

        // 取列中最長的行
        for (int col = 0; col < cols; col++) {
            for (int row = 0; row < rows; row++) {
                Cell cell = sheet.getRow(row).getCell(col);
                String value = getCellValue(cell);
                int length = value.getBytes().length;
                if (length > cellWidth[col]) {
                    cellWidth[col] = length;
                }
            }
        }

        for (int j = 0; j < cellWidth.length; j++) {
            if (cellWidth[j] > 254) {
                cellWidth[j] = 254;
            }

            // 設置列寬度 單位爲 1/256 個字符 設置加10%
            sheet.setColumnWidth(j,
                    cellWidth[j] * 12 > 255 ? (255 * 256 / 10) : (cellWidth[j] * 12 * 256 / 10));
        }

    }

    /**
     * 主要功能: 取單元格的值
     * 注意事項:按數字和字符兩種類型先處理。 BOOLEAN FORMULA 先不處理。 日期格式如何判斷?
     *
     * @param cell 單元格
     * @return 單元格的值
     */
    @SuppressWarnings("deprecation")
    private String getCellValue(Cell cell) {

        String value = "";

        try {
            // 按數字和字符兩種類型先處理。 BOOLEAN FORMULA 先不處理。 日期格式如何判斷?
            switch (cell.getCellTypeEnum()) {
                case NUMERIC:
                    value = cell.getNumericCellValue() + "1111"; // 增加4位的長度
                    // 數字格式包含日期格式,但暫時無法判斷日期格式
                    // 除非使用固定寬度。。。。。。。

                    break;
                case STRING:
                    value = cell.getStringCellValue();
                    break;
                default:
                    break;

            }
        } catch (Exception e) {
            // 不對異常做處理。僅打印到控制檯以供調試
            // 佔不打印
            // e.printStackTrace();
        }

        return value;

    }

    /**
     * 主要功能: 生成表頭樣式(默認樣式)
     * 注意事項:僅生成默認樣式
     *
     * @param type 類型 title 或  data
     * @return CellStyle
     */
    private CellStyle getStyle(String type) {
        CellStyle cs = workBook.createCellStyle();// 創建一個style
        if ("title".equals(type)) {// 表頭樣式
            Font font = workBook.createFont();// 創建一個字體
            // font.setBoldweight(Font.BOLDWEIGHT_BOLD); // 粗體
            font.setBold(true);
            // cs.setAlignment(CellStyle.ALIGN_CENTER);// 水平居中
            cs.setAlignment(HorizontalAlignment.CENTER);
            cs.setFillBackgroundColor(HSSFColor.SKY_BLUE.index);// 設置背景色
            cs.setFont(font);
        }
        return cs;
    }

    /**
     * 取得wb的值
     *
     * @return wb值.
     */
    public Workbook getWorkbook() {
        return workBook;
    }

    /**
     * 設定wb的值
     *
     * @param workBook 設定值
     */
    public void setWorkbook(Workbook workBook) {
        this.workBook = workBook;
    }

    /**
     * 取得exportFileName的值
     *
     * @return exportFileName值.
     */
    public String getExportFileName() {
        return exportFileName;
    }

    /**
     * 設定exportFileName的值
     *
     * @param exportFileName 設定值
     */
    public void setExportFileName(String exportFileName) {
        this.exportFileName = exportFileName;
    }

}

前端代碼:

這個就是比較折磨了,剛開始查閱資料,有用異步的,有用跳轉的,我也用了異步發現這個下載框就是彈不出來,改進後,後端代碼也不用返回值,改成跳轉的了,上代碼

 <i-button type="warning" @click="submit">導出Excel</i-button>


這是我後端需要的參數,使用vue做的,你們正常拼接你們定義的參數就行
 submit: function () {
            location.href = "../black/export?carNo=" + vm.q.carNo + "&createTime=" + vm.q.createTime + "&stopTime=" + vm.q.stopTime
                + "&createMoney=" + vm.q.createMoney + "&stopMoney=" + vm.q.stopMoney + "&num=" + vm.q.num + "&mobile=" + vm.q.mobile;
}

Controller層: 實

體類改成你自己的就ok了

  /**
     * 黑名單導出功能
     */
    @RequestMapping("/export")
    public void exportStudent(HttpServletResponse response, HttpServletRequest request) {

        Map<String, Object> params = new HashMap<>();
        params.put("carNo",request.getParameter("carNo"));
        params.put("createTime",request.getParameter("createTime"));
        params.put("stopTime",request.getParameter("stopTime"));
        params.put("createMoney",request.getParameter("createMoney"));
        params.put("stopMoney",request.getParameter("stopMoney"));
        params.put("num",request.getParameter("num"));
        params.put("mobile",request.getParameter("mobile"));


        String filename = "黑名單列表";

        List<CarBlack> blackList = blackService.queryAllList(params);

        ExcelExport ee1 = new ExcelExport();
        List<Object[]> list1 = new ArrayList<Object[]>();
        List<Object> obj = new ArrayList<Object>();

        for (CarBlack carBlack : blackList) {
            obj.add(carBlack.getId());
            obj.add(carBlack.getCarNo());
            obj.add(carBlack.getDebtSum() / 100);
            obj.add(carBlack.getDebtCount());
            obj.add(carBlack.getCreateTime());
            obj.add(carBlack.getUserName());
            obj.add(carBlack.getMobile());
            list1.add(obj.toArray());
            obj.clear();
        }

        String[] header = new String[]{"編號", "車牌號", "欠費金額(元)", "欠費次數", "欠費生成時間", "車主姓名",
                "手機號碼"};
        ee1.addSheetByArray("黑名單列表", list1, header);

        ee1.export(response);

 

效果:

 

至此完成,呼呼呼  希望可以幫到小夥伴們

 

 

 

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