目录
背景
最近项目需要导出数据到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); } } }
结果:
能力一般,水平有限,如果错误请指出。