Formatting of exporting Excel using poi in Java

Posted by gin on Tue, 18 Jan 2022 07:41:17 +0100

Recently, I received a request. The customer was not satisfied with the csv file originally exported and wanted to export an excel file. Don't you just export Excel files? It's a little fun, so you're full of confidence. Pick up the exported code from the Internet, a CV method, and get it done! The code is as follows:

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.usermodel.*;

import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class ExcelUtils {

    // New Excel file suffix
    private static final String EXCEL_SUFFIX = ".xlsx";

    /**
     * Export core implementation
     *
     * @param fileName
     * @param headers
     * @param dataList
     * @return XSSFWorkbook
     */
    @Deprecated
    private static XSSFWorkbook writeDataToWorkbook(String fileName, List<String> headers, List<Map<String, Object>> dataList) {
        // Create a workbook
        XSSFWorkbook workbook = new XSSFWorkbook();
        try {
            // Create a worksheet
            XSSFSheet sheet = workbook.createSheet(fileName);

            // Format header font
            XSSFFont headersFont = workbook.createFont();
            headersFont.setColor(new XSSFColor(java.awt.Color.DARK_GRAY));
            headersFont.setFontHeightInPoints((short) 14);
            headersFont.setBold(true);

            // Format body font
            XSSFFont dataSetFont = workbook.createFont();
            dataSetFont.setColor(new XSSFColor(java.awt.Color.BLACK));
            dataSetFont.setBold(false);

            // Create header style
            XSSFCellStyle headersStyle = workbook.createCellStyle();
            headersStyle.setBorderTop(BorderStyle.THIN);
            headersStyle.setBorderBottom(BorderStyle.THIN);
            headersStyle.setBorderLeft(BorderStyle.THIN);
            headersStyle.setBorderRight(BorderStyle.THIN);
            headersStyle.setFont(headersFont);
            // Header content alignment: Center
            headersStyle.setAlignment(HorizontalAlignment.CENTER);

            // Create text style
            XSSFCellStyle textStyle = workbook.createCellStyle();
            textStyle.setBorderBottom(BorderStyle.THIN);
            textStyle.setBorderRight(BorderStyle.THIN);
            textStyle.setBorderLeft(BorderStyle.THIN);
            textStyle.setFont(dataSetFont);
            // Data content alignment: left
            textStyle.setAlignment(HorizontalAlignment.LEFT);

            // Create a number style
            XSSFCellStyle numeralStyle = workbook.createCellStyle();
            numeralStyle.setBorderBottom(BorderStyle.THIN);
            numeralStyle.setBorderRight(BorderStyle.THIN);
            numeralStyle.setBorderLeft(BorderStyle.THIN);
            numeralStyle.setFont(dataSetFont);
            // Data content alignment: right
            numeralStyle.setAlignment(HorizontalAlignment.RIGHT);

            // Format data here
            XSSFDataFormat df = workbook.createDataFormat();

            int index = 0;
            // Create and style headers
            XSSFRow row = sheet.createRow(index);
            for (int i = 0; i < headers.size(); i++) {
                sheet.setColumnWidth(i, 20 * 256);
                XSSFCell cell = row.createCell(i);
                cell.setCellStyle(headersStyle);
                XSSFRichTextString text = new XSSFRichTextString(headers.get(i));
                cell.setCellValue(text);
            }
            // Export body data and set its style
            for (Map<String, Object> data : dataList) {
                index++;
                row = sheet.createRow(index);
                int column = 0;
                for (String key : data.keySet()) {
                    XSSFCell cell = row.createCell(column++);
                    Object value = data.get(key);
                    if (value == null) {
                        continue;
                    }

                    String dataType = value.getClass().getName();
                    if (dataType.endsWith("BigDecimal") || dataType.endsWith("Double")) {
                        // Number format with decimal point
                        cell.setCellStyle(numeralStyle);
                        numeralStyle.setDataFormat(df.getFormat("0.00"));//Keep two decimal places
                        cell.setCellValue(Double.parseDouble(value.toString()));
                    } else if (dataType.endsWith("Integer") || dataType.endsWith("Long")) {
                        // Integer numeric format
                        cell.setCellStyle(numeralStyle);
                        numeralStyle.setDataFormat(df.getFormat("General"));//The data format is conventional
                        cell.setCellValue(Double.parseDouble(value.toString()));
                    } else if (dataType.endsWith("Date")) {
                        //Date to string
                        cell.setCellStyle(textStyle);
                        cell.setCellValue(date2Str((Date) value, "yyyy-MM-dd HH:mm:ss"));
                    } else {
                        // Text format
                        cell.setCellStyle(textStyle);
                        cell.setCellValue(value.toString());
                    }
                }
            }
        } catch (Exception e) {
            log.error("writeDataToWorkbook error, ", e);
        }
        return workbook;
    }

    /**
     * Test class
     */
    public static void main(String[] args) {
        String filename = date2Str(new Date(), "yyyyMMddHHmmss");
        List<String> headers = Arrays.asList("Customer number", "cell-phone number", "full name", "Creation time", "Account balance", "Account balance 1",  "Account balance 2", "Age");
        List<Map<String, Object>> datas = new ArrayList<>();
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("id", 123);
        map.put("mobile", "0833344545");
        map.put("name", "jfdkdb ft#E@");
        map.put("time", new Date());
        map.put("amount", new BigDecimal("34276.8601"));
        map.put("amount1", 34276.8);
        map.put("amount2", 323455.10);
        map.put("days", 24);
        datas.add(map);
        XSSFWorkbook wb = writeDataToWorkbook(filename, headers, datas);
        try {
            File file = new File("/Users/test/" + filename + EXCEL_SUFFIX);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            wb.write(fileOutputStream);
            fileOutputStream.close();
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
        System.out.println("export excel " + filename + " succeed!");
    }

    public static String date2Str(Date date, String pattern) {
        if (null == date) return "";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }
}

Run the project and test the wave locally to see the effect:

There seems to be nothing wrong with it.... The decimal places of the balance columns seem to be wrong!

Looking back on the code, I set it. Why didn't it take effect???

So I continued to pick up information on the Internet and tried all kinds of theories:

1. As shown in the figure below with celltype setting, the test effect is the same as the first time, and it fails;

 2. I also guessed whether it was caused by changing to double type, so I changed it to the following figure, and the assignment was in string format:

The test effect is the same as the first time. No, it's worse than the first time. Even if the decimal places are wrong, there is a small green arrow in the upper left corner of the cell, which means that the customer can't directly check the total amount. It fails;

Such a simple function, I actually stuck here, mentality.. It broke....

3. You forced me. I'm going to make a unique move. I process the data myself, so I changed it to this:

Running, the effect is good, the decimal places are right, but the cell is still in text format....

 4. The data formats are all right. The cell format is simple. Just set the input parameters. So easy! Immediately change to the following figure:

Run again and the result is as follows: collapse... Completely collapse.. It's over!

Surrendered.. I decided that the text format should be the text format. If the data format is right, I'm ready to use scheme 3.

Just when I wanted to commit, I suddenly saw that the balance data in result 4 was divided by "," and I wiped it. Isn't this the integer format I set??? I decided to try again. I created a new number format for floating-point data, and the code was changed as follows:

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.xssf.usermodel.*;

import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class ExcelUtils {

    // New Excel file suffix
    private static final String EXCEL_SUFFIX = ".xlsx";

    /**
     * Export core implementation
     *
     * @param fileName
     * @param headers
     * @param dataList
     * @return XSSFWorkbook
     */
    @Deprecated
    private static XSSFWorkbook writeDataToWorkbook(String fileName, List<String> headers, List<Map<String, Object>> dataList) {
        // Create a workbook
        XSSFWorkbook workbook = new XSSFWorkbook();
        try {
            // Create a worksheet
            XSSFSheet sheet = workbook.createSheet(fileName);

            // Format header font
            XSSFFont headersFont = workbook.createFont();
            headersFont.setColor(new XSSFColor(java.awt.Color.DARK_GRAY));
            headersFont.setFontHeightInPoints((short) 14);
            headersFont.setBold(true);

            // Format body font
            XSSFFont dataSetFont = workbook.createFont();
            dataSetFont.setColor(new XSSFColor(java.awt.Color.BLACK));
            dataSetFont.setBold(false);

            // Format data here
            XSSFDataFormat df = workbook.createDataFormat();

            // Create header style
            XSSFCellStyle headersStyle = workbook.createCellStyle();
            headersStyle.setBorderTop(BorderStyle.THIN);
            headersStyle.setBorderBottom(BorderStyle.THIN);
            headersStyle.setBorderLeft(BorderStyle.THIN);
            headersStyle.setBorderRight(BorderStyle.THIN);
            headersStyle.setFont(headersFont);
            // Header content alignment: Center
            headersStyle.setAlignment(HorizontalAlignment.CENTER);

            // Create text style
            XSSFCellStyle textStyle = workbook.createCellStyle();
            textStyle.setBorderBottom(BorderStyle.THIN);
            textStyle.setBorderRight(BorderStyle.THIN);
            textStyle.setBorderLeft(BorderStyle.THIN);
            textStyle.setFont(dataSetFont);
            // Data content alignment: left
            textStyle.setAlignment(HorizontalAlignment.LEFT);

            // Create floating point number style
            XSSFCellStyle floatStyle = workbook.createCellStyle();
            floatStyle.setBorderBottom(BorderStyle.THIN);
            floatStyle.setBorderRight(BorderStyle.THIN);
            floatStyle.setBorderLeft(BorderStyle.THIN);
            floatStyle.setAlignment(HorizontalAlignment.RIGHT);
            floatStyle.setFont(dataSetFont);
            floatStyle.setDataFormat(df.getFormat("#,##0.00"));

            // Create an integer number style
            XSSFCellStyle integerStyle = workbook.createCellStyle();
            integerStyle.setBorderBottom(BorderStyle.THIN);
            integerStyle.setBorderRight(BorderStyle.THIN);
            integerStyle.setBorderLeft(BorderStyle.THIN);
            integerStyle.setAlignment(HorizontalAlignment.RIGHT);
            integerStyle.setFont(dataSetFont);
            integerStyle.setDataFormat(df.getFormat("0"));

            int index = 0;
            // Create and style headers
            XSSFRow row = sheet.createRow(index);
            for (int i = 0; i < headers.size(); i++) {
                sheet.setColumnWidth(i, 20 * 256);
                XSSFCell cell = row.createCell(i);
                cell.setCellStyle(headersStyle);
                XSSFRichTextString text = new XSSFRichTextString(headers.get(i));
                cell.setCellValue(text);
            }
            // Export body data and set its style
            for (Map<String, Object> data : dataList) {
                index++;
                row = sheet.createRow(index);
                int column = 0;
                for (String key : data.keySet()) {
                    XSSFCell cell = row.createCell(column++);
                    Object value = data.get(key);
                    if (value == null) {
                        continue;
                    }

                    String dataType = value.getClass().getName();
                    if (dataType.endsWith("BigDecimal") || dataType.endsWith("Double") || dataType.endsWith("Float")) {
                        cell.setCellStyle(floatStyle);  // Number format with decimal point
                        cell.setCellValue(Double.parseDouble(value.toString()));
                    } else if (dataType.endsWith("Integer") || dataType.endsWith("Long")) {
                        cell.setCellStyle(integerStyle);    // Integer numeric format
                        cell.setCellValue(Double.parseDouble(value.toString()));
                    } else if (dataType.endsWith("Date")) {
                        cell.setCellStyle(textStyle);   //Date to string
                        cell.setCellValue(date2Str((Date) value, "yyyy-MM-dd HH:mm:ss"));
                    } else {
                        cell.setCellStyle(textStyle);   // Text format
                        cell.setCellValue(value.toString());
                    }
                }
            }
        } catch (Exception e) {
            log.error("writeDataToWorkbook error, ", e);
        }
        return workbook;
    }

    /**
     * Test class
     */
    public static void main(String[] args) {
        String filename = date2Str(new Date(), "yyyyMMddHHmmss");
        List<String> headers = Arrays.asList("Customer number", "cell-phone number", "full name", "Creation time", "Account balance", "Account balance 1",  "Account balance 2", "Age");
        List<Map<String, Object>> datas = new ArrayList<>();
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("id", 123);
        map.put("mobile", "0833344545");
        map.put("name", "jfdkdb ft#E@");
        map.put("time", new Date());
        map.put("amount", new BigDecimal("34276.8601"));
        map.put("amount1", 34276.8);
        map.put("amount2", 323455.10);
        map.put("days", 24);
        datas.add(map);
        XSSFWorkbook wb = writeDataToWorkbook(filename, headers, datas);
        try {
            File file = new File("/Users/test/" + filename + EXCEL_SUFFIX);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            wb.write(fileOutputStream);
            fileOutputStream.close();
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
        System.out.println("export excel succeed!");
    }

    public static String date2Str(Date date, String pattern) {
        if (null == date) return "";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }
}

The results are as follows:

I'll wipe it. It's really good???!

it turns out to be the case that

XSSFCellStyle integerStyle = workbook.createCellStyle();

The created style can only be assigned once. The subsequent assignment is invalid.

Although I've been tortured by this small problem for nearly a day and my mentality has collapsed several times, it's good that I finally found the reason. It's great to solve the problem. My broken mentality has been reunited and stronger than before...

Topics: Java poi