java 导出Excel表格通用方法

简介: java 导出Excel表格通用方法

目录

背景

最近项目需要导出数据到Excel 表格中,在包装好获取表格方法之后,剩下的就是往单元格中添加数据和添加标题。写了一两个地方之后发现设置数据这块东西基本都是类似的重复代码,无非就是设置的数据不一样而已,看到这样的代码就很烦,想把它们封装起来,首先想到的就是通过自定义注解的方式来实现。

POI版本

我用的是POI导出Excel,版本如下:

<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
      <dependency>
          <groupId>org.apache.poi</groupId>
          <artifactId>poi</artifactId>
          <version>4.1.1</version>
      </dependency>

自定义注解

首先就自定义了两个注解

1、EnableExcel

这个注解的作用是是否开启Excel表格的导出。

/**
 *  标记类是否开启Excel
 * @Author: Sunlong
 * @date: 2020/5/10 20:29
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableExcel {
}

2、ExcelRow

ExcelRow在属性上使用,对应着Excel中的列

/**
 *  excel 表格 列名注解
 *
 * @author sunlong
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelRow {
    /**
     *  Excel 对应列名
     * @return
     */
    String name();
    /**
     *  excel 列名备注
     * @return
     */
    String note() default "";
}

逻辑代码实现

1、通过反射获取自定义注解EnableExcel 判断是否开启Excel导出

2、通过反射获取自定义注解ExcelRow 获取列对应的属性

3、把属性对应的列下标取出来,属性名做为key,下标做为value放到map中

4、遍历要导出的数据集合,通过属性描述器PropertyDescriptor获取对应属性下标及属性值并设置到cell单元格中


代码如下:

public class ExcelUtils {
    /**
     *  workbook
     * @param titleList
     * @return
     */
    public static HSSFWorkbook getWorkBook(List<String> titleList){
        //第一步,创建一个workbook,对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();
        // 一个sheet
        HSSFSheet sheet = wb.createSheet("sheet1");
        HSSFRow rowTitle = sheet.createRow(0); // 第一行 标题
        // 设置标题
        for (int i = 0; i < titleList.size(); i++) {
            HSSFCell cell = rowTitle.createCell(i);
            cell.setCellValue(titleList.get(i));
        }
        //合并单元格CellRangeAddress构造参数依次表示起始行,截至行,起始列, 截至列
        /*sheet.addMergedRegion(new CellRangeAddress(0,0,0,4));
        sheet.addMergedRegion(new CellRangeAddress(titleList.size()-1,titleList.size()-1,titleList.size()-1,titleList.size()+1));*/
        return wb;
    }
    public static <T> HSSFWorkbook getWorkBook(List<String> titleList , List<T> dataList) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        if (CollectionUtils.isNotEmpty(dataList)) {
            T t1 = dataList.get(0);
            Class<?> t1Class = t1.getClass();
            EnableExcel enableExcel = t1Class.getAnnotation(EnableExcel.class);
            if (enableExcel == null) {
                throw new IllegalArgumentException("EnableExcel 注解没有在实体类启用");
            }
            Field[] fields = t1Class.getDeclaredFields();
            if (fields != null && fields.length > 0) {
                Map<String , Integer> titleMap = new HashMap<>(titleList.size()); // 存放属性名称对应的下标
                int fieldExcelSize = 0; // 类中ExcelRow 注解的数量
                for (Field field : fields) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    ExcelRow excelRow = field.getAnnotation(ExcelRow.class);
                    if (excelRow != null) {
                        String name = excelRow.name();
                        if (StringUtils.isEmpty(name)) {
                            throw new IllegalArgumentException("ExcelRow 注解name属性不能为空");
                        }
                        int index = titleList.indexOf(name.trim());
                        if (index != -1) {
                            fieldExcelSize++;
                            titleMap.put(fieldName , index);
                        }
                    }
                }
                if (!(titleList.size() == fieldExcelSize)) {
                    throw new IllegalArgumentException("ExcelRow 注解name属性对应的列数不对");
                }
                HSSFWorkbook workBook = getWorkBook(titleList);
                HSSFSheet sheet = workBook.getSheetAt(0);
                for (T t : dataList) {
                    int lastRowNum = sheet.getLastRowNum();
                    HSSFRow row = sheet.createRow(lastRowNum + 1);
                    BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
                    PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
                    for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                        String fieldName = propertyDescriptor.getName();
                        if (titleMap.containsKey(fieldName)) {
                            Method readMethod = propertyDescriptor.getReadMethod();
                            if (readMethod != null) {
                                Class<?> returnType = readMethod.getReturnType();
                                String simpleName = returnType.getSimpleName();
                                Object invoke = readMethod.invoke(t);
                                String value = "";
                                // 可以根据不同的类型返回不同的数据
                                if ("date".equalsIgnoreCase(simpleName)) {
                                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                    if (invoke != null) {
                                        value = simpleDateFormat.format(invoke);
                                    }
                                }
                                if (invoke != null && "".equals(value)) {
                                    value = invoke.toString();
                                }
                                row.createCell(titleMap.get(fieldName)).setCellValue(value);
                            }
                        }
                    }
                }
                return workBook;
            }
        }
        return null;
    }
}

测试

@EnableExcel
@Data
public class UserEntity {
    @ExcelRow(name = "name")
    private String username;
    @ExcelRow(name = "pass")
    private String password;
    @ExcelRow(name = "date")
    private Date createDate;
}
public class Test {
    public static void main(String[] args) throws IllegalAccessException, IntrospectionException, InvocationTargetException, IOException {
        List<String> titleList = new ArrayList<>();
        titleList.add("name");
        titleList.add("pass");
        titleList.add("date");
        List<UserEntity> userEntities = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            UserEntity userEntity1 = new UserEntity();
            userEntity1.setUsername("username"+i);
            userEntity1.setPassword("password"+i);
            userEntity1.setCreateDate(new Date());
            userEntities.add(userEntity1);
        }
        HSSFWorkbook workBook = ExcelUtils.getWorkBook(titleList, userEntities);
        if (workBook != null) {
            File file = new File("D:\\1.xlsx");
            workBook.write(file);
        }
    }
}

结果:

image.png

能力一般,水平有限,如果错误请指出。

目录
相关文章
|
1月前
|
消息中间件 Java Kafka
在Java中实现分布式事务的常用框架和方法
总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
|
29天前
|
安全 Java 开发者
Java中WAIT和NOTIFY方法必须在同步块中调用的原因
在Java多线程编程中,`wait()`和`notify()`方法是实现线程间协作的关键。这两个方法必须在同步块或同步方法中调用,这一要求背后有着深刻的原因。本文将深入探讨为什么`wait()`和`notify()`方法必须在同步块中调用,以及这一机制如何确保线程安全和避免死锁。
41 4
|
29天前
|
Java
深入探讨Java中的中断机制:INTERRUPTED和ISINTERRUPTED方法详解
在Java多线程编程中,中断机制是协调线程行为的重要手段。了解和正确使用中断机制对于编写高效、可靠的并发程序至关重要。本文将深入探讨Java中的`Thread.interrupted()`和`Thread.isInterrupted()`方法的区别及其应用场景。
29 4
|
27天前
|
Java 数据处理 数据安全/隐私保护
Java处理数据接口方法
Java处理数据接口方法
26 1
|
1月前
|
前端开发
实现Excel文件和其他文件导出为压缩包,并导入
实现Excel文件和其他文件导出为压缩包,并导入
30 1
|
1月前
|
数据格式 UED
记录一次NPOI库导出Excel遇到的小问题解决方案
【11月更文挑战第16天】本文记录了使用 NPOI 库导出 Excel 过程中遇到的三个主要问题及其解决方案:单元格数据格式错误、日期格式不正确以及合并单元格边框缺失。通过自定义单元格样式、设置数据格式和手动添加边框,有效解决了这些问题,提升了导出文件的质量和用户体验。
176 3
|
23天前
|
数据采集 数据可视化 数据挖掘
利用Python自动化处理Excel数据:从基础到进阶####
本文旨在为读者提供一个全面的指南,通过Python编程语言实现Excel数据的自动化处理。无论你是初学者还是有经验的开发者,本文都将帮助你掌握Pandas和openpyxl这两个强大的库,从而提升数据处理的效率和准确性。我们将从环境设置开始,逐步深入到数据读取、清洗、分析和可视化等各个环节,最终实现一个实际的自动化项目案例。 ####
|
2月前
|
数据采集 存储 JavaScript
自动化数据处理:使用Selenium与Excel打造的数据爬取管道
本文介绍了一种使用Selenium和Excel结合代理IP技术从WIPO品牌数据库(branddb.wipo.int)自动化爬取专利信息的方法。通过Selenium模拟用户操作,处理JavaScript动态加载页面,利用代理IP避免IP封禁,确保数据爬取稳定性和隐私性。爬取的数据将存储在Excel中,便于后续分析。此外,文章还详细介绍了Selenium的基本设置、代理IP配置及使用技巧,并探讨了未来可能采用的更多防反爬策略,以提升爬虫效率和稳定性。
158 4
|
4月前
|
关系型数据库 MySQL Shell
不通过navicat工具怎么把查询数据导出到excel表中
不通过navicat工具怎么把查询数据导出到excel表中
54 0
|
2月前
|
数据处理 Python
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档
这篇文章介绍了如何使用Python读取Excel文件中的数据,处理后将其保存为txt、xlsx和csv格式的文件。
110 3
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档