JAVA POI XSSFWorkbook導出擴展名為xlsx的Excel,附帶weblogic 項目導出Excel文件錯誤的解決方案


  現在很多系統都有導出excel的功能,總結一下自己之前寫的,希望能幫到其他人,這里我用的是XSSFWorkbook,我們項目在winsang 用的Tomcat,LInux上用的weblogic服務器,剛開始win開發完各種導出都沒有問題,但到了linux上就不行了,后面才只知道weblogic會給response寫入一些內容,需要response.reset();或者response.resetBuffer();一下代碼是從前台到后台重點代碼,希望可以幫到有需要的人,如果有問題,希望可以指出來

 

  HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,擴展名是.xls

 

  XSSFWorkbook:是操作Excel2007的版本,擴展名是.xlsx

 

一、前端部分:

  1、html:

<button id="export">導出</button>

  2、javaScript:

$("#export").click(function (e) {
        var startDt = $("#startDd").val();//統計開始時間
        var endDt = $("#endDt").val();//統計結束時間

        //模擬form提交,如果有參數 可以參照這種方式提交
        var export_form = $("<form method='get'>" +
            "<input type='hidden' name='startDd' value='"+startDd+"'/>" +
            "<input type='hidden' name='endDt' value='"+endDt+"'/> </form>");

        export_form.attr("action", "localhost:8080/export/exportExcel");//給form表單添加action
        $(document.body).append(export_form);//追加form表單
        export_form.submit();//提交form
    })  

二、后台代碼

  1、xxxDaoMapper.xml代碼

<!-- LinkedHashMap是有順序的map,按照需要導出字段的順序查詢,導出時直接遍歷 -->
<select id="selectDataList1" resultType="java.util.LinkedHashMap">
    <!-- SQL就不寫了,主要是返回類型 -->
    SELECT * FROM DUAL
</select>

<!-- LinkedHashMap是有順序的map,按照需要導出字段的順序查詢,導出時直接遍歷 -->
<select id="selectDataList2" resultType="java.util.LinkedHashMap">
    <!-- SQL就不寫了,主要是返回類型 -->
    SELECT * FROM DUAL
</select>

  2、xxxDao.java、xxxService.java、xxxserviceImpl.java部分代碼根據業務場景而定,這里就不寫了  

  3、Controller代碼:

@Controller
@RequestMapping(value = "export")
public class ExportExcelController {

    /**
     * @Description 導出表格
     * @Date 2019\8\20
     * @return void
     */
    @RequestMapping(value = "exportExcel")
    public void exportExcel(HttpServletRequest request, HttpServletResponse response, SelectModel selectModel){
        SimpleDateFormat  sdf = new SimpleDateFormat("yyyy年MM月dd日");

        //獲取第一個表格數據
        List<Map<String, Object>> dataList1 = excelService.selectDataList1(selectModel);
        //獲取第二個表格數據
        List<Map<String, Object>> dataList2 = excelService.selectDataList1(selectModel);

        String sheetName1 = "普通表格";
        String sheetName2 = "復雜表格";

        //第一個表格列名
        String[] heads1 = new String[]{"序號", "部門", "姓名", "電話", "年齡"};
        //第二個表格 第一行列名
        String[] heads2a = new String[]{"序號", "部門", "姓名", "電話", "事件"};
        //第二個表格 第二行列名
        String[] heads2b = new String[]{"事件數", "未完成", "已完成", "完成率"};

        //第一個表格 列寬數組
        Integer[] colWidths1 = new Integer[]{3000, 4000, 4000, 4500, 3000};
        //第二個表格列寬數組
        Integer[] colWidths2 = new Integer[]{3000, 4000, 4000, 4500, 3000, 3000, 3000, 3000};

        //第二個表格 需要合並的單元格數組 {"開始行下標, 結束行下標, 開始列下標, 結束列下標",……}
        String[] headNums = new String[]{"2,3,0,0", "2,3,1,", "2,3,2,2", "2,3,3,3", "2,2,4,7"};

        String fileName = "導出文件測試";
        //統計日期范圍
        String date = sdf.format(sdf.format(selectModel.getStartDd()) + "-" + sdf.format(selectModel.getEndDd()));
        try {
            HaiExcelUtils.exportExcelXlsx(request, response, dataList1, dataList2, sheetName1, sheetName2, heads1, heads2a, heads2b, colWidths1, colWidths2, headNums, fileName, date);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  4、ExcelUtils類:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.Map.Entry;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.*;

/**
 * @Description 導出excle工具類
 * @Author Bert
 * @Date 2019\8\20
 */
public class HaiExcelUtils {


    /**
     * @Description 導出多個表格,sheet1 為普通表格,sheet2為復雜表格
     * @Date 2019\8\20
     * @param request
     * @param response
     * @param dataList1 sheet1 數據集合
     * @param dataList2 sheet2 數據集合
     * @param sheetName1 sheet1 名稱
     * @param sheetName2 sheet2 名稱
     * @param colWidths1 sheet1  列寬數組
     * @param colWidths2 sheet2 列寬數組
     * @param heads1 sheet1  表格列名數組
     * @param heads2a sheet2  表格第一行列明數組
     * @param heads2b sheet2  表格第二行列明數組
     * @param headNums sheet2  表格列需要合並的單元格數組
     * @param fileName sheet1  導出文件名稱
     * @param date 時間 格式為: xx年xx月xx日-xx年xx月xx日
     * @return void
     */
    public static void exportExcelXlsx(HttpServletRequest request, HttpServletResponse response,
                                       List<Map<String, Object>> dataList1, List<Map<String, Object>> dataList2,
                                       String sheetName1, String sheetName2,
                                       String[] heads1, String[] heads2a,String[] heads2b,
                                       Integer[] colWidths1, Integer[] colWidths2,
                                       String[] headNums, String fileName,String date) throws Exception {

        ByteArrayInputStream bais = null;
        OutputStream os = null;

        try {
            XSSFWorkbook workbook = new XSSFWorkbook();
            XSSFSheet sheet1 = workbook.createSheet(sheetName1);// 創建一個 普通表格
            XSSFSheet sheet2 = workbook.createSheet(sheetName2);// 創建一個 多行表頭的表格

            // 表頭 標題樣式
            XSSFFont titleFont = workbook.createFont();
            titleFont.setFontName("微軟雅黑");//字體
            titleFont.setFontHeightInPoints((short) 15);// 字體大小
            XSSFCellStyle titleStyle = workbook.createCellStyle();
            titleStyle.setFont(titleFont);
            titleStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);// 左右居中
            titleStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);// 上下居中
            titleStyle.setLocked(true);

            // 表頭 時間樣式
            XSSFFont dateFont = workbook.createFont();
            dateFont.setFontName("宋體");//字體
            dateFont.setFontHeightInPoints((short) 11);// 字體大小
            XSSFCellStyle dateStyle = workbook.createCellStyle();
            dateStyle.setFont(dateFont);
            dateStyle.setAlignment(XSSFCellStyle.ALIGN_LEFT);// 左右 居左
            dateStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);// 上下居中
            dateStyle.setLocked(true);

            // 列名樣式
            XSSFFont headFont = workbook.createFont();
            headFont.setFontName("宋體");//字體
            headFont.setFontHeightInPoints((short) 11);// 字體大小
            XSSFCellStyle headSsyle = workbook.createCellStyle();
            headSsyle.setBorderBottom(XSSFCellStyle.BORDER_THIN); //下邊框
            headSsyle.setBorderLeft(XSSFCellStyle.BORDER_THIN);//左邊框
            headSsyle.setBorderTop(XSSFCellStyle.BORDER_THIN);//上邊框
            headSsyle.setBorderRight(XSSFCellStyle.BORDER_THIN);//右邊框
            headSsyle.setFont(headFont);
            headSsyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);// 左右居中
            headSsyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);// 上下居中
            headSsyle.setLocked(true);

            //普通單元格樣式
            XSSFFont nalFont = workbook.createFont();
            nalFont.setFontName("宋體");
            nalFont.setFontHeightInPoints((short) 11);
            XSSFCellStyle nalStyle = workbook.createCellStyle();
            nalStyle.setBorderBottom(XSSFCellStyle.BORDER_THIN); //下邊框
            nalStyle.setBorderLeft(XSSFCellStyle.BORDER_THIN);//左邊框
            nalStyle.setBorderTop(XSSFCellStyle.BORDER_THIN);//上邊框
            nalStyle.setBorderRight(XSSFCellStyle.BORDER_THIN);//右邊框
            nalStyle.setFont(nalFont);
            nalStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);// 左右居中
            nalStyle.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);// 上下居中
            nalStyle.setWrapText(true); // 設置自動換行
            nalStyle.setLocked(true);

            // sheet1 設置列寬 (第幾列,寬度)
            for (int i = 0; i < colWidths1.length; i++) {
                sheet1.setColumnWidth(i, colWidths1[i]);// 下標 , 寬度
            }
            sheet1.setDefaultRowHeight((short) 12);//設置行高

            // sheet2  設置列寬 (第幾列,寬度)
            for (int i = 0; i < colWidths2.length; i++) {
                sheet2.setColumnWidth(i, colWidths2[i]);// 下標 , 寬度
            }
            sheet2.setDefaultRowHeight((short) 12);//設置行高

            // sheet1 第一行 為 表頭標題 (開始行下標, 結束行下標, 開始列下標, 結束列下標(下標從零開始計算,so 表格列長度 -1))
            sheet1.addMergedRegion(new CellRangeAddress(0, 0, 0, heads1.length - 1));
            XSSFRow row1 = sheet1.createRow(0);//創建一行表格
            row1.setHeight((short) 0x349);//設置高度
            XSSFCell cell1 = row1.createCell(0);//創建單元格
            cell1.setCellStyle(titleStyle);//設置樣式
            saveCellValue(cell1, sheetName1);//設置標題

            // sheet2 第一行 為 表頭標題 (開始行下標, 結束行下標, 開始列下標, 結束列下標(下標從零開始計算,so 表格列長度 -1 - 重疊長度))
            sheet2.addMergedRegion(new CellRangeAddress(0, 0, 0, (heads2a.length + heads2b.length) - 3));
            XSSFRow row2 = sheet1.createRow(0);//創建一行表格
            row2.setHeight((short) 0x349);//設置高度
            XSSFCell cell2 = row1.createCell(0);//創建單元格
            cell2.setCellStyle(titleStyle);//設置樣式
            saveCellValue(cell2, sheetName2);//設置標題

            // sheet1 第二行 統計時間 (開始行下標, 結束行下標, 開始列下標, 結束列下標(下標從零開始計算,so 表格列長度 -1))
            sheet1.addMergedRegion(new CellRangeAddress(1, 1, 0, heads1.length - 1));
            row1 = sheet1.createRow(1);//創建第二行
            row1.setHeight((short) 12);//設置高度
            cell1 = row1.createCell(0);//創建單元格
            cell1.setCellStyle(dateStyle);//設置樣式
            saveCellValue(cell1, "統計日期:" + date);//設置時間

            // sheet2 第二行 統計時間 (開始行下標, 結束行下標, 開始列下標, 結束列下標(下標從零開始計算,so 表格列長度 -1 - 重疊長度))
            sheet2.addMergedRegion(new CellRangeAddress(1, 1, 0, (heads2a.length + heads2b.length) - 3));
            row2 = sheet2.createRow(1);//創建第二行
            row2.setHeight((short) 12);//設置高度
            cell2 = row1.createCell(0);//創建單元格
            cell2.setCellStyle(dateStyle);//設置樣式
            saveCellValue(cell2, "統計日期:" + date);//設置時間


            // sheet1 第三行 表頭列名
            row1 = sheet1.createRow(2);//創建第三行
            for (int i = 0; i < heads1.length; i++) {
                cell1 = row1.createCell(i);
                saveCellValue(cell1, heads1[i]);
                cell1.setCellStyle(headSsyle);
            }

            // sheet2 第三行 表頭列名
            row2 = sheet2.createRow(2);//創建第三行
            for (int i = 0; i < heads2a.length; i++) {
                cell2 = row2.createCell(i);
                saveCellValue(cell2, heads2a[i]);
                cell2.setCellStyle(headSsyle);
            }
//sheet2 復雜表頭 動態合並單元格 for (int i = 0; i < headNums.length; i++) { String[] temp = headNums[i].split(","); Integer firstRow = Integer.parseInt(temp[0]);//開始行 Integer lastRow = Integer.parseInt(temp[1]);// 結束行 Integer firstCol = Integer.parseInt(temp[2]);//開始列 Integer lastCol = Integer.parseInt(temp[3]);//結束列 sheet2.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); } //設置合並單元格的參數並初始化帶邊框的表頭(這樣做可以避免因為合並單元格后有的單元格的邊框顯示不出來) row2 = sheet2.createRow(3); //因為下標從0開始,所以這里表示的是excel中的第四行 for (int i = 0; i < heads2a.length; i++) { cell2 = row2.createCell(i); cell2.setCellStyle(headSsyle); //設置excel中第四行的邊框 if (i > 3 && i < 3) { for (int k = 0; k < heads2b.length; k++) { cell2 = row2.createCell(k + 4);//k + 4 是因為 0-3 前面四個取自heads2a的數組中 saveCellValue(cell2, heads2b[k]); //給excel中第四行的4 …… 7 列賦值 cell2.setCellStyle(headSsyle); //設置excel中第四行的4 …… 7 列的邊框 } } } // sheeet1 普通表格寫入數據 從第三行開始 int rownum1 = 3; if (dataList1 != null && dataList1.size() > 0) { // 遍歷數據生成成功數據Execl for (Map<String, Object> map : dataList1) { row1 = sheet1.createRow(rownum1); int cellnum1 = 0; for (Entry<String, Object> entry : map.entrySet()) { cell1 = row1.createCell(cellnum1); saveCellValue(cell1, String.valueOf(entry.getValue())); cellnum1++; } rownum1++; } } // sheeet2 多行表頭表格 寫入數據 從第四行開始 int rownum2 = 4; if (dataList2 != null && dataList2.size() > 0) { // 遍歷數據生成成功數據Execl for (Map<String, Object> map : dataList2) { row2 = sheet2.createRow(rownum2); int cellnum2 = 0; for (Entry<String, Object> entry : map.entrySet()) { cell2 = row2.createCell(cellnum2); saveCellValue(cell2, String.valueOf(entry.getValue())); cellnum2++; } rownum2++; } } // rownum1 = 4; // if (countList != null && countList.size() > 0) { // // 遍歷數據生成成功數據Execl // for (Map<String, Object> map : countList) { // row1 = sheet1.createRow(rownum1); // int cellnum1 = 0; // for (Entry<String, Object> entry : map.entrySet()) { // cell1 = row1.createCell(cellnum1); // saveCellValue(cell1, String.valueOf(entry.getValue())); // cellnum1++; // } // rownum1++; // } // } //如果項目部署在weblogic 上面,需要增加以下 response.reset(); 因為weblogic會向response寫東西,不重置文件會報錯 response.reset();//tomcat 部署項目可以不用加這行代碼 ByteArrayOutputStream baos = new ByteArrayOutputStream(); workbook.write(baos); response.setContentType("application/x-download;charset=utf-8"); String excelName = new String(( fileName + "(" + date + ")").getBytes("GB2312"), "ISO8859-1") + ".xlsx";//防止中文文件名亂碼 response.addHeader("Content-Disposition", "attachment;filename=" + excelName); os = response.getOutputStream(); bais = new ByteArrayInputStream(baos.toByteArray()); byte[] b = new byte[1024]; while ((bais.read(b)) > 0) { os.write(b); } bais.close(); os.flush(); os.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (null != bais) { IOUtils.closeQuietly(bais); } if (null != os) { IOUtils.closeQuietly(os); } } } /** * @param xssfCell * @return void * @Description 將單元格內容轉為字符串 * @Date 2019\8\20 */ public static String cellToString(XSSFCell xssfCell) { if (null == xssfCell) { return ""; } switch (xssfCell.getCellType()) { case XSSFCell.CELL_TYPE_NUMERIC: // 數字 return String.valueOf(xssfCell.getNumericCellValue()).trim(); case XSSFCell.CELL_TYPE_STRING: // 字符串 return String.valueOf(xssfCell.getStringCellValue()).trim(); case XSSFCell.CELL_TYPE_BOOLEAN: // Boolean return String.valueOf(xssfCell.getBooleanCellValue()).trim(); case XSSFCell.CELL_TYPE_FORMULA: // 公式 return String.valueOf(xssfCell.getCellFormula()).trim(); case XSSFCell.CELL_TYPE_BLANK: // 空值 return ""; case XSSFCell.CELL_TYPE_ERROR: // 故障 return ""; default: return ""; } } private static void saveCellValue(XSSFCell xssfCell, Object object) { if (object == null) { xssfCell.setCellValue(""); } else { saveCellValue(xssfCell, object, null); } } /** * @param xssfCell 1 * @return java.lang.String * @Description 避免cell.setCellValue(checkOrderQmSave.getSellOrderNo ())中參數為空就會報錯 * @Date 2019\8\20 0020 */ private static void saveCellValue(XSSFCell xssfCell, Object object, String format) { if (null == xssfCell) { xssfCell.setCellValue(""); } else { if (object instanceof String) { xssfCell.setCellValue(String.valueOf(object)); } else if (object instanceof Long) { xssfCell.setCellValue(formatNumber((Long) object, "#0")); } else if (object instanceof Double) { xssfCell.setCellValue(formatNumber((Double) object, "#0.00")); } else if (object instanceof Float) { xssfCell.setCellValue(formatNumber((Float) object, "#0.00")); } else if (object instanceof Integer) { xssfCell.setCellValue(formatNumber((Integer) object, "#0")); } else if (object instanceof BigDecimal) { xssfCell.setCellValue(formatNumber((BigDecimal) object, "#0.00")); } else if (object instanceof java.sql.Date) { xssfCell.setCellValue(new SimpleDateFormat(format).format(object)); } else if (object instanceof java.util.Date) { xssfCell.setCellValue(new SimpleDateFormat(format).format(object)); } else { xssfCell.setCellValue(""); } } } /** * @Description number格式化 * @Date 2019\8\20 * @param number 數字 * @param forMat 格式,可帶#,也可不帶# * #0 或者 0 * #0.0 或者 0.0 * #0.00 或者 0.00 * @return java.lang.String */ private static String formatNumber(Number number, String forMat) { if (null == number) //當傳入的number 為Null 返回不帶 #號的格式 return forMat.replace("#", "").replace(".+", "."); else //number格式化 替換多個#為 一個# ,替換 多個. 為一個. return new DecimalFormat(("#" + forMat).replace("#+", "#").replace(".+", ".")).format(number.doubleValue()); } //判斷EXCEL表格高度用 row.setHeight((short) CellUtil.getExcelCellAutoHeight(TAR_VAL_ALL_STRING, 280, 30)); public static float getExcelCellAutoHeight(String str, float defaultRowHeight, int fontCountInline) { int defaultCount = 0; for (int i = 0; i < str.length(); i++) { int ff = getregex(str.substring(i, i + 1)); defaultCount = defaultCount + ff; } if (defaultCount > fontCountInline) { return ((int) (defaultCount / fontCountInline) + 1) * defaultRowHeight;//計算 } else { return defaultRowHeight; } } public static int getregex(String charStr) { if ("".equals(charStr) || charStr == null) { return 1; } // 判斷是否為字母或字符 if (Pattern.compile("^[A-Za-z0-9]+$").matcher(charStr).matches()) { return 1; } // 判斷是否為全角 if (Pattern.compile("[\u4e00-\u9fa5]+$").matcher(charStr).matches()) { return 2; } //全角符號 及中文 if (Pattern.compile("[^x00-xff]").matcher(charStr).matches()) { return 2; } return 1; } }

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM