最新公告
  • 欢迎您光临欧资源网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入我们
  • 基于某个Model类来定义Excel表头及所处列的设计方法

    现状

    在日常Java开发中,有时会有业务需要根据已有的查询结果导出Excel文件。通常,他们会考虑使用开源 POI 库。大部分人应该先从网上找几个例子poi单元格颜色设定 程序人生,然后复制粘贴到项目中,根据需求设置对应的单元格内容,代码中会有很多自定义的代码,如下图:

    对应的单元格分配

    设计

    一般导出的Excel第一行是表头信息,第二行是需要导出的数据。我们可以使用 Model 类来定义 Excel 标题和列信息。

    // 实现Comparable接口是为了根据order字段排序,确定这个表头的标题放在列的位置顺序
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class ExcelHeader implements Comparable {
        // 表头的标题名称
        private String title;
        // 表头的标题所在列的顺序
        private int order;
        // 单元格的宽度
        private int width;
        // 对应字段
        private String fieldName;
        @Override
        public int compareTo(ExcelHeader o) {
            return Integer.compare(order, o.order);
        }
    }

    导出的数据是基于后端某个Model类的List集合。我们可以定义一个注解来标识这个Model需要导出的字段poi单元格颜色设定 程序人生,从而实现通用导出。

    // 用来在导出对象的field上加入的注解,通过该annotation说明某个属性所对应的标题
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    @Documented
    public @interface ExcelResources {
        // 导出字段的标题名称,用于构造ExcelHeader对象的title
        String title();
        // 导出字段在excel的顺序,用于构造ExcelHeader对象的order
        int order() default 9999;
        // 导出字段列的宽度,用于构造ExcelHeader对象的width
        int width() default 150;
    }

    1、先定义工具类的通用静态导出方法

     /**
         * @param objs      导出的数据集合,一般为后端DB查询结果
         * @param clz       导出的Excel内容Model类,其导出属性上需要加@ExcelResources
         * @param sheetName 导出的Excel的Sheet页名称
         * @param pageSize  导出的Excel的每个Sheet页的数据量,若objs.size()>pageSize,会写入到(objs.size()/pageSize+1)个Sheet页中
         * @param fileName  导出的Excel文件名,会加上_yyyyMMddHHmmss避免重名
         * @param response  HttpServletResponse
         */
    public static void exportExcel(List objs, Class clz, String sheetName, int pageSize, String fileName,
                                       HttpServletResponse response)
                throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
            if (objs == null || clz == null) {
                throw new NullPointerException("parameter must be not null");
            }
            OutputStream outputStream = null;
            try {
                Workbook wb = handleObj2Excel(objs, clz, sheetName, pageSize);
                setResponseHeader(response, fileName);
                // 定入到输出流
                outputStream = response.getOutputStream();
                wb.write(outputStream);
                // 刷新流
                outputStream.flush();
            } finally {
                IOUtils.closeQuietly(outputStream);
            }
        }

    2、私有方法handleObj2Excel()会使用参数objs data和clz上的自定义注解来反映获取到的数据并设置到cell中,并返回HSSFWorkbook对象。

    private static HSSFWorkbook handleObj2Excel(List objs, Class clz, String sheetName, int pageSize)
                throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
            HSSFWorkbook wb = new HSSFWorkbook();
            // 获取excel标题列表并排序,详见下面私有方法
            List headers = getHeaderList(clz);
            Collections.sort(headers);
            int size = objs.size();
            if (size > 0) {
                int sheetCount = size % pageSize == 0 ? size / pageSize : size / pageSize + 1;
                HSSFSheet sheet;
                // 设置第i个sheet页内的数据
                for (int i = 1; i <= sheetCount; i++) {
                     // 创建sheet页
                    if (!StringUtils.isEmpty(sheetName)) {
                        sheet = wb.createSheet(sheetName + i);
                    } else {
                        sheet = wb.createSheet();
                    }
                    HSSFRow row = sheet.createRow(0);
                   // 设置head的数据格式,详见下面私有方法
                    CellStyle titleStyle = setCellStyle(wb, POSITION_TITLE);
                    for (int m = 0, len = headers.size(); m < len; m++) {
                        HSSFCell head = row.createCell(m);
                        head.setCellStyle(titleStyle);
                        head.setCellValue(headers.get(m).getTitle());
                        sheet.setColumnWidth(m, 40 * headers.get(m).getWidth());
                    }
                    // 设置body数据部分的格式
                    int begin = (i - 1) * pageSize;
                    int end = Math.min((begin + pageSize), objs.size());
                    int rowCount = 1;
                    CellStyle bodyStyle = setCellStyle(wb, POSITION_BODY);
                    for (int n = begin; n < end; n++) {
                        row = sheet.createRow(rowCount);
                        Object obj = objs.get(n);
                        for (int x = 0, len = headers.size(); x < len; x++) {
                            Cell body = row.createCell(x);
                            body.setCellStyle(bodyStyle);
    												// 反射获取值并set到对应的单元格中,
                            // objs中model的field与clz的field名称需要相同对应才能导出
                            body.setCellValue(BeanUtils.getProperty(obj, headers.get(x).getFieldName()));
                        }
                        rowCount++;
                    }
                }
            }
            return wb;
        }
    // 由参数clz来获取@ExcelResources注解并生成表头信息ExcelHeader类的集合
     private static List getHeaderList(Class clz) {
            Field[] ms = clz.getDeclaredFields();
            List headers = new ArrayList(ms.length);
            for (Field m : ms) {
                String field = m.getName();
                if (m.isAnnotationPresent(ExcelResources.class)) {
                    ExcelResources er = m.getAnnotation(ExcelResources.class);
                    // 标题,序号,宽度,其成员变量
                    headers.add(new ExcelHeader(er.title(), er.order(), er.width(), field));
                }
            }
            return headers;
        }
    // 设置单元格样式
     private static CellStyle setCellStyle(Workbook workBook, String position) {
            CellStyle cellStyle = workBook.createCellStyle();
            cellStyle.setAlignment(HorizontalAlignment.GENERAL);
            cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            // 设置单元格字体,表头字段可以大些
            Font headerFont = workBook.createFont();
            if (POSITION_TITLE.equals(position)) {
                headerFont.setFontHeightInPoints((short) 12);
                headerFont.setBold(true);
            } else {
                headerFont.setFontHeightInPoints((short) 10);
            }
            cellStyle.setFont(headerFont);
            return cellStyle;
        }

    poi 读取单元格颜色_poi单元格颜色设定 程序人生_poi 获取单元格颜色

    3、私有方法setResponseHeader()是设置响应头和文件名。

    // 设置返回的响应头
    private static void setResponseHeader(HttpServletResponse response, String fileName) {
            // 返回的文件名
            String resName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)
                    + "_" + DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMddHHmmss") + ".xls";
            response.setContentType("application/vnd.ms-excel");
            // excel的导出设置(文件名必须去掉空格,否则出现问题)
            response.setHeader("Content-Disposition", "attachment;filename="
                    + resName.replaceAll("\s*", StringUtils.EMPTY));
        }

    例子

    1、首先定义一个Model类,在需要导出的字段上使用@ExcelResources注解,如下图:

    参数clz的定义类

    2、通过DB查询数据后,直接调用工具类导出Excel。

    获取数据并调用实用方法

    3、查看导出文件的内容

    Excel文件内容

    可扩展性

    由于自定义注解,所以具有可扩展性,比如定义单元格的格式(字体、颜色、边框、类型等),增加单元格的勾选(单选、多选、范围等)。

    站内大部分资源收集于网络,若侵犯了您的合法权益,请联系我们删除!
    欧资源网 » 基于某个Model类来定义Excel表头及所处列的设计方法

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    欧资源网
    一个高级程序员模板开发平台

    发表评论