POI操作Execl工具类简单实现

最近又在使用poi进行execl的导入导出,然后思来想去,决定简单实现一个工具类。那么问题来了,要怎么实现呢?

  • 首先肯定需要利用反射,根据列名进行值的设置。
  • 然后是实体属性与列名的对应关系(不是每个字段都对应一个execl表中的一个列),最终决定使用自定义注解实现。

前置知识

  • 反射
  • 注解

思路

导出

  • 参数
    – 需要导出的数据集合。
    – 要导出的列名的数组
  • 操作
    – 遍历数据集合,创建行HSSFRow,遍历列名数组,创建列HSSFCell
    – 反射获取属性和列名的对应关系,在遍历列名数组创建列时,获取对应的属性名,如果存在对应关系,则获取属性名,利用反射执行getXxx方法获取值,然后setCellValue();

导入

  • 参数
    – execl文件的输入流
    – 标题所在行(方便遍历获取值)
    – 实体类Class对象(最后生成实体集合)
  • 操作
    – 反射获取实体类的注解(实体属性和列名的对应关系)
    – 根据输入流创建HSSFWorkbook,然后遍历,如果存在属性和列名的对应,则反射实体类的属性,然后赋值。

代码

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
  @TableId(type = IdType.AUTO)
  private long id;
  @ExeclTitleName("工号")
  private String uno;
  @ExeclTitleName("姓名")
  private String uname;
  private String upass;
  @ExeclTitleName("头像")
  private String uimage;
  @ExeclTitleName("性别")
  private long usex;
  @ExeclTitleName("手机")
  private String uphone;
  @ExeclTitleName("邮箱")
  private String uemail;

反射获取注解信息

/**
 * 获取指定类中 @ExeclTitleName和属性的对应关系
 *
 * @param clazz
 * @param <T>
 * @return
 */
public static <T> Map<String, String> getAnnotationName(Class<T> clazz) {
    Map<String, String> map = new HashMap<>();
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        field.setAccessible(true);
        if (field.isAnnotationPresent(ExeclTitleName.class)) {
            String propValue = field.getName();
            ExeclTitleName annotation = field.getAnnotation(ExeclTitleName.class);
            String execlValue = annotation.value();
            map.put(execlValue, propValue);
        }
    }
    return map;
}

导入

/**
 * @param is      execl文件输入流
 * @param dataRow 标题开始行
 * @param clazz   需要映射的实体类
 * @param <T>
 * @return 实体类集合
 * @throws Exception
 */
public static <T> List<T> getData(InputStream is, int dataRow, Class<T> clazz) throws Exception {
    HSSFWorkbook workbook = new HSSFWorkbook(is);
    HSSFSheet sheet = workbook.getSheetAt(0);
    int rowNum = sheet.getLastRowNum();
    HSSFRow titleRow = sheet.getRow(dataRow);
    //列名和属性名对应关系
    Map<String, String> map = getAnnotationName(clazz);
    //execl表中全部列和属性的对应关系
    Map<Integer, String> propertyMap = new HashMap<>();
    //获取列名,并获取属性
    for (int i = 0; i < titleRow.getLastCellNum(); i++) {
        HSSFCell cell = titleRow.getCell(i);
        //列名
        String titleName = cell.getStringCellValue();
        //属性名
        String propertyName = map.get(titleName);
        propertyMap.put(i, propertyName);
    }
    //映射结果集合
    List<T> list = new ArrayList<>();
    for (int i = dataRow + 1; i <= rowNum; i++) {
        HSSFRow row = sheet.getRow(i);
        T object = clazz.newInstance();
        if (row == null)
            continue;
        short cellNum = row.getLastCellNum();
        for (int j = 0; j < cellNum; j++) {
            HSSFCell cell = row.getCell(j);
            String cellValue;
            if (cell == null) {
                cellValue = "";
            } else if (cell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {// 对布尔值的处理
                cellValue = String.valueOf(cell.getBooleanCellValue());
            } else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {// 对数字值的处理
                cellValue = cell.getNumericCellValue() + "";
            } else {
                // 其余按照字符串处理
                cellValue = cell.getStringCellValue();
            }
            if (cellValue != null && cellValue != "") {
                //获取execl对应的属性名
                String propertyNmme = propertyMap.get(j);
                //存在对应关系则进行反射赋值
                if (propertyNmme != null) {
                    Field field = clazz.getDeclaredField(propertyNmme);
                    field.setAccessible(true);
                    Type genericType = field.getGenericType();
                    if (genericType.toString().equals("long")) {
                        field.setLong(object, Long.valueOf(cellValue));
                    } else if (genericType.toString().equals("double")) {
                        field.setDouble(object, Double.valueOf(cellValue));
                    } else {
                        field.set(object, cellValue);
                    }
                }
            }
        }
        list.add(object);
    }
    return list;
}

导出

/**
 * 导出Execl工具类
 * @param titleName  大标题名称
 * @param columns    列名数组
 * @param clazz      导出的数据类型
 * @param list       导出的数据集合
 * @param <T>
 * @return
 * @throws Exception
 */
public static <T> HSSFWorkbook createWorkBook(String titleName, String[] columns, Class<T> clazz, List<T> list) throws Exception {
    HSSFWorkbook workbook = new HSSFWorkbook();

    HSSFSheet sheet = workbook.createSheet(titleName);

    int rowCount = 0;
    //大标题,合并单元格
    sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, columns.length - 1));
    HSSFRow bigtitleRow = sheet.createRow(rowCount++);
    HSSFCell bigtitleCell = bigtitleRow.createCell(0);
    //设置单元格样式
    bigtitleCell.setCellStyle(bigTitleStyle(workbook));
    bigtitleCell.setCellValue(titleName);

    HSSFRow titleRow = sheet.createRow(rowCount++);

    //创建标题栏
    for (int i = 0; i < columns.length; i++) {
        HSSFCell cell = titleRow.createCell(i);
        cell.setCellStyle(smallCellStyle(workbook));
        cell.setCellValue(columns[i]);
    }

    //属性和列名映射
    Map<String, String> annotationName = getAnnotationName(clazz);

    //创建数据
    for (int i = 0; i < list.size(); i++ ) {
        HSSFRow row = sheet.createRow(rowCount++);
        T object = list.get(i);
        for (int j = 0; j < columns.length; j++) {
            sheet.setColumnWidth(j,22*256);//设置列宽为22个字符长度
            String property = annotationName.get(columns[j]);
            Object value;
            if (property != null) {
                String methodName = "get"+property.substring(0,1).toUpperCase()+property.substring(1);
                Method method = clazz.getDeclaredMethod(methodName, null);
                value = method.invoke(object, null);
            }else{
                value = "";
            }
            HSSFCell unoCell = row.createCell(j);
            unoCell.setCellStyle(smallCellStyle(workbook));
            unoCell.setCellValue(String.valueOf(value));
        }
    }
    return workbook;
}


private static CellStyle bigTitleStyle(Workbook wb) {

    //单元格样式
    CellStyle curStyle = wb.createCellStyle();
    //字体
    Font curFont = wb.createFont();
    curFont.setFontName("微软雅黑");
    curFont.setFontHeightInPoints((short) 18);
    //字体加粗
    curFont.setBold(true);
    curStyle.setFont(curFont); // 绑定字体

    curStyle.setAlignment(HorizontalAlignment.CENTER); // 横向居中
    curStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 纵向居中

    curStyle.setFillBackgroundColor((short) 13);

    return curStyle;
}

public static CellStyle smallCellStyle(Workbook wb) {
    //单元格样式
    CellStyle curStyle = wb.createCellStyle();
    //字体
    Font curFont = wb.createFont();
    curFont.setFontName("微软雅黑");
    curStyle.setFont(curFont); // 绑定字体
    curStyle.setAlignment(HorizontalAlignment.CENTER); // 横向居中
    curStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 纵向居中
    return curStyle;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
POI(Poor Obfuscated Implementation)是一款用于操作Microsoft Office格式文件的Java API库。它的目标是提供一种简单、快速、可靠的方式来读取、创建和编辑这些类型的文件,包括Excel、Word和PowerPoint等。 POI库中的HSSFWorkbook类用于操作Excel文件。开发者可以使用该类在内存中创建一个Excel文件,并将数据填充到不同的工作表和单元格中。此外,HSSFWorkbook也可以打开现有的Excel文件,以便进行编辑和保存。 为了将POI带入Excel,我们可以使用POI提供的API来实现Excel文件的下载。首先,我们需要创建一个HSSFWorkbook对象,并设置工作表的名字。然后,可以利用HSSFWorkbook对象创建一个或多个工作表,并填充所需的数据。最后,我们将HSSFWorkbook写入OutputStream或将其保存到本地文件中。这样,使用我们编写的代码,用户就可以下载包含所需数据的Excel文件。 例如,假设我们要从数据库中获取一些用户信息,并将其导出到Excel文件中进行下载。我们可以使用POI库提供的API来实现这个需求。首先,我们连接数据库并查询所需的用户信息。然后,我们创建一个HSSFWorkbook对象并设置一个工作表名称,比如“用户信息”。接下来,我们使用结果集将用户信息逐行填充到工作表的不同单元格中。最后,我们将HSSFWorkbook写入到OutputStream中,并将其作为一个可下载的文件返回给用户。 总之,POI是一个非常实用的工具类,可以帮助我们在Java应用程序中操作Excel文件。无论是创建、读取还是编辑ExcelPOI库都提供了简单且丰富的API来满足我们的需求。通过将POI带入Excel,我们可以方便地实现Excel文件的下载功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值