zoukankan      html  css  js  c++  java
  • 重构:以Java POI 导出EXCEL为例2

    前言

    上一篇博文已经将一些对象抽象成成员变量以及将一些代码块提炼成函数。这一节将会继续重构原有的代码,将一些函数抽象成类,增加成员变量,将传入的参数合成类等等。

    上一篇博文地址:http://www.cnblogs.com/fixzd/p/8982739.html

    正文

    我们先来看看上一篇博文重构后的代码,还是有点长

    public class ExportExcel<T> {
        private HSSFWorkbook workbook;
        
        public ExportExcel() {
            this(new HSSFWorkbook());
        }
    
        public ExportExcel(HSSFWorkbook workbook) {
            this.workbook = workbook;
        }
    
        public void exportExcel(Collection<T> dataset, OutputStream out) {
            exportExcel("测试POI导出EXCEL文档", null, dataset, out, "yyyy-MM-dd");
        }
    
        public void exportExcel(String[] headers, Collection<T> dataset, OutputStream out) {
            exportExcel("测试POI导出EXCEL文档", headers, dataset, out, "yyyy-MM-dd");
        }
    
        public void exportExcel(String[] headers, Collection<T> dataset, OutputStream out, String pattern) {
            exportExcel("测试POI导出EXCEL文档", headers, dataset, out, pattern);
        }
    
        public void exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out, String pattern) {
            // 生成一个表格
            HSSFSheet sheet = workbook.createSheet(title);
            
            // 生成数据标题和数据行样式
            HSSFCellStyle rowTirtleStyle = getRowTitleStyle();
            HSSFCellStyle rowDataStyle = getRowDataStyle();
            
            //创建数据标题和数据行
            createRowTitle(headers, sheet, rowTirtleStyle);
            createRowData(dataset, pattern, sheet, rowDataStyle);
            
            //写入流
            writeExecl(out);
        }
    
        /**
         * Description:写入到OutputStream
         */
        private void writeExecl(OutputStream out) {
            try {
                workbook.write(out);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Description: 产生数据行
         */
        private void createRowData(Collection<T> dataset, String pattern, HSSFSheet sheet, HSSFCellStyle rowDataStyle) {
            // 遍历集合数据,产生数据行
            Iterator<T> it = dataset.iterator();
            int index = 0;
            while (it.hasNext()) {
                index++;
                HSSFRow row = sheet.createRow(index);
                T t = (T) it.next();
                // 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
                Field[] fields = t.getClass().getDeclaredFields();
                for (int i = 0; i < fields.length; i++) {
                    HSSFCell cell = row.createCell(i);
                    cell.setCellStyle(rowDataStyle);
                    Field field = fields[i];
                    String fieldName = field.getName();
                    String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                    try {
                        Class tCls = t.getClass();
                        Method getMethod = tCls.getMethod(getMethodName, new Class[] {});
                        Object value = getMethod.invoke(t, new Object[] {});
                        // 判断值的类型后进行强制类型转换
                        String textValue = null;
                        if (value instanceof Boolean) {
                            boolean bValue = (Boolean) value;
                            textValue = "男";
                            if (!bValue) {
                                textValue = "女";
                            }
                        } else if (value instanceof Date) {
                            Date date = (Date) value;
                            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                            textValue = sdf.format(date);
                        } else {
                            // 其它数据类型都当作字符串简单处理
                            textValue = value.toString();
                        }
                        // 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成
                        if (textValue != null) {
                            Pattern p = Pattern.compile("^//d+(//.//d+)?$");
                            Matcher matcher = p.matcher(textValue);
                            if (matcher.matches()) {
                                // 是数字当作double处理
                                cell.setCellValue(Double.parseDouble(textValue));
                            } else {
                                HSSFRichTextString richString = new HSSFRichTextString(textValue);
                                HSSFFont font3 = workbook.createFont();
                                font3.setColor(HSSFColor.BLUE.index);
                                richString.applyFont(font3);
                                cell.setCellValue(richString);
                            }
                        }
                    } catch (SecurityException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } finally {
                        // 清理资源
                    }
                }
            }
        }
    
        /**
         * Description: 产生表格标题行
         */
        private void createRowTitle(String[] headers, HSSFSheet sheet, HSSFCellStyle rowTirtleStyle) {
            HSSFRow row = sheet.createRow(0);
            for (int i = 0; i < headers.length; i++) {
                HSSFCell cell = row.createCell(i);
                cell.setCellStyle(rowTirtleStyle);
                HSSFRichTextString text = new HSSFRichTextString(headers[i]);
                cell.setCellValue(text);
            }
        }
    
        /**
         * Description:生成数据标题样式
         */
        private HSSFCellStyle getRowTitleStyle() {
            HSSFCellStyle style = workbook.createCellStyle();
            // 设置这些样式
            style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
            style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
            style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style.setBorderTop(HSSFCellStyle.BORDER_THIN);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            
            // 生成一个字体
            HSSFFont font = workbook.createFont();
            font.setColor(HSSFColor.VIOLET.index);
            font.setFontHeightInPoints((short) 12);
            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
            
            // 把字体应用到当前的样式
            style.setFont(font);
            
            return style;
        }
        
        /**
         * Description:生成数据行样式
         */
        private HSSFCellStyle getRowDataStyle() {
            HSSFCellStyle style = workbook.createCellStyle();
            // 设置这些样式
            style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
            style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
            style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style.setBorderTop(HSSFCellStyle.BORDER_THIN);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
            
            // 生成另一个字体
            HSSFFont font = workbook.createFont();
            font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
            
            style.setFont(font);
                    
            return style;
        }
    
    }
    View Code

    那么接下来我们要如何重构呢?我们从问题的角度来重构吧

    1. 在上面代码中我们可以看到有两个创建样式的函数,这两个函数getRowTitleStyle()和getRowDataStyle()可以说是导出execl的默认样式。在这里我们思考下,如果我们对导出的样式有变动是不是又要修改ExportExcel类?
          /**
           * Description:生成数据标题样式
           */
          private HSSFCellStyle getRowTitleStyle() {
              HSSFCellStyle style = workbook.createCellStyle();
              // 设置这些样式
              style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
              style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
              style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
              style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
              style.setBorderRight(HSSFCellStyle.BORDER_THIN);
              style.setBorderTop(HSSFCellStyle.BORDER_THIN);
              style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
              
              // 生成一个字体
              HSSFFont font = workbook.createFont();
              font.setColor(HSSFColor.VIOLET.index);
              font.setFontHeightInPoints((short) 12);
              font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
              
              // 把字体应用到当前的样式
              style.setFont(font);
              
              return style;
          }
          
          /**
           * Description:生成数据行样式
           */
          private HSSFCellStyle getRowDataStyle() {
              HSSFCellStyle style = workbook.createCellStyle();
              // 设置这些样式
              style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
              style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
              style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
              style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
              style.setBorderRight(HSSFCellStyle.BORDER_THIN);
              style.setBorderTop(HSSFCellStyle.BORDER_THIN);
              style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
              style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
              
              // 生成另一个字体
              HSSFFont font = workbook.createFont();
              font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
              
              style.setFont(font);
                      
              return style;
          }
      View Code
    2. 接下来我们看看导出的主方法exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out, String pattern)。有没有觉得参数有点多了,能不能将一些参数合并成一个类或者去除没用的参数?
    3. 我们再来看看产生数据行函数createRowData的数据处理方式,如下。虽然这里只有两个if...else,但是我们能不能用什么设计模式将他们提取出来,方便以后增加类型时不必修改原有的类?
                          if (value instanceof Boolean) {
                              boolean bValue = (Boolean) value;
                              textValue = "男";
                              if (!bValue) {
                                  textValue = "女";
                              }
                          } else if (value instanceof Date) {
                              Date date = (Date) value;
                              SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                              textValue = sdf.format(date);
                          } else {
                              // 其它数据类型都当作字符串简单处理
                              textValue = value.toString();
                          }
    4. 我们在思考下第三个问题,数据的转换不仅仅只有上面那么按部就班的,就好比一辆车的状态有正常,损坏、维修中、报废等等,但是在数据库中是以0、1、2、3来存储的,那么有什么好的方法可以在不修改原有代码下进行转换呢?

    好了,这篇博文就围绕着上面四个问题进行重构,大家可以试着按照这几个问题对上面代码进行重构,相信经过自己思考和动手后会对代码的设计有进一步的理解。

    问题1:如果我们对导出的样式有变动是不是又要修改ExportExcel类?

    针对上面问题,我们是不是可以将样式创建抽象成类?

        /**
         * Description:生成数据标题样式
         */
        private HSSFCellStyle getRowTitleStyle() {
            HSSFCellStyle style = workbook.createCellStyle();
            // 设置这些样式
            style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
            style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
            style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style.setBorderTop(HSSFCellStyle.BORDER_THIN);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            
            // 生成一个字体
            HSSFFont font = workbook.createFont();
            font.setColor(HSSFColor.VIOLET.index);
            font.setFontHeightInPoints((short) 12);
            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
            
            // 把字体应用到当前的样式
            style.setFont(font);
            
            return style;
        }

    从上面代码可以置顶HSSFCellStyle的创建需要用到Workbook对象,所以接口就不适用。

    然后上面代码中可以看出一个整体的样式还包含了字体,那么就可以设计一个抽象类,如下

    public abstract class AbstractCellStyle {
        HSSFWorkbook workbook;
        HSSFCellStyle style;
        HSSFFont font;
    
        public AbstractCellStyle(HSSFWorkbook workbook) {
            this.workbook = workbook;
            style = workbook.createCellStyle();
            font = workbook.createFont();
        }
        
        public abstract void setStyle();
        
        public abstract void setFont();
    
        
        public HSSFCellStyle getCellStyle() {
            style.setFont(font);
            return style;
        }
    }

    该抽象类AbstractCellStyle有一个有参构造函数、三个成员变量、一个获得样式的方法和两个抽象方法setStyle和setFont。

    子类通过继承AbstractCellStyle,然后重写方法setStyle和setFont即可。

    构造函数需要传入Workbook,然后在构造函数里创建样式和字体对象,最后调用getCellStyle方法获得HSSFCellStyle即可。

    我这里弄了两个默认的样式了,如下

    默认数据行样式类

    DefaultDataCellStyle.java

    public class DefaultDataCellStyle extends AbstractCellStyle{
        public DefaultDataCellStyle(HSSFWorkbook workbook) {
            super(workbook);
        }
    
        @Override
        public void setStyle() {
            style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
            style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
            style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style.setBorderTop(HSSFCellStyle.BORDER_THIN);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        }
        @Override
        public void setFont() {
            font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
        }
    
    }
    View Code

    默认一个数据标题样式,

    DefaultTitleCellStyle.java

    public class DefaultTitleCellStyle extends AbstractCellStyle{
        public DefaultTitleCellStyle(HSSFWorkbook workbook) {
            super(workbook);
        }
    
        @Override
        public void setStyle() {
            style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
            style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
            style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style.setBorderTop(HSSFCellStyle.BORDER_THIN);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        }
        @Override
        public void setFont() {
            font.setColor(HSSFColor.VIOLET.index);
            font.setFontHeightInPoints((short) 12);
            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        }
    }
    View Code

    然后ExportExcel这个类也需要做出相应的修改,修改内容如下

    1. 删除两个函数getRowTitleStyle()和getRowDataStyle()
    2. 增加两个成员变量,且将Workbook也抽象成成员变量
          private HSSFWorkbook workbook;
          private AbstractCellStyle titleCellStyle;//标题行样式
          private AbstractCellStyle dataCellStyle;//数据行样式
    3. 修改构造函数,如下
      public ExportExcel() {
              this(new HSSFWorkbook());
          }
      
          /**
           * 这里可以定义两个常量,但是这里需要workbook,所以就没有抽取出来
           * @param workbook
           */
          public ExportExcel(HSSFWorkbook workbook) {
              this(workbook,new DefaultTitleCellStyle(workbook),new DefaultDataCellStyle(workbook));
          }
      
          public ExportExcel(HSSFWorkbook workbook, AbstractCellStyle titleCellStyle, AbstractCellStyle dataCellStyle) {
              this.workbook = workbook;
              this.titleCellStyle = titleCellStyle;
              this.dataCellStyle = dataCellStyle;
          }
    4. 其他调用getRowTitleStyle()和getRowDataStyle()方法的修改成调用成员变量的方法。

    重构后

    那么现在我们再来看看这个问题,如果我们对导出的样式有变动是不是又要修改ExportExcel类?

    现在我们需要修改导出的标题样式或者数据行样式的话,我们只需要写个类继承AbstractCellStyle,然后设置字体和样式即可,是不是很方便。如果你有更好的建议在评论处留言哦


    问题2:导出的主方法exportExcel参数有点多了,能不能将一些参数合并成一个类或者去除没用的参数?

     原来的如下

    public void exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out, String pattern) {...}

    现在让我们来思考思考下execl文件,一个execl文件可能有多个工作簿(也就是sheet),如下

    每个工作簿(sheet)都有自己的表格,每个表格都有自己的行和列

    在我们到处这里是以每一行对应数据库中一张表的一条记录,每一列就好比数据库中的一张表的一个属性。

    现在我们现将每一列抽象成一个类,每一列中包含一个标题和数据所对应的实体属性,例如,学号是标题,学号在实体Student中对应的属性是id

    抽象出来的类如下

    public class CellEntity {
        private String title;
        private String filedName;
        
        //set get方法...
    }

    接下来我们把每个工作簿(sheet)也抽象成一个类,这个类中包含多个列(CellEntity)、工作簿名称(sheetName)、数据集合。

    public class SheetEntity {
        private String sheetName;
    
        private List<CellEntity> cellEntitys;
    
        private Collection dataset;
    
        //set get方法  
    }

    最后修改导出的主方法exportExcel和其他一些参数的获取

    public void exportExcel(SheetEntity sheetEntity, OutputStream out) {...}

    问题3:函数createRowData的数据处理能不能用什么设计模式将他们提取出来,方便以后增加类型时不必修改原有的类?

        String textValue = null;
        if (value instanceof Boolean) {
            boolean bValue = (Boolean) value;
            textValue = "男";
            if (!bValue) {
                textValue = "女";
            }
        } else if (value instanceof Date) {
            Date date = (Date) value;
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            textValue = sdf.format(date);
        } else {
            // 其它数据类型都当作字符串简单处理
            textValue = value.toString();
        }

    从上面代码中可以看出value被判断是哪种类型,然后再进行赋值操作,显示被判断是否是Boolean,然后判断Date,最后都被当成字符串处理。

    这里博主采用的是如下方法,将数据转换抽象成一个抽象类,如下

    public abstract class AbstractDataHandler {
        private AbstractDataHandler abstractDataHandler;
    
        public AbstractDataHandler(AbstractDataHandler abstractDataHandler) {
            this.abstractDataHandler = abstractDataHandler;
        }
    
        public abstract String dataHandle(Object value);
    
        protected String nextHandle(Object value) {
            if (abstractDataHandler != null) {
                return abstractDataHandler.dataHandle(value);
            }
            return null;
        }
    }

    子类通过集成该抽象类,实现dataHandle方法,如果是当前类型,则处理后返回,否则调用抽象类AbstractDataHandler的nextHandle方法继续调用下个数据处理方法。现在来看看我写的几个数据处理类

    Boolean数据处理

    public class BooleanDataHandler extends AbstractDataHandler {
    
        public BooleanDataHandler(AbstractDataHandler abstractDataHandler) {
            super(abstractDataHandler);
        }
    
        @Override
        public String dataHandle(Object value) {
            if (value instanceof Boolean) {
                boolean bValue = (Boolean) value;
                String textValue = "是";
                if (!bValue) {
                    textValue = "否";
                }
                return textValue;
            } else {
                return nextHandle(value);
            }
        }
    
    }

    Date数据处理

    public class DateDataHandler extends AbstractDataHandler {
        
        public DateDataHandler(AbstractDataHandler abstractDataHandler) {
            super(abstractDataHandler);
        }
    
        @Override
        public String dataHandle(Object value) {
            if (value instanceof Date) {
                Date date = (Date) value;
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return sdf.format(date);
            } else {
                return nextHandle(value);
            }
        }
    
    }

    String数据处理

    public class StringDataHandler extends AbstractDataHandler {
    
        public StringDataHandler(AbstractDataHandler abstractDataHandler) {
            super(abstractDataHandler);
        }
    
        @Override
        public String dataHandle(Object value) {
            return value.toString();
        }
    
    }

    然后创建一个工厂类DataHandlerFactory,工具类调用这个工厂类的dataHandle方法,数据处理就会按照Boolean-->Date-->String流程走下去,都没有处理就返回null

    public class DataHandlerFactory {
    
        private static AbstractDataHandler dataHandler = new BooleanDataHandler(
                new DateDataHandler(
                        new StringDataHandler(null)));
    
        public static String dataHandle(Object value) {
            return dataHandler.dataHandle(value);
        }
    }

     修改后的代码如下,是不是简便了许多

           

     -------------->     

     

    现在如果需要增加默认的类型处理,只需要增加AbstractDataHandler的子类,然后修改DataHandlerFactory工厂类即可。

    问题4:数据的转换并不是按照预期进行的那么有什么好的方法可以在不修改原有代码下进行转换呢?

    关于这个问题,我们需要增加一个转换接口,然后将数据转换交给子类来实现即可。其实在实体类CellEntity增加一个类型转换的成员变量即可。接口如下

    public interface DataConversion {
        String transferData(Object data);
    }

    实体类CellEntity也需要做相应的修改,增加一个成员变量即可

    public class CellEntity {
        private String title;
        private String fieldName;
        private DataConversion conversion;
        ......
    }

    然后到处工具类中也要做修改,由原先交给工厂处理的修改为判断cellEntity对象的成员变量conversion是否为null,为null则交给默认的数据处理类处理,不为null则交给conversion处理

        if (cellEntity.getConversion() == null)
            textValue = DataHandlerFactory.dataHandle(value);
        else
            textValue = cellEntity.getConversion().transferData(value);

    就按上面车辆状态来举个相应的例子吧,判断传入的类型是否为0或者1,0返回正常,1返回异常,其他的都返回null,如下

    public class CarStatusExportConversion implements DataExportConversion {
    
        @Override
        public String transferData(Object data) {
            if (data == null) return null;
            Integer carStatus = (Integer) data;
            switch (carStatus){
                case 0:
                    return "正常";
                case 1:
                    return "异常";
            }
            return null;
        }
    }

    完整的工具类和测试代码

    ExportExecl工具类

    public class ExportExcel<T> {
        private HSSFWorkbook workbook;
        private AbstractCellStyle titleCellStyle;//标题行样式
        private AbstractCellStyle dataCellStyle;//数据行样式
    
        public ExportExcel() {
            this(new HSSFWorkbook());
        }
    
        /**
         * 这里可以定义两个常量,但是这里需要workbook,所以就没有抽取出来
         * @param workbook
         */
        public ExportExcel(HSSFWorkbook workbook) {
            this(workbook,new DefaultTitleCellStyle(workbook),new DefaultDataCellStyle(workbook));
        }
    
        public ExportExcel(HSSFWorkbook workbook, AbstractCellStyle titleCellStyle, AbstractCellStyle dataCellStyle) {
            this.workbook = workbook;
            this.titleCellStyle = titleCellStyle;
            this.dataCellStyle = dataCellStyle;
        }
    
        public void exportExcel(SheetEntity sheetEntity, OutputStream out) {
            // 生成一个表格
            HSSFSheet sheet = workbook.createSheet(sheetEntity.getSheetName());
            // 生成数据标题和数据行样式
            HSSFCellStyle rowTirtleStyle = titleCellStyle.getCellStyle();
            HSSFCellStyle rowDataStyle = dataCellStyle.getCellStyle();
            
            //创建数据标题和数据行
            createRowTitle(sheetEntity.getCellEntitys(), sheet, rowTirtleStyle);
            createRowData(sheetEntity.getCellEntitys(),sheetEntity.getDataset(), sheet, rowDataStyle);
            
            //写入流
            writeExecl(out);
        }
    
        /**
         * Description:写入到OutputStream
         */
        private void writeExecl(OutputStream out) {
            try {
                workbook.write(out);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Description: 产生数据行
         */
        private void createRowData(List<CellEntity> cellEntitys, Collection<T> dataset, HSSFSheet sheet, HSSFCellStyle rowDataStyle) {
            // 遍历集合数据,产生数据行
            Iterator<T> it = dataset.iterator();
            int index = 0;
            while (it.hasNext()) {
                index++;
                HSSFRow row = sheet.createRow(index);
                T t = (T) it.next();
                for (int i = 0; i < cellEntitys.size(); i++) {
                    HSSFCell cell = row.createCell(i);
                    cell.setCellStyle(rowDataStyle);
                    try {
                        String textValue = null;
    
                        CellEntity cellEntity = cellEntitys.get(i);
                        Object value = PropertyUtils.getProperty(t, cellEntity.getFiledName());
    
                        if (cellEntity.getConversion() == null)
                            textValue = DataHandlerFactory.dataHandle(value);
                        else
                            textValue = cellEntity.getConversion().transferData(value);
    
                        cell.setCellValue(textValue);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        /**
         * Description: 产生表格标题行
         */
        private void createRowTitle(List<CellEntity> cellEntitys, HSSFSheet sheet, HSSFCellStyle rowTirtleStyle) {
            HSSFRow row = sheet.createRow(0);
            for (int i = 0; i < cellEntitys.size(); i++) {
                HSSFCell cell = row.createCell(i);
                cell.setCellStyle(rowTirtleStyle);
                HSSFRichTextString text = new HSSFRichTextString(cellEntitys.get(i).getTitle());
                cell.setCellValue(text);
            }
        }
    
    }
    View Code

    Test导出测试类

    public class Test {
    
        public static void main(String[] args) {
            // 测试学生
            ExportExcel<Student> ex = new ExportExcel<Student>();
            // 测试图书
            ExportExcel<Book> ex2 = new ExportExcel<Book>();
    
            List<Student> studentList = getStudentList();
    
            try {
    
    
                OutputStream out = new FileOutputStream("E://a.xls");
    
                ex.exportExcel(getStudentSheetEntity("学生",studentList), out);
    
                out.close();
                System.out.println("excel导出成功!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private static SheetEntity getStudentSheetEntity(String sheetName,List<Student> studentList){
    
            List<CellEntity> cellEntitys = new ArrayList<CellEntity>();
            cellEntitys.add(new CellEntity("学号","id"));
            cellEntitys.add(new CellEntity("姓名","name"));
            cellEntitys.add(new CellEntity("年龄","age"));
            cellEntitys.add(new CellEntity("性别","sex", new SexDataConversion()));
            cellEntitys.add(new CellEntity("出生日期","birthday"));
    
            SheetEntity entity = new SheetEntity(sheetName,cellEntitys , studentList);
    
            return entity;
        }
    
        private static List<Student> getStudentList() {
            List<Student> datas = new ArrayList<Student>();
            datas.add(new Student(10000001, "张三", 20, true, new Date()));
            datas.add(new Student(20000002, "李四", 24, false, new Date()));
            datas.add(new Student(30000003, "王五", 22, true, new Date()));
            return datas;
        }
    
    }
    
    class SexDataConversion implements DataConversion{
    
        @Override
        public String transferData(Object data) {
            if (data instanceof Boolean) {
                boolean bValue = (Boolean) data;
                String textValue = "男";
                if (!bValue) {
                    textValue = "女";
                }
                return textValue;
            }
            return null;
        }
    }
    View Code

    这一篇修改后的github地址如下

    github地址:https://github.com/rainbowda/utils/tree/master/poi/src/main/java/com/utils/poi/update_2

    后续会增加其他各种各样的工具项目,觉得不错的给个star,谢谢


    作者: 云枭zd
    Github: Github地址
    出处: https://www.cnblogs.com/fixzd/
    版权声明:本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
  • 相关阅读:
    猫与路由器(还没看)
    ORA-12154: TNS: 无法解析指定的连接标识符(未解决)
    easy-batch demo
    mongodb 创建用户
    docker mongodb
    监听器,过滤器,拦截器
    mysql docker-compose启动异常:Database is uninitialized and password option is not specified
    设计模式-builder模式的价值
    【C++ Template | 04】折叠表达式
    【vim】vim插件教程
  • 原文地址:https://www.cnblogs.com/fixzd/p/9059994.html
Copyright © 2011-2022 走看看