• Java导出Excel文件详解


    Java导出Excel文件详解

    一、背景

    当前B/S模式已成为应用开发的主流,而企业办公系统中,常常有客户这样子要求:你要把我们的报表直接用Excel打开(电信系统、银行系统)、或者是:我们已经习惯用Execel打印,这样我们实际的开发中,很多时候需要实现导入、导出EXcel应用。

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

    • fileName

      Excel的文件名

    • HashMap<String,List<?>> data

      具体数据,每个List代表一张表的数据,?表示可以为任意类型的自定义对象

    • LinkedHashMap<String,String[ ] [ ]> headers

      String 代表sheet名,每个String[ ] [ ]代表一个sheet的定义,举个列子如下:

      String[][] headers = {
          {"field1","参数1"}
          ,{"field2","参数2"}
          ,{"field3","参数3"}
      } 
      

      其中的field1,field2,field3为对象中的属性名,参数1,参数2,参数3为列名,实际上这个指定了列的名称和这个列用到数据对象的哪个属性。

    二、怎么用

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

    public class A{
        private String name;
        privaite 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 [][] sheeetA ={
        {"name","姓名"}
        ,{"address","住址"}
    }
    String [][] sheetB ={
        {"id","ID"},
        {"sum","余额"},
        {"cat","猫的名字"}
    }
    

    然后将数据汇总构成一个ExcelUtil

    // 第一个参数:Excel的名字
    String fileName = "测试Excel";
    // 第二个参数:sheet的具体数据
    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);
    

    三、实现原理

    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名,表头数据,行数据传入createSheet方法中创建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);
      }
    
    1. 插入数据

    这里是我们最重要的部分,首先通过数据的类对象获取它的反射属性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());
      }
     }
    }
    


    作者:关小涛
    学习和分享是博客最大的乐趣,欢迎大家取之所需。
    努力是自己努力的原因,每周天写博客总结工作中的新技能和出现的问题
  • 相关阅读:
    Nginx 七层反向代理
    Nginx Rewrite域名及资源重定向!(重点)
    对FPM 模块进行参数优化!
    Nginx压力测试及通用优化
    LNMP架构及应用部署!(重点)
    安装PHP解析环境!
    Mysql安装并修改字符集 ----> 基于源码包安装
    Nginx安装部署!
    python入门
    Android学习进度三
  • 原文地址:https://www.cnblogs.com/XtsLife/p/12575698.html
Copyright © 2020-2023  润新知