POI下载excel通用方法

POI下载excel通用方法

最近遇到一个业务是需要下载excel,使用POI,这里记录一下实现过程

1、导包

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

2.公共方法的编写

package com.pingan.esbx.cassandra.util;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;

public class ExcelDonload {
    /**
     * 26个英文字母表
     **/
    public static final String[] letters = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
    /**
     * 创建excel的行数(随描述 标题等的增加而增加)
     **/
    public static int rowNum = NumberUtils.INTEGER_ZERO;
    /**
     * 指定时间格式
     */
    public static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 下载
     * ①tableTitles 与 titlesInfoKey 个数要一致,不能为空
     * ②fileName、title、subtitle、desc均可不传或者传null
     * ③titlesInfoKey 是与tableTitles对应的字段,需与实体类一致
     *
     * @param title         标题
     * @param resultList    数据
     * @param fileName      文件名
     * @param tableTitles   表头
     * @param titlesInfoKey 表头对应的字段
     * @param subtitle      副标题
     * @param desc          描述
     * @param response
     */
    public static <T> void donloadExcel(
            String title,
            List<T> resultList,
            String fileName,
            String[] tableTitles,
            String[] titlesInfoKey,
            String subtitle,
            String[] desc,
            HttpServletResponse response

    ) {
        //1.参数校验
        if (CollectionUtils.isEmpty(resultList)
                || tableTitles.length <= NumberUtils.INTEGER_ZERO) {
            throw new RuntimeException("请求参数不正确!");
        }
        if (resultList.size() > 60000) {
            throw new RuntimeException("到处数据超过6w,不能导出!");
        }
        //2.创建Excel工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet();
        //3.设置excel的 描述、标题、副标题、表头
        setExcelTitle(workbook, sheet, title, tableTitles, subtitle, desc);
        //4.写入数据
        HSSFCellStyle dataStyle = workbook.createCellStyle();
        dataStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        dataStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        for (int i = 0; i < resultList.size(); i++) {
            T clazz = resultList.get(i);
            insertDataToCell(sheet, clazz, titlesInfoKey, dataStyle);
        }
        //5.返回数据量
        File file = returnExcelDataStream(fileName, workbook);
        //6.导出
        buildResponseExcelFile(file, response);

    }

    /**
     * 下载文件流
     *
     * @param file
     * @param response
     */
    private static void buildResponseExcelFile(File file, HttpServletResponse response) {
        InputStream in = null;
        OutputStream out = null;

        try {
            in = new FileInputStream(file.getPath());
            response.reset();
            response.setHeader("Content-disposition", "attachment;filename=" + new String(file.getName().getBytes(), "iso-8859-1"));
            response.setContentType("application/octet-stream");
            response.addHeader("Context-Length", "" + file.length());
            response.setCharacterEncoding("utf-8");

            out = response.getOutputStream();
            int b;
            while ((b = in.read()) != -1) {
                out.write(b);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        file.delete();
    }

    /**
     * 返回文件流
     *
     * @param fileName
     * @param workbook
     * @return
     */
    private static File returnExcelDataStream(String fileName, HSSFWorkbook workbook) {

        File file = null;
        try {

         
            String tempExcelPath = null;
            //创建临时目录
            File tempFile = File.createTempFile("tem", null);
            //这里采用相对路径,防止某些部署是非root权限。而导致拿不到根目录,从而不能下载(不能用绝对路径)
            String temPath = tempFile.getParent() + "/";
            if (StringUtils.isNotBlank(fileName)) {
                tempExcelPath = temPath + File.separator + fileName + ".xls";
            } else {
                tempExcelPath = temPath + File.separator + "report.xls";
            }
            file = new File(tempExcelPath);
            file.deleteOnExit();
            file.createNewFile();
            FileOutputStream fileOutputStream = FileUtils.openOutputStream(file);
            workbook.write(fileOutputStream);
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;

    }


    /**
     * 通过反射获取字段值
     *
     * @param sheet
     * @param clazz
     * @param titlesInfoKey
     * @param <T>
     */
    private static <T> void insertDataToCell(HSSFSheet sheet, T clazz, String[] titlesInfoKey, HSSFCellStyle dataStyle) {
        HSSFRow row = sheet.createRow(rowNum);
        row.setHeight((short) (15 * 20));
        for (int j = 0; j < titlesInfoKey.length; j++) {
            HSSFCell cell = row.createCell(j);
            cell.setCellStyle(dataStyle);
            //反射获取对象的值
            Object fieldValue = getValueByReflect(titlesInfoKey[j], clazz);

            String cellResult = null;
            //时间类型 Date 转换为字符串
            if (fieldValue instanceof Date) {
                cellResult = getStringTime((Date) fieldValue);
            } else {
                cellResult = Objects.isNull(fieldValue) ? "" : String.valueOf(fieldValue);
            }

            cell.setCellValue(cellResult);
        }
        rowNum += NumberUtils.INTEGER_ONE;
    }


    /**
     * 设置excel的 描述、标题、副标题、表头
     *
     * @param workbook
     * @param sheet
     * @param title
     * @param tableTitles
     * @param subtitle
     * @param desc
     */
    private static void setExcelTitle(HSSFWorkbook workbook,
                                      HSSFSheet sheet,
                                      String title,
                                      String[] tableTitles,
                                      String subtitle,
                                      String[] desc) {
        //合并单元格的行数 desc描述的数组项数+(beginTime && endTime)+title标题
        //$A$1:$I$1" 的含义是 第1行的A列到第1行的I列合并
        //计算要合并的行数
        int cellMergedRegionNm = NumberUtils.INTEGER_ZERO;
        //描述的长度
        int descLength = NumberUtils.INTEGER_ZERO;
        //当前要创建的excel的行数
        rowNum = NumberUtils.INTEGER_ZERO;
        if (desc != null) {
            descLength = desc.length;
            cellMergedRegionNm += descLength;
            rowNum += descLength;
        }
        //统计时间栏
        if (StringUtils.isNotBlank(subtitle)) {
            cellMergedRegionNm += NumberUtils.INTEGER_ONE;
        }
        //标题栏
        if (StringUtils.isNotBlank(title)) {
            cellMergedRegionNm += NumberUtils.INTEGER_ONE;
        }
        //获取表头的数量(他决定了合并单元格的列数)
        int tableTitleLength = tableTitles.length;
        //获取表头的长度对应的字母
        String letter = getLetterByNum(tableTitleLength);
        //设置需合并的行数与列数(循环次数是行数 ,$A$1:$I$1中的A代表第一列,I代表列的最后一列)
        for (int i = 0; i < cellMergedRegionNm; i++) {
            sheet.addMergedRegion(CellRangeAddress.valueOf("$A$" + (i + 1) + ":$" + letter + "$" + (i + 1)));
        }
        //设置颜色
        HSSFPalette palette = workbook.getCustomPalette();
        palette.setColorAtIndex((short) 9, (byte) 240, (byte) 240, (byte) 240);
        palette.setColorAtIndex((short) 10, (byte) 255, (byte) 153, (byte) 102);
        palette.setColorAtIndex((short) 11, (byte) 100, (byte) 149, (byte) 137);
        palette.setColorAtIndex((short) 12, (byte) 176, (byte) 196, (byte) 222);
        //字体
        HSSFFont workbookFont = workbook.createFont();
        workbookFont.setFontName("仿宋");
        workbookFont.setFontHeightInPoints((short) 14);
        //字体
        HSSFFont titleFont = workbook.createFont();
        titleFont.setFontName("黑体");
        titleFont.setFontHeightInPoints((short) 18);
        titleFont.setColor(IndexedColors.WHITE.index);
        //单元格的风格1
        HSSFCellStyle descStyleLong = workbook.createCellStyle();
        descStyleLong.setFont(workbookFont);
        descStyleLong.setFillForegroundColor((short) 9);
        descStyleLong.setFillPattern(CellStyle.SOLID_FOREGROUND);
        //单元格的风格2
        HSSFCellStyle descStyleShort = workbook.createCellStyle();
        descStyleShort.setFont(workbookFont);
        descStyleShort.setFillForegroundColor((short) 10);
        descStyleShort.setFillPattern(CellStyle.SOLID_FOREGROUND);
        //单元格的风格3
        HSSFCellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setFont(titleFont);
        titleStyle.setFillForegroundColor((short) 11);
        titleStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
        titleStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        titleStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        //描述:设置描述,没有就不传
        HSSFRow row = null;
        HSSFCell cell = null;
        if (descLength > 0) {
            for (int i = 0; i < descLength; i++) {
                row = sheet.createRow(i);
                row.setHeight((short) (23 * 20));
                cell = row.createCell(0);
                cell.setCellValue(desc[i]);
                if (i >= 4) {
                    row.setHeight((short) (40 * 20));
                    cell.setCellStyle(descStyleShort);
                } else {
                    cell.setCellStyle(descStyleLong);
                }
            }
        }

        //设置标题:没有就不传
        if (StringUtils.isNoneBlank(title)) {

            row = sheet.createRow(rowNum);
            row.setHeight((short) (60 * 20));
            cell = row.createCell(0);
            cell.setCellValue(title);
            cell.setCellStyle(titleStyle);

            rowNum += NumberUtils.INTEGER_ONE;
        }
        HSSFCellStyle styleTimeRange = workbook.createCellStyle();
        styleTimeRange.setFont(titleFont);
        styleTimeRange.setFillForegroundColor((short) 11);
        styleTimeRange.setFillPattern(CellStyle.FINE_DOTS);
        styleTimeRange.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        styleTimeRange.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        //设置时间范围
        if (StringUtils.isNotBlank(subtitle)) {

            row = sheet.createRow(rowNum);
            row.setHeight((short) (30 * 20));
            cell = row.createCell(0);
            cell.setCellValue(subtitle);
            cell.setCellStyle(styleTimeRange);
            rowNum += NumberUtils.INTEGER_ONE;
        }
        //设置表头字体
        HSSFFont tableTitleFont = workbook.createFont();
        tableTitleFont.setFontName("仿宋");
        tableTitleFont.setFontHeightInPoints((short) 14);
        tableTitleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        //表头风格
        HSSFCellStyle tableTitleStyle = workbook.createCellStyle();
        tableTitleStyle.setFont(tableTitleFont);
        tableTitleStyle.setFillForegroundColor((short) 12);
        tableTitleStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
        tableTitleStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        tableTitleStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        tableTitleStyle.setLeftBorderColor(IndexedColors.WHITE.index);
        tableTitleStyle.setRightBorderColor(IndexedColors.WHITE.index);
        tableTitleStyle.setTopBorderColor(IndexedColors.WHITE.index);
        tableTitleStyle.setBottomBorderColor(IndexedColors.WHITE.index);
        tableTitleStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        tableTitleStyle.setBorderTop(HSSFCellStyle.BORDER_THICK);
        tableTitleStyle.setBorderRight(HSSFCellStyle.BORDER_THICK);
        tableTitleStyle.setBorderBottom(HSSFCellStyle.BORDER_THICK);

        if (tableTitles != null && tableTitles.length > 0) {
            row = sheet.createRow(rowNum);

            row.setHeight((short) (41.2 * 20));

            for (int i = 0; i < tableTitles.length; i++) {
                cell = row.createCell(i);
                String tableTitle = tableTitles[i];
                cell.setCellValue(tableTitle);
                cell.setCellStyle(tableTitleStyle);
                //根据标题长短设置单元格的宽窄
                sheet.setColumnWidth(i, (tableTitle.length() * 5) * 256);

            }
            rowNum += NumberUtils.INTEGER_ONE;
        }
    }

    private static String getLetterByNum(int tableTitleLength) {
        return letters[tableTitleLength - NumberUtils.INTEGER_ONE];
    }

    /**
     * 返回指定时间的指定字符串格式 yyyy-MM-dd HH:mm:ss
     * SimpleDateFormat 线程不安全 所以枷锁
     */
    public synchronized static String getStringTime(Date date) {
        String format = dateFormat.format(date);
        return format;
    }

    /**
     * 通过反射获取字段值(通过get方法)
     *
     * @param fieldName
     * @param t
     * @param <T>
     * @return
     */
    public static <T> Object getValueByReflect(String fieldName, T t) {
        String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        try {
            Method method = t.getClass().getMethod(methodName);
            Object fieldValue = method.invoke(t);
            return fieldValue;
        } catch (Exception e) {
            return null;
        }
    }
}

3.调用示例

@RestController
@RequestMapping("/excel")
public class ExcelController {
    private static final String[] TITLES_NONEXP_INFO_KEY = {
            "time",
            "consumerCompany",
            "consumerSystem",
            "consumerCode",
            "providerCompany",
            "providerSystem",
            "providerCode",
            "failCount",
            "failRatio",
            "totalCount"
    };
    private static final String[] TITLES_NONEXP_INFO = {
            "时  间", "消费方公司", "消费方系统",
            "消费方编码", "服务方公司",
            "服务方系统", "服务方编码", "失败次数", "失败率", "总数"
    };


    @GetMapping("/exportExcel")
    public void exportExcel(HttpServletRequest request, HttpServletResponse response) {
        String title = "INVALID 月报表";
        List<ReportDTO> list = new ArrayList<>();
        String inputParams = "111111";

        ReportDTO reportDTO = new ReportDTO();
        reportDTO.setTime(new Date());
        reportDTO.setConsumerCompany("集团总部");
        reportDTO.setConsumerSystem("文件处理系统");
        reportDTO.setConsumerCode("EIP_DPS");
        reportDTO.setProviderCompany("中国科技");
        reportDTO.setProviderSystem("中国智者统一搜索平台");
        reportDTO.setProviderCode("PA011-ZHIZHE-USP-SE_PZHIZHE_ESG");
        reportDTO.setFailCount(100);
        reportDTO.setFailRatio(0.34);
        reportDTO.setTotalCount(340);

        list.add(reportDTO);
        String fileName = "我的测试";
        String[] desc = {
                "报表中数据排序方法:",
                "1.选中待排序的数据区域",
                "2.excel菜单栏:【开始】->【格式】->【设置单元格】->【对齐】->【文本控制】:取消\"合并单元格\"选项\"",
                "3.excel菜单栏:【开始】->【排序和筛选】->【自定义排序】",
                "查询条件:",
                JSON.toJSONString("这里可以写自己的查询条件")
        };
        String beginTime = "2023-7-6";
        String endTime = "2023-7-7";
        String subtitle = "统计时间范围【" + beginTime + "," + endTime + "】";
        ExcelDonload.donloadExcel(
                title,
                list,
                fileName,
                TITLES_NONEXP_INFO,
                TITLES_NONEXP_INFO_KEY,
                subtitle,
                desc,
                response);

    }
}

4.实体类

@Data
public class ReportDTO implements Serializable {
    private Date time;
    private String consumerCompany;
    private String consumerSystem;
    private String consumerCode;
    private String providerCompany;
    private String providerSystem;
    private String providerCode;
    private Integer failCount;
    private Double failRatio;
    private Integer totalCount;
}

5.下载效果

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是一个使用POI实现的Java Excel处理工具类ExcelUtils。 ```java import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ExcelUtils { /** * 读取Excel文件 * @param filePath 文件路径 * @return 返回List<List<String>>类型的数据 */ public static List<List<String>> readExcel(String filePath) { List<List<String>> result = new ArrayList<List<String>>(); try { FileInputStream fis = new FileInputStream(filePath); XSSFWorkbook workbook = new XSSFWorkbook(fis); XSSFSheet sheet = workbook.getSheetAt(0); Iterator<Row> rowIterator = sheet.rowIterator(); while (rowIterator.hasNext()) { XSSFRow row = (XSSFRow) rowIterator.next(); Iterator<Cell> cellIterator = row.cellIterator(); List<String> rowData = new ArrayList<String>(); while (cellIterator.hasNext()) { XSSFCell cell = (XSSFCell) cellIterator.next(); String value = ""; switch (cell.getCellType()) { case XSSFCell.CELL_TYPE_NUMERIC: value = cell.getRawValue(); break; case XSSFCell.CELL_TYPE_STRING: value = cell.getStringCellValue(); break; } rowData.add(value); } result.add(rowData); } fis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return result; } /** * 写入Excel文件 * @param filePath 文件路径 * @param data 要写入的数据 */ public static void writeExcel(String filePath, List<List<String>> data) { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); for (int i = 0; i < data.size(); i++) { XSSFRow row = sheet.createRow(i); List<String> rowData = data.get(i); for (int j = 0; j < rowData.size(); j++) { XSSFCell cell = row.createCell(j); cell.setCellValue(rowData.get(j)); } } try { FileOutputStream fos = new FileOutputStream(filePath); workbook.write(fos); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } ``` 这个 ExcelUtils 类可以读取和写入 Excel 文件,读取 Excel 文件时返回一个 List<List<String>> 类型的数据,每一行数据用 List<String> 来表示,每一个单元格的数据用 String 类型来表示。写入 Excel 文件时传入一个 List<List<String>> 类型的数据,Excel 的每一行用 List<String> 来表示,每一个单元格的数据用 String 类型来表示。 下面是一个使用 ExcelUtils 类读取和写入 Excel 文件的例子: ```java public class ExcelTest { public static void main(String[] args) { // 读取 Excel 文件 List<List<String>> data = ExcelUtils.readExcel("test.xlsx"); for (List<String> rowData : data) { for (String value : rowData) { System.out.print(value + "\t"); } System.out.println(); } // 写入 Excel 文件 List<List<String>> newData = new ArrayList<List<String>>(); List<String> newRowData = new ArrayList<String>(); newRowData.add("1"); newRowData.add("2"); newRowData.add("3"); newData.add(newRowData); ExcelUtils.writeExcel("newTest.xlsx", newData); } } ``` 这个例子读取了 test.xlsx 文件,并将其打印出来,然后将一行数据写入到 newTest.xlsx 文件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神雕大侠mu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值