通用生成Excel方法

xu.wang

发布于 2020.03.26 23:59 阅读 2622 评论 0

在多数项目当中都会使用到将数据查询出来并导出到Excel的功能,若是每个Excel导出功能都需要写一个单独方法的话,会使代码重复率过高,且效率不高。

所以,下面我们使用Apache POI以及java的反射功能来造一个轮子来解决这个问题,即使用一个方法解决Excel导出功能。

第一步:在pom中引入POI

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

第二步:直接上代码

package com.jtexplorer.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.VerticalAlignment;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;

/**
 * @author xuwang
 */
@Slf4j
public class ExcelUtil {

    /**
     * 导出excel
     * @param sheetTitle sheet标题(也会在excel的第一行显示)
     * @param nameAndFiledName 字段的标题以及字段对应对象的属性名称,中间用英文':'进行隔开,举例: 姓名:name,列顺序按照list顺序进行显示
     * @param list 对象列表
     * @return 文件流
     *
     */
    public static byte[] objectToExcelFile(String sheetTitle, List<String> nameAndFiledName, List list) {

        //创建excel表
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet(sheetTitle);
        //设置默认行宽
        sheet.setDefaultColumnWidth(20);

        //表头样式(加粗,水平居中,垂直居中)
        HSSFCellStyle cellStyle = wb.createCellStyle();
        //水平居中
        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        //垂直居中
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        //设置边框样式
        //下边框
        cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        //左边框
        cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        //上边框
        cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
        //右边框
        cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);

        HSSFFont fontStyle = wb.createFont();
        fontStyle.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

        cellStyle.setFont(fontStyle);

        //标题样式(加粗,垂直居中)
        HSSFCellStyle cellStyle2 = wb.createCellStyle();
        //垂直居中
        cellStyle2.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle2.setFont(fontStyle);

        //设置边框样式
        //下边框
        cellStyle2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        //左边框
        cellStyle2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        //上边框
        cellStyle2.setBorderTop(HSSFCellStyle.BORDER_THIN);
        //右边框
        cellStyle2.setBorderRight(HSSFCellStyle.BORDER_THIN);

        //字段样式(垂直居中)
        HSSFCellStyle cellStyle3 = wb.createCellStyle();
        //垂直居中
        cellStyle3.setVerticalAlignment(VerticalAlignment.CENTER);

        //设置边框样式
        //下边框
        cellStyle3.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        //左边框
        cellStyle3.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        //上边框
        cellStyle3.setBorderTop(HSSFCellStyle.BORDER_THIN);
        //右边框
        cellStyle3.setBorderRight(HSSFCellStyle.BORDER_THIN);

        //创建表头
        HSSFRow row = sheet.createRow(0);
        row.setHeightInPoints(20); //行高

        HSSFCell cell = row.createCell(0);
        cell.setCellValue(sheetTitle);
        cell.setCellStyle(cellStyle);

        //创建标题
        HSSFRow rowTitle = sheet.createRow(1);
        rowTitle.setHeightInPoints(20);

        HSSFCell hc;
        for (int i = 0; i < nameAndFiledName.size(); i++) {
            hc = rowTitle.createCell(i);
            hc.setCellValue(nameAndFiledName.get(i).split(":")[0]);
            hc.setCellStyle(cellStyle2);
        }

        byte result[] = null;

        ByteArrayOutputStream out = null;

        try {
            //创建表格数据
            Field[] fields;
            int i = 2;
            //循环每行数据
            for (Object obj : list) {

                fields = obj.getClass().getDeclaredFields();

                HSSFRow rowBody = sheet.createRow(i);
                rowBody.setHeightInPoints(20);
                int n = 0;
                //先循环标题,确定显示顺序
                for (int j = 0; j < nameAndFiledName.size(); j++) {
                    //循环对象的属性
                    for (int m = 0; m < fields.length; m++) {
                        //对象属性名
                        String fliedName = fields[m].getName();
                        // 私有属性必须设置访问权限
                        fields[m].setAccessible(true);
                        //获取当前属性的值
                        Object object = fields[m].get(obj);
                        //获取需要显示的属性名
                        String xlsTitle = nameAndFiledName.get(j).split(":")[1];
                        //判断需要显示的字段
                        if(xlsTitle.equals(fliedName)) {
                            hc = rowBody.createCell(n);
                            //只能输出字符串
                            if(object != null) {
                                hc.setCellValue(object.toString());
                            }else {
                                hc.setCellValue("");
                            }
                            hc.setCellStyle(cellStyle3);
                            n++;
                        }
                    }
                }
                i++;
            }

            out = new ByteArrayOutputStream();
            wb.write(out);
            result =  out.toByteArray();
        } catch (Exception ex) {
            log.info(ex.getMessage());
        } finally{
            try {
                if(null != out){
                    out.close();
                }
            } catch (IOException ex) {
                log.info(ex.getMessage());
            } finally{
                try {
                    wb.close();
                } catch (IOException ex) {
                    log.info(ex.getMessage());
                }
            }
        }

        return result;
    }
}

附带一个byte[] 生成文件的方法:

/**
     * bfile 需要转换成文件的byte数组
     * filePath  生成的文件保存路径
     * fileName  生成文件后保存的名称如test.pdf,test.xls等
     */
    public static void byteToFile(byte[] bfile, String filePath,String fileName) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            File dir = new File(filePath);
            boolean isDir = dir.isDirectory();
            // 目录不存在则先建目录
            if (!isDir) {
                try {
                    dir.mkdirs();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            file = new File(filePath + File.separator + fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bfile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

第三步:测试

 @Test
    public void badTypeReportReport() {

        //项目路径
        String realPath = System.getProperty("user.dir")+"/target/Main";
//        String realPath = request.getRealPath("/");
        String fileDir = "/upload/excel/";
        String fileName = System.currentTimeMillis()+"badTypeReport.xls";

        List lifeCycleDTOList = recordService.eventLifeCycle(new EventLifeCycleQuery(),new RowBounds());

        List<String> titleList = new ArrayList<>();
        titleList.add("异常事件:strAudiocontent");
        titleList.add("岗位名称:cellName");
        titleList.add("设备名称:cellDeviceName");
        titleList.add("发生时间:HappenTime");
        titleList.add("响应时间:ResponseTime");
        titleList.add("解除时间:OverTime");
        titleList.add("响应时长(秒):eventResponseTime");
        titleList.add("解除时长(秒):eventOverTime");
        titleList.add("异常总时间(秒):eventTime");
        byte[] file = ExportExcelUtil.objectToExcelFile("异常生命周期",titleList,lifeCycleDTOList);

        if(file == null){
            System.out.println("file is null");
        }
        System.out.println(realPath);
        System.out.println(realPath+fileDir);
        FileUtil.byteToFile(file,realPath+fileDir,fileName);

        System.out.println("excelPath : "+ fileDir+fileName);

    }

excel效果如下:

 

注意,目前版本导出的字段必须是字符串类型,时间等类型的显示格式未做处理;目前时间复杂度为O(m*n*a),执行效率也需要进行优化。接下来我们会一步步的解决这些问题。