Java无模版导出Excel 0基础教程

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
数据可视化DataV,5个大屏 1个月
简介: 经常写数据导出到EXCEL,没有模板的情况下使用POI技术。以此作为记录,以后方便使用。2 工具类样式工具:处理工具Java接口水印工具导出Excel工具类3 测试代码与实际复杂业务不同 在此我们只做模拟ControllerService4 导出测试使用Postman进行接口测试,没接触过Postman的小伙伴可以看我这篇博客Postman导出excel文件保存为文件可以看到导出很成功,包括水印 sheet页名称自适应宽度。还有一些高亮……等功能可以直接搜索使用

0 写在前面

经常写数据导出到EXCEL,没有模板的情况下使用POI技术。以此作为记录,以后方便使用。

1 依赖

         <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>ooxml-schemas</artifactId>
            <version>1.4</version>
        </dependency>

2 工具类

样式工具:

import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
import org.apache.poi.hssf.usermodel.HeaderFooter;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.*;

import java.io.UnsupportedEncodingException;

public class ExcelStyleUtils {
   
   

    /**
     * 生成标题样式
     * @param workbook
     * @return
     */
    public static XSSFCellStyle genTitleStyle(XSSFWorkbook workbook) {
   
   
        // 创建标题样式
        XSSFCellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setWrapText(true);

        // 标题居中,没有边框,所以这里没有设置边框,设置标题文字样式
        XSSFFont titleFont = workbook.createFont();
        // 加粗
        titleFont.setBold(true);
        // 文字尺寸
        titleFont.setFontHeight((short) 15);
        titleFont.setFontHeightInPoints((short) 15);
        style.setFont(titleFont);

        return style;
    }

    /**
     * 生成表头样式
     * @param workbook
     * @return
     */
    public static XSSFCellStyle genTableStyle(XSSFWorkbook workbook) {
   
   
        // 创建表头样式
        XSSFCellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setWrapText(true);
        style.setBorderRight(BorderStyle.THIN);
        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderLeft(BorderStyle.THIN);
        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderTop(BorderStyle.THIN);
        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderBottom(BorderStyle.THIN);
        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        // 设置字体样式
        Font headerFont = workbook.createFont();
        headerFont.setFontName("Arial");
        headerFont.setFontHeightInPoints((short) 10);
        headerFont.setBold(true);
        headerFont.setColor(IndexedColors.WHITE.getIndex());
        style.setFont(headerFont);

        return style;
    }

    /**
     * 创建文本样式
     * @param workbook
     * @return
     */
    public static XSSFCellStyle genContextStyle(XSSFWorkbook workbook) {
   
   
        XSSFCellStyle style = workbook.createCellStyle();
        // 文本水平居中显示
        style.setAlignment(HorizontalAlignment.CENTER);
        // 文本竖直居中显示
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        // 文本自动换行
        style.setWrapText(true);

        //生成Excel表单,需要给文本添加边框样式和颜色
        /*
             CellStyle.BORDER_DOUBLE      双边线
             CellStyle.BORDER_THIN        细边线
             CellStyle.BORDER_MEDIUM      中等边线
             CellStyle.BORDER_DASHED      虚线边线
             CellStyle.BORDER_HAIR        小圆点虚线边线
             CellStyle.BORDER_THICK       粗边线
         */
        // 设置文本边框
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);

        // 设置文本边框颜色
        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());

        // 设置字体样式
        XSSFFont contextFont = workbook.createFont();
        contextFont.setFontName("Arial");
        // 文字尺寸
        contextFont.setFontHeightInPoints((short) 10);
        style.setFont(contextFont);

        return style;
    }

    /**
     * 设置表单,并生成表单
     * @param workbook
     * @param sheetName
     * @return
     */
    public static XSSFSheet genSheet(XSSFWorkbook workbook, String sheetName){
   
   
        // 生成表单
        XSSFSheet sheet = workbook.createSheet(sheetName);
        // 设置表单文本居中
        sheet.setHorizontallyCenter(true);
        sheet.setFitToPage(false);
        // 打印时在底部右边显示文本页信息
        Footer footer = sheet.getFooter();
        footer.setRight( "Page " + HeaderFooter.numPages()+ " Of "+ HeaderFooter.page());
        // 打印时在头部右边显示Excel创建日期信息
        Header header = sheet.getHeader();
        header.setRight("Create Date " + HeaderFooter.date() + " " + HeaderFooter.time());
        // 设置打印方式
        XSSFPrintSetup ps = sheet.getPrintSetup();
        ps.setLandscape(true); // true:横向打印,false:竖向打印 ,因为列数较多,推荐在打印时横向打印
        ps.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE); // 打印尺寸大小设置为A4纸大小
        return sheet;
    }

    /**
     * 自适应宽度处理
     */
    public static void setAutoColumnWidth(XSSFSheet sheet, int maxColumnNum) {
   
   
        try {
   
   
            for (int columnNum = 0; columnNum <= maxColumnNum; columnNum++) {
   
   
                int columnWidth = sheet.getColumnWidth(columnNum) / 256;
                for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
   
   
                    Row currentRow;
                    if (sheet.getRow(rowNum) == null) {
   
   
                        currentRow = sheet.createRow(rowNum);
                    } else {
   
   
                        currentRow = sheet.getRow(rowNum);
                    }
                    if (currentRow.getCell(columnNum) != null) {
   
   
                        Cell currentCell = currentRow.getCell(columnNum);
                        int length = currentCell.toString().getBytes("GBK").length;
                        if (columnWidth < length + 1) {
   
   
                            columnWidth = length + 1;
                        }
                    }
                }
                int maxWith = 128 * 255;
                if (columnWidth * 300 > maxWith) {
   
   
                    sheet.setColumnWidth(columnNum, maxWith);
                } else {
   
   
                    sheet.setColumnWidth(columnNum, columnWidth * 300);
                }
            }
        } catch (UnsupportedEncodingException e) {
   
   
            e.printStackTrace();
        }
    }

    /**
     * 设置某些列的值只能sheet中某列输入预制的数据,显示下拉框.
     *
     * @param sheet     模板sheet页(需要设置下拉框的sheet)
     * @param sheetName 隐藏的sheet页,用于存放下拉框的值 (下拉框值对应一列)
     * @param lastRow   存放下拉框值的最后一行
     * @param col       存放下拉框值的列名 "A"
     * @param firstRow  添加下拉框对应开始行
     * @param endRow    添加下拉框对应结束行
     * @param firstCol  添加下拉框对应开始列
     * @param endCol    添加下拉框对应结束列
     * @return XSSFSheet 设置好的sheet.
     */
    public static XSSFSheet setXSSFValidation(XSSFSheet sheet, String sheetName, int lastRow, String col, int firstRow, int endRow, int firstCol, int endCol) {
   
   
        // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);

        // 下拉框列
        String cell = sheetName + "!$" + col + "$2:$" + col + "$" + lastRow;

        // 创建验证对象
        DataValidationHelper helper = sheet.getDataValidationHelper();
        DataValidationConstraint constraint = helper.createFormulaListConstraint(cell);

        // 这句话是关键 引用ShtDict的单元格
        DataValidation dataValidate = helper.createValidation(constraint, regions);
        dataValidate.setSuppressDropDownArrow(true);
        dataValidate.createErrorBox("提示", "请输入规定范围内容");
        dataValidate.setShowErrorBox(true);
        sheet.addValidationData(dataValidate);
        return sheet;
    }

}

处理工具Java接口

import org.apache.poi.ss.usermodel.HorizontalAlignment;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SimpleExcel {
   
   

    /**
     * 导出到Excel中的名字
     */
    String labelName() default "";

    /**
     * 自定义日期格式, 如: yyyy-MM-dd
     */
    String dateFormat() default "";

    /**
     * 导出数据样式, 居中:左对齐..
     */
    HorizontalAlignment alignStyle() default HorizontalAlignment.CENTER;

}

水印工具

/**
 * Excel 添加水印。支持 SXSSFWorkbook 和 XSSFWorkbook 模式
 */
public class WaterMarkUtil {
   
   

    /**
     * Excel 导出添加水印
     * @param workbook ExcelWorkbook
     */
    public static void insertWaterMarkTextToXlsx(Workbook workbook, String waterMarkText) throws IOException {
   
   
        // 根据工作博类型两种方式添加水印
        if (workbook instanceof SXSSFWorkbook) {
   
   
            insertWaterMarkTextToXlsx((SXSSFWorkbook) workbook, waterMarkText);
        } else if (workbook instanceof XSSFWorkbook) {
   
   
            insertWaterMarkTextToXlsx((XSSFWorkbook) workbook, waterMarkText);
        }
        //throw new RemoteException("HSSFWorkbook 模式不支持 Excel 水印");
    }


    /**
     * 给 Excel 添加水印
     * @param workbook      SXSSFWorkbook
     * @param waterMarkText 水印文字内容
     */
    public static void insertWaterMarkTextToXlsx(SXSSFWorkbook workbook, String waterMarkText) throws IOException {
   
   
        BufferedImage image = createWatermarkImage(waterMarkText);
        ByteArrayOutputStream imageOs = new ByteArrayOutputStream();
        ImageIO.write(image, "png", imageOs);
        int pictureIdx = workbook.addPicture(imageOs.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG);
        XSSFPictureData pictureData = (XSSFPictureData) workbook.getAllPictures().get(pictureIdx);
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
   
   //获取每个Sheet表
            SXSSFSheet sheet = workbook.getSheetAt(i);
            //这里由于 SXSSFSheet 没有 getCTWorksheet() 方法,通过反射取出 _sh 属性
            XSSFSheet shReflect = (XSSFSheet) ReflectUtil.getFieldValue(sheet, "_sh");
            PackagePartName ppn = pictureData.getPackagePart().getPartName();
            String relType = XSSFRelation.IMAGES.getRelation();
            PackageRelationship pr = shReflect.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
            shReflect.getCTWorksheet().addNewPicture().setId(pr.getId());
        }
    }


    /**
     * 给 Excel 添加水印
     * @param workbook      XSSFWorkbook
     * @param waterMarkText 水印文字内容
     */
    public static void insertWaterMarkTextToXlsx(XSSFWorkbook workbook, String waterMarkText) throws IOException {
   
   
        BufferedImage image = createWatermarkImage(waterMarkText);
        ByteArrayOutputStream imageOs = new ByteArrayOutputStream();
        ImageIO.write(image, "png", imageOs);
        int pictureIdx = workbook.addPicture(imageOs.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG);
        XSSFPictureData pictureData = workbook.getAllPictures().get(pictureIdx);
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
   
   //获取每个Sheet表
            XSSFSheet sheet = workbook.getSheetAt(i);
            PackagePartName ppn = pictureData.getPackagePart().getPartName();
            String relType = XSSFRelation.IMAGES.getRelation();
            PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
            sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
        }
    }

    /**
     * 创建水印图片
     * @param waterMark 水印文字
     */
    public static BufferedImage createWatermarkImage(String waterMark) {
   
   
        String[] textArray = waterMark.split("\n");
        Font font = new Font("microsoft-yahei", Font.PLAIN, 32);
        int width = 500;
        int height = 400;

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 背景透明 开始
        Graphics2D g = image.createGraphics();
        image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g.dispose();
        // 背景透明 结束
        g = image.createGraphics();
        g.setColor(new Color(Color.lightGray.getRGB()));// 设定画笔颜色
        g.setFont(font);// 设置画笔字体
        // g.shear(0.1, -0.26);// 设定倾斜度

        //设置字体平滑
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        //文字从中心开始输入,算出文字宽度,左移动一半的宽度,即居中
        FontMetrics fontMetrics = g.getFontMetrics(font);

        // 水印位置
        int x = width / 2;
        int y = height / 2;
        // 设置水印旋转
        g.rotate(Math.toRadians(-40), x, y);
        for (String s : textArray) {
   
   
            // 文字宽度
            int textWidth = fontMetrics.stringWidth(s);
            g.drawString(s, x - (textWidth / 2), y);// 画出字符串
            y = y + font.getSize();
        }

        g.dispose();// 释放画笔
        return image;
    }

    /**
     * 设置打印的参数
     * @param wb XSSFWorkbook
     */
    public static void setPrintParams(XSSFWorkbook wb) {
   
   
        XSSFSheet sheet = wb.getSheetAt(0);
        XSSFPrintSetup printSetup = sheet.getPrintSetup();
        // 打印方向,true:横向,false:纵向(默认
        printSetup.setLandscape(true);
        //设置A4纸
        printSetup.setPaperSize(XSSFPrintSetup.A4_PAPERSIZE);
        // 将整个工作表打印在一页(缩放),如果行数很多的话,可能会出问题
        // sheet.setAutobreaks(true);
        //将所有的列调整为一页,行数多的话,自动分页
        printSetup.setScale((short) 70);//缩放的百分比,自行调整
        sheet.setAutobreaks(false);
    }

}

导出Excel工具类

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

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Excel的工具类
 */
public class SimpleExcelUtil<T> {
   
   

    /**
     * 工作薄
     */
    private XSSFWorkbook wb;

    /**
     * 工作表
     */
    private XSSFSheet sheet;

    /**
     * 需要导出的数据
     */
    private List<T> exportList;

    /**
     * 对象的class对象
     */
    private Class<T> clazz;

    /**
     * 被选中需要导出的字段名称
     */
    private Map<String, Object> checkedFieldsName;

    /**
     * 被选中需要导出的字段对象
     */
    private List<Field> checkedFields;


    private SimpleExcelUtil() {
   
   
    }

    public SimpleExcelUtil(Class<T> clazz) {
   
   
        this.clazz = clazz;
    }

    /**
     * 导出Excel
     * @param list       导出数据列表
     * @param fieldsName 选中需要导出的字段
     * @param sheetName  sheet页名称
     */
    public void exportExcel(HttpServletResponse response, List<T> list, Map<String, Object> fieldsName, String sheetName, String labelTitle, Boolean isWaterMark, String waterMarkText) {
   
   
        // 初始化数据
        init(list, sheetName, fieldsName);

        // 加入标题数据
        createTopTitleRow(labelTitle);

        // 在标题下方加入表头数据
        createTopRow();

        try {
   
   
            // 在表头下方,添加目标数据
            createOtherRow();

            // 调整自适应列宽
            setAutoColumnWidth(sheet, checkedFields.size());

            // 添加水印
            try {
   
   
                if (isWaterMark) {
   
   
                    WaterMarkUtil.insertWaterMarkTextToXlsx(wb, waterMarkText);
                }
            } catch (Exception e) {
   
   
                throw new Exception("添加水印失败");
            }
        } catch (Exception e) {
   
   
            e.printStackTrace();
        }

        // 生成excel文件并入response
        try {
   
   
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition","attachment;filename=" + new String((labelTitle + ".xlsx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
            wb.write(response.getOutputStream());
        } catch (IOException e) {
   
   
            e.printStackTrace();
        } finally {
   
   
            try {
   
   
                wb.close();
            } catch (IOException e) {
   
   
                e.printStackTrace();
            }
        }
    }

    /**
     * 将数据导出Excel(重载,自定义导出列)
     * @param response
     * @param list 需要导出的数据
     * @param fieldsName 自定义导出字段
     * @param labelTitle 首行标题内容
     */
    public void exportExcel(HttpServletResponse response, List<T> list, Map<String, Object> fieldsName, String labelTitle) {
   
   
        exportExcel(response, list, fieldsName, null, labelTitle, false, null);
    }

    /**
     * 导出含有水印的Excel
     * @param response
     * @param labelTitle 首行标题内容
     * @param list 需要导出的数据
     * @param fieldsName 自定义导出字段
     * @param waterMarkText 水印内容
     */
    public void exportWaterMarkExcel(HttpServletResponse response, List<T> list, Map<String, Object> fieldsName, String labelTitle, String waterMarkText) {
   
   
        exportExcel(response, list, fieldsName, null, labelTitle, true, waterMarkText);
    }

    /**
     * sheet页第一行加入导出的标题数据
     */
    private void createTopTitleRow(String title) {
   
   
        Row row = sheet.createRow(0);
        // 设定固定行高
        row.setHeightInPoints(30);
        Cell cell = row.createCell(0);
        //前端只传一个值合并单元格报错
        if (checkedFields.size() > 1) {
   
   
            // 对标题所处列进行单元格的合并(对应下面导出的字段列数)
            CellRangeAddress region = new CellRangeAddress(0, 0, 0, checkedFields.size() - 1);
            sheet.addMergedRegion(region);
        }

        // 设置单元格样式
        CellStyle style = wb.createCellStyle();
        // 设置单元格水平样式
        style.setAlignment(HorizontalAlignment.CENTER);
        // 设置单元格垂直样式
        style.setVerticalAlignment(VerticalAlignment.CENTER);

        // 设置字体样式
        Font font = wb.createFont();
        font.setBold(true);
        font.setFontHeightInPoints((short) 15);
        font.setFontName("Arial");
        font.setColor(IndexedColors.BLACK.getIndex());
        style.setFont(font);

        cell.setCellValue(title);
        cell.setCellStyle(style);
    }

    /**
     * sheet第二行加入表头数据
     */
    private void createTopRow() {
   
   
        Row row = sheet.createRow(1);
        // 设定固定行高
        row.setHeightInPoints(20);

        for (int index = 0; index < checkedFields.size(); index++) {
   
   
            Cell cell = row.createCell(index);
            cell.setCellValue(checkedFields.get(index).getAnnotation(SimpleExcel.class).labelName());

            // 表头格式
            CellStyle style = wb.createCellStyle();
            style.setBorderRight(BorderStyle.THIN);
            style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
            style.setBorderLeft(BorderStyle.THIN);
            style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
            style.setBorderTop(BorderStyle.THIN);
            style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
            style.setBorderBottom(BorderStyle.THIN);
            style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
            style.setAlignment(HorizontalAlignment.CENTER);
            style.setVerticalAlignment(VerticalAlignment.CENTER);
            style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            Font headerFont = wb.createFont();
            headerFont.setFontName("Arial");
            headerFont.setFontHeightInPoints((short) 10);
            headerFont.setBold(true);
            headerFont.setColor(IndexedColors.WHITE.getIndex());
            style.setFont(headerFont);

            cell.setCellStyle(style);
        }
    }

    /**
     * 添加导出数据
     */
    private void createOtherRow() throws IllegalAccessException {
   
   
        // 导出数据格式
        CellStyle style = wb.createCellStyle();
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderRight(BorderStyle.THIN);
        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderLeft(BorderStyle.THIN);
        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderTop(BorderStyle.THIN);
        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderBottom(BorderStyle.THIN);
        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        Font dataFont = wb.createFont();
        dataFont.setFontName("Arial");
        dataFont.setFontHeightInPoints((short) 10);
        style.setFont(dataFont);

        for (int rowNum = 2; rowNum <= exportList.size() + 1; rowNum++) {
   
   
            Row row = sheet.createRow(rowNum);
            row.setHeightInPoints(18);
            T t = exportList.get(rowNum - 2);

            for (int colNum = 0; colNum < checkedFields.size(); colNum++) {
   
   
                Cell cell = row.createCell(colNum);
                Field field = checkedFields.get(colNum);
                field.setAccessible(true);
                // 处理不同单元格字段对应不同样式
                if (colNum != 0) {
   
   
                    CellStyle cStyle = wb.createCellStyle();
                    cStyle.cloneStyleFrom(row.getCell(colNum - 1).getCellStyle());
                    cStyle.setAlignment(checkedFields.get(colNum).getAnnotation(SimpleExcel.class).alignStyle());
                    cell.setCellStyle(cStyle);
                    addCell(cell, field, t);
                    continue;
                }
                // 单元格水平样式自定义
                style.setAlignment(checkedFields.get(colNum).getAnnotation(SimpleExcel.class).alignStyle());
                cell.setCellStyle(style);
                // 单元格设置值
                addCell(cell, field, t);
            }
        }
    }

    /**
     * 单元格中添加数据
     * @param cell  单元格
     * @param field 字段
     * @param t     list中的一条数据
     */
    private void addCell(Cell cell, Field field, T t) throws IllegalAccessException {
   
   
        Class<?> fieldType = field.getType();
        if (String.class == fieldType && field.get(t) != null) {
   
   
            cell.setCellValue((String) field.get(t));
        } else if (((Integer.TYPE == fieldType) || (Integer.class == fieldType)) && field.get(t) != null) {
   
   
            cell.setCellValue((Integer) field.get(t));
        } else if (((Long.TYPE == fieldType) || (Long.class == fieldType)) && field.get(t) != null) {
   
   
            cell.setCellValue((Long) field.get(t));
        } else if (((Double.TYPE == fieldType) || (Double.class == fieldType)) && field.get(t) != null) {
   
   
            cell.setCellValue((Double) field.get(t));
        } else if (((Float.TYPE == fieldType) || (Float.class == fieldType)) && field.get(t) != null) {
   
   
            cell.setCellValue((Float) field.get(t));
        } else if (BigDecimal.class == fieldType && field.get(t) != null) {
   
   
            cell.setCellValue(((BigDecimal) field.get(t)).toString());
        } else if (Date.class == fieldType && field.get(t) != null) {
   
   
            String dateFormat = field.getAnnotation(SimpleExcel.class).dateFormat();
            cell.setCellValue(dateFormat((Date) field.get(t), dateFormat));
        }
    }

    /**
     * 时间格式转换
     * @param date       日期
     * @param dateFormat 日期格式
     * @return
     */
    private String dateFormat(Date date, String dateFormat) {
   
   
        // 默认格式
        if (dateFormat == null || "".equals(dateFormat)) {
   
   
            dateFormat = "yyyy-MM-dd";
        }

        SimpleDateFormat df = new SimpleDateFormat(dateFormat);
        return df.format(date);
    }

    /**
     * 初始化
     */
    public void init(List<T> list, String sheetName, Map<String, Object> fieldsName) {
   
   
        this.exportList = list;

        this.checkedFieldsName = fieldsName;

        // 初始化导出数据
        initExportList();

        // 初始化工作薄
        initWorkbook();

        // 初始化工作表
        initSheet(sheetName == null ? "Sheet1" : sheetName);

        // 初始化待导出的字段
        initFields();
    }

    /**
     * 初始化导出数据
     */
    private void initExportList() {
   
   
        // 防止导出过程中出现空指针
        if (Objects.isNull(this.exportList)) {
   
   
            this.exportList = new ArrayList<>();
        }
    }

    /**
     * 初始化工作簿
     */
    private void initWorkbook() {
   
   
        this.wb = new XSSFWorkbook();
    }

    /**
     * 初始化工作表
     */
    private void initSheet(String sheetName) {
   
   
        this.sheet = wb.createSheet(sheetName);
    }

    /**
     * 初始化checkedFields
     * checkedFields用户选中的字段
     * 1.如果checkedFieldsName没有定义(未自定义导出字段),所有字段全部导出
     * 2.如果checkedFieldsName进行了定义,根据定义字段进行导出
     */
    private void initFields() {
   
   
        // 获取对象所有字段对象
        Field[] fields = clazz.getDeclaredFields();

        // 过滤出checkedFields
        this.checkedFields = Arrays.asList(fields).stream().
                filter(item -> {
   
   
                    if (!Objects.isNull(this.checkedFieldsName)) {
   
   
                        if (item.isAnnotationPresent(SimpleExcel.class)) {
   
   
                            return checkedFieldsName.containsKey(item.getName());
                        }
                    } else {
   
   
                        return item.isAnnotationPresent(SimpleExcel.class);
                    }
                    return false;
                }).collect(Collectors.toList());
    }

    /**
     * 自适应宽度处理
     */
    private static void setAutoColumnWidth(XSSFSheet sheet, int maxColumnNum) {
   
   
        try {
   
   
            for (int columnNum = 0; columnNum <= maxColumnNum; columnNum++) {
   
   
                int columnWidth = sheet.getColumnWidth(columnNum) / 256;
                for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
   
   
                    Row currentRow;
                    if (sheet.getRow(rowNum) == null) {
   
   
                        currentRow = sheet.createRow(rowNum);
                    } else {
   
   
                        currentRow = sheet.getRow(rowNum);
                    }
                    if (currentRow.getCell(columnNum) != null) {
   
   
                        Cell currentCell = currentRow.getCell(columnNum);
                        int length = currentCell.toString().getBytes("GBK").length;
                        if (columnWidth < length + 1) {
   
   
                            columnWidth = length + 1;
                        }
                    }
                }
                int maxWith = 128 * 255;
                if (columnWidth * 300 > maxWith) {
   
   
                    sheet.setColumnWidth(columnNum, maxWith);
                } else {
   
   
                    sheet.setColumnWidth(columnNum, columnWidth * 300);
                }
            }
        } catch (UnsupportedEncodingException e) {
   
   
            e.printStackTrace();
        }
    }

}

3 测试代码

与实际复杂业务不同 在此我们只做模拟

3.1实体User 类

import lombok.Data;

@Data
public class User {
   
   
    // 姓名
    private String name;
    // 性别
    private String sex;
    // 年龄
    private Integer age;
    // 邮箱
    private String email;
    // 生日
    private String birthday;
    // 住址
    private String address;

    public User(String name, String sex, Integer age, String email, String birthday, String address) {
   
   
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.email = email;
        this.birthday = birthday;
        this.address = address;
    }
}

Controller

import com.example.demo17.service.ExcelTestService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("/test")
public class ExcelTestController {
   
   
    @Resource
    private ExcelTestService excelTestService;
    @GetMapping("/export-excel")
    public void export(HttpServletResponse response) {
   
   
        excelTestService.exportExcel(response);
    }


}

Service

import javax.servlet.http.HttpServletResponse;

public interface ExcelTestService {
   
   
    void exportExcel(HttpServletResponse response);
}
import com.example.demo17.demos.web.User;
import com.example.demo17.util.ExcelStyleUtils;
import com.example.demo17.util.WaterMarkUtil;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Classname ExcelTestServiceImpl
 * @Date 2024/7/18 14:30
 * @Created by Yue Teng
 */
@Service("ExcelTestService")
public class ExcelTestServiceImpl implements ExcelTestService{
   
   
    @Override
    public void exportExcel(HttpServletResponse response) {
   
   

        // 模拟数据
        User user1 = new User("岳腾", "男", 23, "ateng1118@163.com", "2001-02-17", "泰山区山东出版(泰山)文创设计产业园");
        User user2 = new User("岳公凯", "男", 23, "fengyexieyang@gmail.com", "2001-03-01", "淄博市高新区仪器仪表产业园");
        User user3 = new User("路舜", "男", 22, "1078550822@qq.com", "2002-06-13", "槐荫区华图教育");
        User user4 = new User("王尊贞", "男", 24, "2323189192@qq.com", "2000-12-25", "历城区中建凤栖第");

        List<User> users = new ArrayList<>();
        users.add(user1);
        users.add(user2);
        users.add(user3);
        users.add(user4);

        // 初始化导出文件名字
        String labelTitle = "人员表.xlsx";
        //设置导出格式
        String excelName = new String(labelTitle.getBytes(), StandardCharsets.ISO_8859_1);
        // 创建工作簿
        XSSFWorkbook excel = new XSSFWorkbook();
        // 绘制第一个sheet -> 人员表
        creatUserSheet(excel,users);


        // 生成excel文件并入response
        try {
   
   
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");

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

            excel.write(response.getOutputStream());
            excel.close();
        } catch (IOException e) {
   
   
            e.printStackTrace();
        }
    }

    /**
     * 绘制sheet
     * @param excel
     * @param users
     */
    private void creatUserSheet(XSSFWorkbook excel , List<User> users) {
   
   

        // 设置sheet名称
        XSSFSheet sheet = excel.createSheet();
        // 此处sheetIndex的参数代表值绘制的第几个sheet页,如果有绘制多个sheet的需求,则0,1,2,3,4……这样创建,不同的sheet页可以复用一个方法或者单独写不同的方法
        excel.setSheetName(0, "人员");
        XSSFCellStyle header = ExcelStyleUtils.genContextStyle(excel);
        header.setFillPattern(FillPatternType.SOLID_FOREGROUND);    //设置填充方案
        header.setFillForegroundColor(IndexedColors.YELLOW.getIndex());  //设置填充颜色

        // 创建标题
        XSSFRow titleRow = sheet.createRow(0);
        XSSFCell titleCell = titleRow.createCell(0);

        // 合并标题单元格 4个参数分别为 起始行 截止行 起始列 截止列
        sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 6));
        titleCell.setCellValue("人员明细");
        // 设置标题样式
        XSSFCellStyle titleStyle = ExcelStyleUtils.genTitleStyle(excel);
        titleCell.setCellStyle(titleStyle);


        // 创建表头1
        XSSFRow tableRow1 = sheet.createRow(2);
        // 创建表头样式
        XSSFCellStyle tableStyle = ExcelStyleUtils.genTableStyle(excel);
        // 组装表头数据
        String[] tableTitleInit = {
   
   "序号", "姓名", "性别", "年龄", "邮箱", "生日" , "住址"};
        for (int i = 0; i < tableTitleInit.length; i++) {
   
   
            XSSFCell tableRowCell = tableRow1.createCell(i);
            tableRowCell.setCellStyle(tableStyle);
            tableRowCell.setCellValue(tableTitleInit[i]);
        }

        // 对以上数据设置自适应宽度
        ExcelStyleUtils.setAutoColumnWidth(sheet, 6);
        // 主数据内容导出
        // 记录行数从表头下方(第四行)开始

        int rowNum = 3;
        // 创建文本样式
        XSSFCellStyle contextStyle = ExcelStyleUtils.genContextStyle(excel);
        for (int i = 0; i < users.size(); i++) {
   
   
            // 创建数据行
            XSSFRow tableRow = sheet.createRow(rowNum);
            // 取导出数据
            User data = users.get(i);
            // 进行逐列单元格塞入数据
            for (int j = 0; j < 7; j++) {
   
   
                XSSFCell rowCell = tableRow.createCell(j);
                rowCell.setCellStyle(contextStyle);
                switch (j) {
   
   
                    case 0:
                        // 序号
                        rowCell.setCellValue(i + 1);
                        break;
                    case 1:
                        // 姓名
                        rowCell.setCellValue(data.getName());
                        break;
                    case 2:
                        // 性别
                        rowCell.setCellValue(data.getSex());
                        break;
                    case 3:
                        // 年龄
                        rowCell.setCellValue(data.getAge());
                        break;
                    case 4:
                        // 邮箱
                        rowCell.setCellValue(data.getEmail());
                        break;
                    case 5:
                        // 生日
                        rowCell.setCellValue(birthdayConvert(data.getBirthday()));
                        break;
                    case 6:
                        // 住址
                        rowCell.setCellValue(data.getAddress());
                        break;
                }

            }
            rowNum++;

        }

        // 对以上数据设置自适应宽度
        ExcelStyleUtils.setAutoColumnWidth(sheet, 7);

        // 添加水印
        try {
   
   
            // 定义水印
            String waterMarkText = "我是水印";
            WaterMarkUtil.insertWaterMarkTextToXlsx(excel, waterMarkText);
        } catch (Exception e) {
   
   
            try {
   
   
                throw new Exception("添加水印失败");
            } catch (Exception ex) {
   
   
                throw new RuntimeException(ex);
            }
        }

    }

    /**
     * 生日转换,只用来演示在上方switch - case 语句内部可以转换数据
     * @param birthday
     * @return
     */
    public String birthdayConvert(String birthday){
   
   


        Date date = null;
        try {
   
   
            date = new SimpleDateFormat("yyyy-MM-dd").parse(birthday);
        } catch (ParseException e) {
   
   
            throw new RuntimeException(e);
        }

        return new SimpleDateFormat("yyyy年MM月dd日").format(date);
    }
}

4 导出测试

使用Postman进行接口测试,没接触过Postman的小伙伴可以看我这篇博客Postman导出excel文件

image.png

保存为文件

image.png

5 写在末尾

可以看到导出很成功,包括水印 sheet页名称自适应宽度。还有一些高亮……等功能可以直接搜索使用

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
相关文章
|
13天前
|
Java API Apache
Java编程如何读取Word文档里的Excel表格,并在保存文本内容时保留表格的样式?
【10月更文挑战第29天】Java编程如何读取Word文档里的Excel表格,并在保存文本内容时保留表格的样式?
66 5
|
24天前
|
缓存 easyexcel Java
Java EasyExcel 导出报内存溢出如何解决
大家好,我是V哥。使用EasyExcel进行大数据量导出时容易导致内存溢出,特别是在导出百万级别的数据时。以下是V哥整理的解决该问题的一些常见方法,包括分批写入、设置合适的JVM内存、减少数据对象的复杂性、关闭自动列宽设置、使用Stream导出以及选择合适的数据导出工具。此外,还介绍了使用Apache POI的SXSSFWorkbook实现百万级别数据量的导出案例,帮助大家更好地应对大数据导出的挑战。欢迎一起讨论!
139 1
|
13天前
|
Java API Apache
|
14天前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
|
14天前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
14天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
|
16天前
|
存储 Java API
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
24 4
|
21天前
|
JavaScript 前端开发 数据处理
Vue导出el-table表格为Excel文件的两种方式
Vue导出el-table表格为Excel文件的两种方式
|
23天前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
61 2
|
8天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。