通过poi依赖将java对象写入excel之中,核心理念是通过反射获取Java对象的getter方法和属性,使用getter方法获取要写入excel中的值,再通过属性上的自定义注解获取excel标题行,然后以文件流的方式写入excel

代码用到poi依赖如下:

 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.17</version></dependency>

首先我们定义注解@ExcelTitle,用来初始化excel第一行作为标题行

/*** excel标题头注解,当Java属性没有使用此注解,则默认使用Java属性作为标题。*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelTitle {String value();
}

然后定义对象转excel工具类ExcelWriterUtil

import com.sc.ops.annotations.ExcelTitle;
import com.sc.ops.annotations.Order;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
/*** 对象转excel工具类*/
@Slf4j
public class ExcelWriterUtil{private static ThreadLocal<ExcelValueFormatter> valueFormatter = ThreadLocal.withInitial(() -> new DateValueFormatter("yyyy-MM-dd"));public static void setExcelValueFormatter(ExcelValueFormatter excelValueFormatter) {valueFormatter.set(excelValueFormatter);}public static <E> void writeToExcel(List<E> list, Class<E> clazz, String fileName)throws InvocationTargetException, IllegalAccessException {@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")List<Object[]> dataList = new ArrayList<>();Field[] fields = getAllFields(clazz);Map<String, Method> fieldMethodMap = buildFieldMethodMap(clazz);sortMethodMap(fields, fieldMethodMap);Map<String, String> fieldTitleMap = buildFieldTitleMap(clazz, fieldMethodMap);List<Map.Entry<String, Method>> methodEntrySet = new ArrayList<>(fieldMethodMap.entrySet());int addMark = 0;int itemSize = fieldTitleMap.size();String[] titleArr = new String[itemSize];for (E obj : list) {Object[] item = new Object[itemSize];for (int i = 0; i < methodEntrySet.size(); i++) {Map.Entry<String, Method> methodEntry = methodEntrySet.get(i);String field = methodEntry.getKey();if (addMark < itemSize) {titleArr[addMark] = fieldTitleMap.get(field);addMark++;}Method method = methodEntry.getValue();Object value = formatValue(method, obj, valueFormatter.get());if (value != null) {item[i] = value;}}dataList.add(item);}writeObjectToExcel(dataList, titleArr, fileName);}private static Object formatValue(Method method, Object obj,ExcelValueFormatter excelValueFormatter)throws InvocationTargetException, IllegalAccessException {Object value = method.invoke(obj);if (value == null) {return null;}if(excelValueFormatter == null) {return value;}Class<?> returnType = method.getReturnType();return excelValueFormatter.formatValue(returnType, value);}private static <E> Map<String, Method> buildFieldMethodMap(Class<E> clazz) {List<Method> getMethods = Arrays.stream(clazz.getMethods()).filter(method -> method.getName().startsWith("get") && !method.getName().equals("getClass")).collect(Collectors.toList());Map<String, Method> fieldMethodMap = new LinkedHashMap<>();for (Method getMethod : getMethods) {String m = getMethod.getName().replace("get", "");String field = m.substring(0, 1).toLowerCase() + m.substring(1);fieldMethodMap.put(field, getMethod);}return fieldMethodMap;}public static <E> Field[] getAllFields(Class<E> clazz){List<Field> fieldList = new ArrayList<>();while (clazz != null){fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));clazz = (Class<E>) clazz.getSuperclass();}Field[] fields = new Field[fieldList.size()];fieldList.toArray(fields);return fields;}private static <E> Map<String, String> buildFieldTitleMap(Class<E> clazz,Map<String, Method> fieldMethodMap) {Map<String, String> fieldTitleMap = new LinkedHashMap<>();Field[] fields = getAllFields(clazz);Arrays.stream(fields).forEach(field -> {if (fieldMethodMap.containsKey(field.getName())) {ExcelTitle excelTitle = field.getAnnotation(ExcelTitle.class);String title = excelTitle == null ? field.getName() : excelTitle.value();fieldTitleMap.put(field.getName(), title);}});return fieldTitleMap;}private static void writeObjectToExcel(List<Object[]> list, String[]excelTitle, String fileName) {//在内存中创建Excel文件Workbook workbook;if (fileName.endsWith("xls")) {workbook = new HSSFWorkbook();} else if (fileName.endsWith("xlsx")) {workbook = new XSSFWorkbook();} else {throw new IllegalArgumentException("fileName not legal");}Sheet sheet = workbook.createSheet();//标题行Row titleRow = sheet.createRow(0);for (int i = 0; i < excelTitle.length; i++) {titleRow.createCell(i).setCellValue(excelTitle[i]);}//创建数据行并写入值for (Object[] dataArr : list) {int lastRowNum = sheet.getLastRowNum();Row dataRow = sheet.createRow(lastRowNum + 1);for (int i = 0; i < dataArr.length; i++) {Cell cell = dataRow.createCell(i);Object cellValue = dataArr[i];if(cellValue != null) {setCellValue(cellValue, cell);}}}//创建输出流对象FileOutputStream outputStream = null;try {outputStream = new FileOutputStream(new File(fileName));} catch (FileNotFoundException e) {log.error("file not found", e);}try {workbook.write(outputStream);} catch (IOException e) {log.error("write to file failed", e);} finally {if (outputStream != null) {try {outputStream.close();} catch (IOException ignore) {}}}}private static void setCellValue(Object cellValue, Cell cell) {if (cellValue instanceof Boolean) {cell.setCellValue((boolean) cellValue);} else if (cellValue instanceof String) {cell.setCellValue(cellValue.toString());} else if (cellValue instanceof Double || cellValue instanceof Integer|| cellValue instanceof Long) {cell.setCellValue(Double.valueOf(cellValue.toString()));} else if (cellValue instanceof Date) {cell.setCellValue((Date) cellValue);} else if (cellValue instanceof Calendar) {cell.setCellValue((Calendar) cellValue);} else if (cellValue instanceof RichTextString) {cell.setCellValue((RichTextString) cellValue);} else {cell.setCellValue(cellValue.toString());}}private static void sortMethodMap(Field[] fields, Map<String, Method> fieldMethodMap) {Set<String> fieldSet = fieldMethodMap.keySet();List<Field> fieldList = Arrays.stream(fields).filter(e -> fieldSet.contains(e.getName())).collect(Collectors.toList());fields = fieldList.toArray(new Field[]{});Arrays.sort(fields, (o1, o2) -> {Order order1 = o1.getAnnotation(Order.class);Order order2 = o2.getAnnotation(Order.class);if (order1 == null && order2 == null) { //均不含注解时不排序return 0;}if (order1 == null) { //order1 == null && order2 != null 仅有一个含有注解时,默认排到不含注解的后面return -1;}if (order2 == null) { //order1 != null && order2 == null 仅有一个含有注解时,默认排到不含注解的后面return 1;}return order1.value() - order2.value();//均含有注解时,按照注解值从小到大排序});Map<String, Method> sortedMethodMap = new LinkedHashMap<>();Arrays.stream(fields).forEach(e -> {String key = e.getName();sortedMethodMap.put(key, fieldMethodMap.get(key));});fieldMethodMap.clear();fieldMethodMap.putAll(sortedMethodMap);}
}

这个工具类涉及到一个自定义的接口ExcelValueFormatter,它用来实现将不同类型的java属性映射到不同的excel单元格格式。由于ExcelValueFormatter是个接口,所以你可以实现它,自定义不同的映射策略。

public interface ExcelValueFormatter {Object formatValue(Class<?> returnType, Object value);
}

本案例提供一个默认的实现类DateValueFormatter,将Date类型的属性转换为格式为yyyy-MM-dd的文本。

@Data
@AllArgsConstructor
public class DateValueFormatter implements ExcelValueFormatter {private String dateFormat;@Overridepublic Object formatValue(Class<?> returnType, Object value) {if (returnType.equals(Date.class)) {return DateTimeFormatter.ofPattern(dateFormat).format(toLocalDateTime((Date) value));} else {return value;}}private static LocalDateTime toLocalDateTime(Date date) {Instant instant = date.toInstant();ZoneId zoneId = ZoneId.systemDefault();return instant.atZone(zoneId).toLocalDateTime();}
}

为了能让列顺序不被打乱,我们最直接的方法就是给成员指定它的位置是几,也就是定义顺序编号,首先声明一个注解@Order,它只能用于类成员上:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Order {int value();
}

然后通过反射获取每个成员上的该注解,并进行排序:

  private static void sortMethodMap(Field[] fields, Map<String, Method> fieldMethodMap) {Set<String> fieldSet = fieldMethodMap.keySet();List<Field> fieldList = Arrays.stream(fields).filter(e -> fieldSet.contains(e.getName())).collect(Collectors.toList());fields = fieldList.toArray(new Field[]{});Arrays.sort(fields, (o1, o2) -> {Order order1 = o1.getAnnotation(Order.class);Order order2 = o2.getAnnotation(Order.class);if (order1 == null && order2 == null) { //均不含注解时不排序return 0;}if (order1 == null) { //order1 == null && order2 != null 仅有一个含有注解时,默认排到不含注解的后面return -1;}if (order2 == null) { //order1 != null && order2 == null 仅有一个含有注解时,默认排到不含注解的后面return 1;}return order1.value() - order2.value();//均含有注解时,按照注解值从小到大排序});Map<String, Method> sortedMethodMap = new LinkedHashMap<>();Arrays.stream(fields).forEach(e -> {String key = e.getName();sortedMethodMap.put(key, fieldMethodMap.get(key));});fieldMethodMap.clear();fieldMethodMap.putAll(sortedMethodMap);}

最后做个简单的测试。

在Student的成员上添加@Order指定相对位置:

    @Data@AllArgsConstructorpublic static class Student {@ExcelTitle("id")@Order(1)private Integer id;@ExcelTitle("姓名")@Order(2)private String name;@ExcelTitle("薪水")@Order(4)private Double salary;@ExcelTitle("生日")@Order(3)private Date birthDay;}

测试代码:

    public static void main(String[] args) {try {List<Student> students = new ArrayList<>();for (int i = 0; i < 100; i++) {students.add(new Student(i, "member" + i, i * 55D, new Date()));}ExcelWriter.writeToExcel(students, Student.class, "/Users/Downloads/test.xlsx");} catch (Exception ex) {ex.printStackTrace();}}@Data@AllArgsConstructorpublic static class Student {@ExcelTitle("id")private Integer id;@ExcelTitle("姓名")private String name;@ExcelTitle("薪水")private Double salary;@ExcelTitle("生日")private Date birthDay;}

结果如下:

Java将List对象导入Excel文件相关推荐

  1. java txt数据导入excel,java导入excle文件《如何用java 将txt数据导入excel》

    如何用java 将txt数据导入excel 代码如下: import java.io.*; import jxl.*; import jxl.write.*; public class CreateX ...

  2. 关于使用Java后台导入excel文件,读取数据后,更新数据库,并返回数据给到前端的相关问题总结

    在之前的项目中,使用到了Java后台读取excel文件数据的功能点,本想着该功能点已经做过了,这一类的应该都大差不离,不过在刚结束的一个项目中,现实给我深深的上了一课,特此编写此片博客,以作记录,并给 ...

  3. JAVA 导入excel文件

    JAVA 导入excel文件 背景 –>struts2框架 –>from表单提交excel模板文件 –>java获取excel数据 步骤 1.获取excel文件 struts2 fr ...

  4. SpringMVC导入Excel文件到MySQL

    转载自 https://blog.csdn.net/wdehxiang/article/details/77619677 使用SpringMVC导入Excel文件到MySQL时,由于是第一次做,所以走 ...

  5. 如何优雅的用POI导入Excel文件

    在企业级项目开发中,要经常涉及excel文件和程序之间导入导出的业务要求,那么今天来讲一讲excel文件导入的实现.java实现对excel的操作有很多种方式,例如EasyExcel等,今天我们使用的 ...

  6. wxwidgets mysql_wxWidgets导入Excel文件详细教程

    开始写教师端程序,首先要实现导入EXCEL文件,读取数据后再添加到mysql数据库.wxWidgets提供了wxAutomationObject类,用来调用OLE automation的方法.网上找到 ...

  7. KnockOut+TypeScript+上传图片(oos功能)以及导入Excel文件(oos功能)并回显插入

    没有看过oos配置的可以参考我的另一边文章oos配置 废话不多说,上正文 一:上传图片 1.前端: <div class="gift-form"><label&g ...

  8. 导入excel文件处理流程节点的解决方案

    导入excel文件处理流程节点的解决方案 参考文章: (1)导入excel文件处理流程节点的解决方案 (2)https://www.cnblogs.com/webreport/archive/2012 ...

  9. python打开excel数据库_使用python导入excel文件中的mssql数据库数据

    我试图用python导入excel文件中的mssql数据库数据.我的数据在excel表格中的顺序不正确.e. g它显示第1列数据,然后是第3列,第2列,然后是第4列,依此类推. 我使用以下脚本:imp ...

最新文章

  1. eclipse 对齐行号在括号中显示和字体调整
  2. [kubernetes] 资源管理 ---- 资源请求和限制
  3. c++ 转bcd码_8421BCD码转换为十进制
  4. 《scikit-learn》数据预处理与特征工程(二)数值转换
  5. 细说Python Lambda函数的用法,建议收藏!
  6. 【英语学习】4000 Words 【V1】【U01】The Lion and the Rabbit
  7. 17 类的成员 私有
  8. 《计算机操作系统》思维导图
  9. MTK改串工具,mtk刷机工具,高通刷机工具,MTK生成线刷包工具资料下载
  10. 无人驾驶感知篇之车载摄像头
  11. 正则表达式匹配以xx开头以xx结尾
  12. day04-selenium滚动和常见反爬
  13. 常见开源Java论坛(附JForum论坛安装以及部署)
  14. win10系统盘清理彻底的方法
  15. SQL Server练习
  16. CSS从入门到精通——文本与字体样式1.0
  17. 北大邹磊:图数据库中的子图匹配算法
  18. 20189220 余超《Linux内核原理与分析》第九周作业
  19. 【2012NOIP普及组】T1. 质因数分解 试题解析
  20. vue+echarts饼状图中间计算总数

热门文章

  1. 用20门编程语言说生日快乐/我爱你
  2. UML软件开发与建模工具Enterprise Architect发布最新版本v15.2
  3. 2模矩阵转换成1模矩阵
  4. 【干货】新显卡太贵,便宜老卡怎么选?二手亮机卡过渡指南!
  5. 一起零基础学Python
  6. 每日一题:1894.找到需要补充粉笔的学生编号 简单的模拟题目,注意求余的技巧!...
  7. 【安全头条】美国政府起诉 Kochava 出售敏感的地理位置数据
  8. SNETCracker:开源的超级弱口令检查审计工具,支持批量多线程
  9. 高并发高可用之ElasticSearch
  10. 什么是signal(SIGCHLD, SIG_IGN)函数