一个导出数据的功能模块的优化过程
业务场景:从学生数据库导出一张表为Excel
-
Excel导出工具类
/** * @author Cao Jiwen * @version V1.0 */ public class ExcelExportUtil { /** * @param outputStream 输出流 * @param columnList 列名列表 * @param dataList 数据列表 */ public static void export(OutputStream outputStream, List<String> columnList,List<List<String>> dataList) throws IOException { //excel文件主题对象 SXSSFWorkbook wb = null; try{ //内存的最大行数,防止内存溢出 wb = new SXSSFWorkbook(1000); //创建一个sheet SXSSFSheet sheet1 = wb.createSheet("数据"); //行索引 int excelRow = 0; //创建第一行,列名行 Row titleRow = sheet1.createRow(excelRow++); if (ObjectUtil.isNotEmpty(columnList)){ //遍历列名表 for (int i = 0; i < columnList.size(); i++) { //创建一个单元格 Cell cell = titleRow.createCell(i); //设置单元格的值 cell.setCellValue(columnList.get(i)); } } if (ObjectUtil.isNotEmpty(dataList)){ for (int i = 0; i < dataList.size(); i++) { //创建数据行 Row dataRow = sheet1.createRow(excelRow++); //遍历出单个数据 for (int j = 0; j < dataList.get(0).size(); j++) { Cell cell = dataRow.createCell(j); cell.setCellValue(dataList.get(i).get(j)); } } } wb.write(outputStream); }catch (Exception e){ e.printStackTrace(); throw e; }finally { if (wb != null){ wb.close(); } if (outputStream != null){ outputStream.close(); } } } }
-
导出过程
public static void main(String[] args) throws IOException { //调用方角度 //查询数据 Student student1 = new Student("luoxi", 18); Student student2 = new Student("jixian", 19); //创建输出流 FileOutputStream fileOutputStream = new FileOutputStream("D:\\Javaproject\\ myApp\\exportItem\\src\\main\\java\\学生信息表.xlsx"); //创建列名列表 List<String> columList = new ArrayList<>(); columList.add("姓名"); columList.add("年龄"); //创建数据列表 List<List<String>> dataList = new ArrayList<>(); //创建单条数据列表 List<String> data1 = new ArrayList<>(); List<String> data2 = new ArrayList<>(); data1.add(student1.getName()); data1.add(student1.getAge().toString()); data2.add(student2.getName()); data2.add(student2.getAge().toString()); dataList.add(data1); dataList.add(data2); ExcelExportUtil.export(fileOutputStream,columList,dataList); }
-
使用反馈
最直接的感受就是,被调用方每次都需要一次一次的创建列表,再从对象中提取数据,非常麻烦
-
代码改进
第一步:反射改进
不传列表,那就直接传对象,那就要从对象中自己提取数据,对象我事先不知道的,所以要用到反射
/** * @param outputStream 输出流 * @param columList 列名列表 * @param dataList 数据列表 */ public static void reflectExport(OutputStream outputStream,List<String> columList,List dataList) throws IllegalAccessException, IOException { //健壮性检验 if (ObjectUtil.isEmpty(dataList)){ return; } List<List<String>> allList = new ArrayList<>(); //获取class文件 Class<?> aClass = dataList.get(0).getClass(); //通过class文件获取对象属性 Field[] declaredFields = aClass.getDeclaredFields(); for (int i = 0; i < dataList.size(); i++) { List<String> list = new ArrayList<>(); for (int j = 0; j < declaredFields.length; j++) { //由于属性是private修饰,将可见性设为true Field declareField = declaredFields[j]; declareField.setAccessible(true); Object o = declareField.get(dataList.get(i)); if (o != null){ list.add(o.toString()); } } allList.add(list); } export(outputStream,columList,allList); }
继续优化:如果不想导出对象的全部数据呢
第二步:注解改进
- 不想导出全部属性,可以通过给属性标记
- 将导出的属性排序,通过注解上的信息,标记属性的顺序
//在运行时生效 @Retention(RetentionPolicy.RUNTIME) //目标注解,标识属性 @Target(ElementType.FIELD) public @interface Excel { int order(); }
public class Student { private String id; @Excel(order = 1) private String name; @Excel(order = 2) private Integer age; }
public static void reflectExport(OutputStream outputStream,List<String> columList,List dataList) throws IllegalAccessException, IOException { //健壮性检验 if (ObjectUtil.isEmpty(dataList)){ return; } List<List<String>> allList = new ArrayList<>(); //获取class文件 Class<?> aClass = dataList.get(0).getClass(); //通过class文件获取对象属性 Field[] declaredFields = aClass.getDeclaredFields(); //排除没有被标记的属性 List<Field> fields = Arrays.asList(declaredFields).stream().filter(field -> field.isAnnotationPresent(Excel.class)).collect(Collectors.toList()); //属性排序 fields = fields.stream().sorted(Comparator.comparingInt(field -> field.getAnnotation(Excel.class).order())).collect(Collectors.toList()); for (int i = 0; i < dataList.size(); i++) { List<String> list = new ArrayList<>(); for (int j = 0; j < fields.size(); j++) { Field declareField = fields.get(j); declareField.setAccessible(true); Object o = declareField.get(dataList.get(i)); if (o != null){ list.add(o.toString()); } } allList.add(list); } export(outputStream,columList,allList); }