专栏首页青青天空树java导出Excel文件

java导出Excel文件

一、背景

  最近在java上做了一个EXCEL的导出功能,写了一个通用类,在这里分享分享,该类支持多sheet,且无需手动进行复杂的类型转换,只需提供三个参数即可:

  • fileName excel文件名
  • HasMap<String,List<?>> data 具体的数据,每个List代表一张表的数据,?表示可为任意的自定义对象
  • LinkedHashMap<String,String[][]> headers Stirng代表sheet名。每个String[][]代表一个sheet的定义,举个例子如下: String[][] header = { {"field1","参数1"} ,{"field2","参数2"} ,{"field3","参数3"} } 其中的field1,field2,field3为对象中的属性名,参数1,参数2,参数3为列名,实际上这个指定了列的名称和这个列用到数据对象的哪个属性。

二、怎么用

  以一个例子来说明怎么用,假设有两个类A和B定义如下:

public class A{
    private String name;
    private String address;
}
public class B{
    private int id;
    private double sum;
    private String cat;
}

现在我们通过查询数据库获得了A和B的两个列表:

List<A> dataA = .....;
List<B> dataB = .....;

我们将这两个导出到excel中,首先需要定义sheet:

String[][] sheetA = {
    {"name","姓名"}
    ,{"address","住址"}
}
String[][] sheetB = {
    {"id","ID"}
    ,{"sum","余额"}
    ,{"cat","猫的名字"}
}

然后将数据汇总构造一个ExcelUtil:

String fileName = "测试Excel";
HashMap<String,List<?>> data = new HashMap<>();
//ASheet为表名,后面headers里的key要跟这里一致
data.put("ASheet",dataA);
data.put("BSheet",dataB);
LinkedHashMap<String,String[][]> headers = new LinkedHashMap<>();
headers.put("ASheet",sheetA);
headers.put("BSheet",sheetB);
ExcelUtil excelUtil = new ExcelUtil(fileName,data,headers);
//获取表格对象
HSSFWorkbook workbook = excelUtil.createExcel();
//这里内置了一个写到response的方法(判断浏览器类型设置合适的参数),如果想写到文件也是类似的
workbook.writeToResponse(workbook,request,response);

当然通常数据是通过数据库查询的,这里为了演示方便没有从数据库查找。

三、实现原理

  这里简单说明下实现过程,从调用createExcel()这里开始

1、遍历headers创建sheet

    public HSSFWorkbook createExcel() throws Exception {
        try {
            HSSFWorkbook workbook = new HSSFWorkbook();
            //遍历headers创建表格
            for (String key : headers.keySet()) {
                this.createSheet(workbook, key, headers.get(key), this.data.get(key));
            }
            return workbook;
        } catch (Exception e) {
            log.error("创建表格失败:{}", e.getMessage());
            throw e;
        }
    }

将workbook,sheet名,表头数据,行数据传入crateSheet方法中创建sheet。

2、创建表头

  表头也就是一个表格的第一行,通常用来对列进行说明

        HSSFSheet sheet = workbook.createSheet(sheetName);
        // 列数
        int cellNum = header.length;
        // 单元行,单元格
        HSSFRow row;
        HSSFCell cell;
        // 表头单元格样式
        HSSFCellStyle columnTopStyle = this.getColumnTopStyle(workbook);
        // 设置表头
        row = sheet.createRow(0);
        for (int i = 0; i < cellNum; i++) {
            cell = row.createCell(i);
            cell.setCellStyle(columnTopStyle);
            String str = header[i][1];
            cell.setCellValue(str);
            // 设置列宽为表头的文字宽度+6个半角符号宽度
            sheet.setColumnWidth(i, (str.getBytes("utf-8").length + 6) * 256);
        }

3、插入行数据

  这里是最重要的部分,首先通过数据的类对象获取它的反射属性Field类,然后将属性名和Field做一个hash映射,避免循环查找,提高插入速度,接着通过一个switch语句,根据属性类别设值,主要代码如下:

/**
 * 设置单元格,根据fieldName获取对应的Field类,使用反射得到值
 *
 * @param cell 单元格实例
 * @param obj 存有属性的对象实例
 * @param fieldMap  属性名与Field的映射
 * @param fieldName 属性名
 */
private void setCell(HSSFCell cell, Object obj, Map<String, Field> fieldMap, String fieldName) throws Exception {
    //获取该属性的Field对象
    Field field = fieldMap.get(fieldName);
    //通过反射获取属性的值,由于不能确定该值的类型,用下面的判断语句进行合适的转型
    Object value = field.get(obj);
    if (value == null) {
        cell.setCellValue("");
    } else {
        switch (field.getGenericType().getTypeName()) {
        case "java.lang.String":
            cell.setCellValue((String) value);
            break;
        case "java.lang.Integer":
        case "int":
            cell.setCellValue((int) value);
            break;
        case "java.lang.Double":
        case "double":
            cell.setCellValue((double) value);
            break;
        case "java.util.Date":
            cell.setCellValue(this.dateFormat.format((Date) value));
            break;
        default:
            cell.setCellValue(obj.toString());
        }
    }
}

完整代码可以到github上查看下载,这里就不列出来了。

github地址:点击跳转

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1eo2bqjxios23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • EventBus轻松使用

      由greenrobot组织贡献(该组织还贡献了greenDAO),一个Android事件发布/订阅轻量级框架,功能:通过解耦发布者和订阅者简化Android...

    用户2038589
  • 趣味问题:画图(c++实现)

    描述:在一个定义了直角坐标系的纸上,画一个(x1,y1)到(x2,y2)的矩形指将横坐标范围从x1到x2,纵坐标范围从y1到y2之间的区域涂上颜色。下图给出了一...

    用户2038589
  • 安卓OKhttp请求封装

      目前安卓开发中使用的网络工具为OKhttp,但是okhttp的使用还不是很方便,在okhttp的基础上再对请求进行封装会极大的方便网络调用。

    用户2038589
  • 2017第八届蓝桥杯决赛(C++ B组)2.磁砖样式

    小明家的一面装饰墙原来是 310 的小方格。 现在手头有一批刚好能盖住2个小方格的长方形瓷砖。 瓷砖只有两种颜色:黄色和橙色。 小明想知道,对于这么简陋的...

    racaljk
  • 在iOS中怎样创建可展开的Table View?(上)

    几乎所有的app都有一个共同特征,它们向用户提供了多个视图控制器来导航和工作.这些视图控制器可以用在很多方面,例如,简单地显示某种信息在屏幕上,或者从用户的输入...

    hrscy
  • 快速学习POI-模板打印

    自定义生成Excel报表文件还是有很多不尽如意的地方,特别是针对复杂报表头,单元格样式,字体等操作。手写这些代码不仅费时费力,有时候效果还不太理想。那怎么样才能...

    cwl_java
  • 快速学习POI-POI报表导出

    cwl_java
  • 处于UITableView中心线cell的处理

    且行且珍惜_iOS
  • SaaS-百万数据报表导出

    基于XSSFWork导出Excel报表,是通过将所有单元格对象保存到内存中,当所有的Excel单元格全部创建完成之后一次性写入到Excel并导出。当百万数据级别...

    cwl_java
  • iOS 9 Storyboard 教程(一下)

    你可以直接从storyboard编辑器中,使用原型cell你可以很容易的为你的tableViewCell设计一套自定义的布局.

    hrscy

扫码关注云+社区

领取腾讯云代金券