栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

利用注解+反射优雅的实现Excel的导入导出

Java 更新时间:发布时间: 百科书网 趣学号

刚毕业那会儿写过一个 通用的excel导入导出工具类.
这个工具类呢也用了挺久了的,有兴趣的也可以去看一下哈。
最近呢又新写了一个 基于注解+反射实现的Excel导入导出 工具类,具体请看下文

导入方法传入Excel文件输入流,以及一个Class类型
导出方法接收一个list集合,和一个Class类型

#实现过程

首先需要创建三个注解

一个是 EnableExcelimport,必须有这个注解才能导入

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableExcelimport {
    
    String sheetName() default "";
    
    int sheetAt() default 0;
    
    int startRow() default 0;
}

然后是EnableExcelExport,必须有这个注解才能导出到Excel里面

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableExcelExport {
    
    String fileType() default "xlsx";
    
    String sheetName() default "";
    
    boolean isIncludeHeader() default false;
    
    int startRow() default 0;
    
    short startColumn() default 0;
}

再就是SheetColumn,实体类字段上有这个注解才导出或者导入该字段

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SheetColumn {
    
    String name() default "";
    
    int index() default -1;
    
    int width() default 4;
    
    boolean required() default false;
    
    boolean imported() default true;
    
    boolean exported() default true;
}

注解使用示例

@EnableExcelimport(startRow = 1)
@EnableExcelExport(fileName = "test", isIncludeHeader = true)
public class Employee {

    @SheetColumn(name = "姓名", required = true)
    private String fullName;
    @SheetColumn(name = "性别", width = 3, required = true)
    private String gender;
    @SheetColumn(name = "年龄", width = 3, required = true)
    private BigDecimal age;
    @SheetColumn(name = "地址", width = 15, required = true)
    private String address;
    @SheetColumn(name = "电话", width = 6, required = true)
    private String phone;
    @SheetColumn(name = "邮箱", width = 10, required = true)
    private String email;

    // getter and setter...
}
#三个注解创建好之后,下面就开始封装Excel导入导出的工具类了
public class ExcelUtils {

    public static final String EXCEL_XLS = "xls";

    
    public static  List parseExcelToList(InputStream inputStream, Class clazz) {
        List res = Lists.newArrayList();
        EnableExcelimport enableExcelimport = clazz.getAnnotation(EnableExcelimport.class);
        if (Objects.isNull(enableExcelimport)) {
            return res;
        }
        String sheetName = enableExcelimport.sheetName();
        int sheetAt = enableExcelimport.sheetAt();
        int startRow = enableExcelimport.startRow();
        Workbook wb;
        Sheet st;
        Row row;
        Cell cell;
        try {
            wb = WorkbookFactory.create(inputStream);
            st = StringUtils.isEmpty(sheetName) ? wb.getSheetAt(sheetAt) : wb.getSheet(sheetName);
            if (Objects.isNull(st)) {
                return res;
            }
            // 实体类的属性
            List fields = Arrays.stream(clazz.getDeclaredFields())
                    .filter(field -> field.isAnnotationPresent(SheetColumn.class)
                            && field.getAnnotation(SheetColumn.class).imported())
                    .collect(Collectors.toList());
            // 所有属性注解中列索引index最大值
            int maxIndex = fields.stream().mapToInt(item
                    -> item.getAnnotation(SheetColumn.class).index()).max().getAsInt();
            for (int i = startRow; i < st.getPhysicalNumberOfRows(); i++) {
                // 空行跳过
                if (Objects.isNull(row = st.getRow(i))) {
                    continue;
                }
                T object = clazz.newInstance();
                int currentIndex = maxIndex;
                for (Field field : fields) {
                    // 通过属性注解SheetColumn的列索引index取单元格的值
                    // 未指定index,即index为-1,则按照所有索引中最大索引+1取值,最大索引+1即为新的最大索引
                    SheetColumn sheetColumn = field.getAnnotation(SheetColumn.class);
                    int index = sheetColumn.index();
                    cell = index == -1 ? row.getCell(++currentIndex) : row.getCell(index);
                    String value = getCellValue(cell);
                    field.setAccessible(true);
                    Object val = TypeUtils.cast(value, field.getType(), null);
                    field.set(object, val);
                }
                res.add(object);
            }
        } catch (Exception e) {
            // 自定义处理
            e.printStackTrace();
        }
        return res;
    }

    
    private static String getCellValue(Cell cell) {
        if (Objects.isNull(cell)) {
            return null;
        }
        cell.setCellType(CellType.STRING);
        return cell.getStringCellValue();
    }

    
    public static  void writeListToWorkbook(List data, Class clazz, OutputStream outputStream) {
        Optional.ofNullable(writeListToWorkbook(data, clazz)).ifPresent(wb -> {
            try {
                wb.write(outputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    
    public static  Workbook writeListToWorkbook(List data, Class clazz) {
        EnableExcelExport enableExcelExport = clazz.getAnnotation(EnableExcelExport.class);
        if (Objects.isNull(enableExcelExport)) {
            return null;
        }
        Workbook wb;
        Sheet st;
        Row row;
        Cell cell;
        try {
            String sheetName = enableExcelExport.sheetName();
            boolean includeHeader = enableExcelExport.isIncludeHeader();
            int rowNum = enableExcelExport.startRow();
            short startColumn = enableExcelExport.startColumn();
            String fileType = enableExcelExport.fileType();
            // 实体类的属性
            List fields = Arrays.stream(clazz.getDeclaredFields())
                    .filter(field -> field.isAnnotationPresent(SheetColumn.class)
                            && field.getAnnotation(SheetColumn.class).exported())
                    .collect(Collectors.toList());
            // 所有属性注解中列索引index最大值
            int maxIndex = fields.stream().mapToInt(item -> item.getAnnotation(SheetColumn.class).index()).max().getAsInt();
            // 创建工作簿,默认类型为xlsx
            wb = EXCEL_XLS.equals(fileType) ? new HSSFWorkbook() : new XSSFWorkbook();
            st = wb.createSheet(StringUtils.isEmpty(sheetName) ? "Sheet1" : sheetName);
            row = null;
            int currentIndex = maxIndex;
            if (includeHeader) {
                row = st.createRow(rowNum++);
            }
            for (Field field : fields) {
                SheetColumn sheetColumn = field.getAnnotation(SheetColumn.class);
                int index = sheetColumn.index();
                int width = sheetColumn.width();
                // 通过属性注解SheetColumn的列索引index创建单元格
                // 未指定index,即index为-1,则按照所有索引中最大索引+1取值,最大索引+1即为新的最大索引
                index = (index == -1 ? ++currentIndex : index) + startColumn;
                // row已经被初始化说明需要创建表头
                if (Objects.nonNull(row)) {
                    String name = sheetColumn.name();
                    boolean required = sheetColumn.required();
                    cell = row.createCell(index);
                    fillCell(wb, cell, name, required);
                }
                // 列宽为-1为自适应列宽
                if (width == -1) {
                    st.autoSizeColumn(index);
                } else {
                    st.setColumnWidth(index, width * 2 * 256);
                }
            }
            for (T datum : data) {
                currentIndex = maxIndex;
                row = st.createRow(rowNum++);
                for (Field field : fields) {
                    SheetColumn sheetColumn = field.getAnnotation(SheetColumn.class);
                    int index = sheetColumn.index();
                    index = (index == -1 ? ++currentIndex : index) + startColumn;
                    cell = row.createCell(index);
                    field.setAccessible(true);
                    Object value = field.get(datum);
                    fillCell(wb, cell, value, false);
                }
            }
            return wb;
        } catch (Exception e) {
            // 自定义处理
            e.printStackTrace();
        }
        return null;
    }

    
    private static void fillCell(Workbook wb, Cell cell, Object value, boolean required) {
        // 必输列表头填充-浅黄色
        if (required) {
            CellStyle yStyle = wb.createCellStyle();
            yStyle.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.index);
            yStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            cell.setCellStyle(yStyle);
        }
        if (Objects.isNull(value)) {
            return;
        }
        switch (value.getClass().getName()) {
            case "java.lang.String":
                cell.setCellValue((String) value);
                break;
            case "java.lang.Integer":
                cell.setCellValue((Integer) value);
                break;
            case "java.lang.Long":
                cell.setCellValue((Long) value);
                break;
            case "java.lang.Float":
                cell.setCellValue((Float) value);
                break;
            case "java.lang.Double":
                cell.setCellValue((Double) value);
                break;
            case "java.math.BigDecimal":
                cell.setCellValue(Double.valueOf(String.valueOf(value)));
                break;
            case "java.lang.Boolean":
                cell.setCellValue((Boolean) value);
                break;
            case "java.util.Date":
                cell.setCellValue((Date) value);
                break;
            case "java.util.GregorianCalendar":
                cell.setCellValue((Calendar) value);
                break;
            case "org.apache.poi.xssf.usermodel.XSSFRichTextString":
                cell.setCellValue((XSSFRichTextString) value);
                break;
            default:
                return;
        }
    }
}

工具类封装好之后,直接调用即可。

工具类调用示例如下

    public static void main(String[] args) throws IOException {
        File file = new File("/Users/sch/DATA/Temp/11.xlsx");
        List employees = ExcelUtils.parseExcelToList(new FileInputStream(file.getAbsolutePath()), Employee.class);
        System.out.println(employees);

        File file1 = new File("/Users/sch/DATA/Temp/22.xlsx");
        if (!file1.exists()) {
            file1.createNewFile();
        }
        OutputStream outputStream = new FileOutputStream(file1);
        ExcelUtils.writeListToWorkbook(initData(), Employee.class, outputStream);
        outputStream.close();
    }

    private static List initData() {
        List employees = Lists.newArrayList();
        employees.add(new Employee("张三", "男", new BigDecimal(18), "广东省广州市龙洞地铁口A口天桥下", "15211111111", "zhangsan@sanchar.cn"));
        employees.add(new Employee("李四", "女", new BigDecimal(16), "广东省深圳市坪山区光祖公园小凉亭", "15299999999", "lisi@sanchar.cn"));
        employees.add(new Employee("王五", "男", new BigDecimal(21), "广西省桂林市灵川县桂林电子科技大学花江校区", "15288888888", "wangwu@sanchar.cn"));
        return employees;
    }

该工具类只是做了一些简单的封装,有兴趣的小伙伴或者该工具类未满足您当前的开发需求,可以基于该工具类进行二次封装处理哈,比如数据导出的时候excel表格需要有下拉框,必输字段非必输字段的颜色控制等都可以集成到该工具类里边

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/275713.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号