EXCEL导出引发的思考(上)

本文介绍了一种使用Java反射和泛型技术优化Excel导出的方法,通过抽象类和实现类分离不变与可变部分,实现了多页Excel的灵活导出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   公司给我下发一个关于EXCEL导出的功能,引出了以下的内容。以下内容只进行相互交流学习,欢迎批评指正。

   其实,关于EXCEL导出的功能网上有很多的教程,也可以很快的实现这个功能。如果系统存在多个EXCEL导出呢?是不是会存在大量的重复代码呢?如何将重复的代码与不重复的代码相互隔离,又能很好的调用呢?

  基于上面的问题,如何正确的设计呢?JAVA反射可以获取一个类的字段的值,泛型可以基于一个父类进行扩展,那么可以基于此来 获取相关的sheet头的信息,以及EXCEL的实体信息。实现代码如下:

/**
 * excel导出功能
 * 以反射的方式,实现导出excel。以便后续的复用等
 * 注意:头信息字段与实体信息字段的顺序必须一致,否则会出现数据错乱的问题

 */

public class ExcelUtil {


    /**
     * 每一行数据赋值
     * @param info 实体信息值
     * @param sheet 实体页
     * @param row 行数
     */
    private void createExcleRow(Object info ,final HSSFSheet sheet,int row){

           try {

          // 获取真实的类名
            String className = info.getClass().getName();
            Class clazz = Class.forName(className);
            // 类字段信息
            Field[] fields =  clazz.getDeclaredFields();
            // 创建excel行
            HSSFRow headerRow = sheet.createRow(row);

            for(int i = 0; i < fields.length ; i ++ ){

                Field field =  fields[i];
                field.setAccessible(true);
                String alvue = (String)field.get(info);
                HSSFCell cell = headerRow.createCell(i);
                cell.setCellValue(alvue);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }

    /**
     * 设置excel实体信息
     * @param excelInfo
     * @param sheet
     */
    private  void createExcelInfo(List<? extends Object> excelInfo,final HSSFSheet sheet){

        int size = excelInfo.size() ;
        for(int i = 0 ; i < size ; i ++){
            createExcleRow(excelInfo.get(i),sheet,(i+1));
        }

    }

    /**
     * 单一实体页EXCEl生成方法
     * @param headerInfo EXCEL表头信息
     * @param excelInfo EXCEL实体信息
     * @return 返回excel数据
     */
    public  HSSFWorkbook createSingleSheetExcel(Object headerInfo, List<? extends Object> excelInfo){

         final HSSFWorkbook workbook = new HSSFWorkbook();
        // 创建sheer头行
        HSSFSheet sheet = workbook.createSheet();
        // 设置头信息
        createExcleRow(headerInfo,sheet,0);
        // 设置实体数据
        createExcelInfo(excelInfo,sheet);

        return workbook;
    }
}

其实细想一下,上述代码存在问题。一个EXCEL有可能不只是一个实体页或者需要设置单元格的格式怎么办呢?

根据设计模式的开闭原则,可以将变动的对外开放,对不变的对外关闭,代码如下:

public abstract  class AbstractExcelBuilder {


    /**
     * 每一行数据赋值
     * @param info 实体信息值
     * @param sheet 实体页
     * @param row 行数
     */
    public final void createExcleRow(Object info , final HSSFSheet sheet, int row){

        try {

            // 获取真实的类名
            String className = info.getClass().getName();
            Class clazz = Class.forName(className);
            // 类字段信息
            Field[] fields =  clazz.getDeclaredFields();
            // 创建excel行
            HSSFRow headerRow = sheet.createRow(row);

            for(int i = 0; i < fields.length ; i ++ ){

                Field field =  fields[i];
                field.setAccessible(true);
                String alvue = (String)field.get(info);
                HSSFCell cell = headerRow.createCell(i);
                cell.setCellValue(alvue);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }

    /**
     * 设置excel实体信息
     * @param excelInfo
     * @param sheet
     */
    public abstract  void createExcelInfo(final HSSFSheet sheet,List<? extends Object> excelInfo );


    /**
     * 设置excel格式
     * @param excelInfo
     * @param sheet
     */
    public abstract  void createExcelStyle(final HSSFSheet sheet,List<? extends Object> excelInfo );

    /**
     * 生成EXCEL方法
     * @param headerInfos excel头信息;如果存在多个EXCEL Sheet,该list的顺序,与实际EXCEL的生成顺序一致
     * @param excelInfos EXCEL实体信息
     * @return 返回EXCEL信息
     */
    public HSSFWorkbook createExcel(List<Object> headerInfos,  List<? extends Object> ... excelInfos){


        if(headerInfos.size() != excelInfos.length){

            throw new IllegalArgumentException("参数不正确");
        }

        final HSSFWorkbook workbook = new HSSFWorkbook();
       for(int i = 0 ; i < headerInfos.size() ; i++){

           // 创建sheer头行
           HSSFSheet sheet = workbook.createSheet();
           // 设置头信息
           createExcleRow(headerInfos.get(i),sheet,0);
           // 设置实体数据
           createExcelInfo(sheet,excelInfos[i]);
           // 设置Excel格式
           createExcelInfo(sheet,excelInfos[i]);
       }
        return workbook;
    }

}

 

实现类如下:

**
 * excel单实体页创建类
 */
@Component
public class SingleSheetExcleBuilder  extends  AbstractExcelBuilder{

    /**
     * 设置excel实体信息,单实体页不允许多个excelInfo实体信息。
     * 如果存在多个实体信息,则抛出异常。
     * @param excelInfo 实体页的信息
     * @param sheet 实体页
     */
    @Override
    public void createExcelInfo(HSSFSheet sheet, List<?> excelInfo) {



        for(int i = 0 ; i < excelInfo.size() ; i ++){
            createExcleRow(excelInfo.get(i),sheet,(i+1));
        }
    }

    /**
     * 暂不需要设置EXCEL格式,故不进行设置
     * @param sheet 实体页
     * @param excelInfo excel实体信息
     */
    @Override
    public void createExcelStyle(HSSFSheet sheet, List<?> excelInfo) {
    }

    @Override
    public HSSFWorkbook createExcel(List<Object> headerInfos, List<?>... excelInfo) {
        return super.createExcel(headerInfos, excelInfo);
    }
}

 

留一个问题,这样做数据会不会错乱呢?

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值