日常在做后台系统的时候会很频繁的遇到Excel导入导出的问题,正好这次在做一个后台系统,就想着写一个公用工具来进行Excel的导入导出。
一般我们在导出的时候都是导出的前端表格,而前端表格同时也会对应的在后台有一个映射类。
所以在写这个工具的时候我们先理一下我们需要实现的效果:
导出方法接收一个list集合,和一个Class类型,和HttpServletResponse对象
导出是可能会有下拉列表,所以需要一个map存储下拉列表数据源,传入参数后只需一行代码即可导出
导入方法需要传入file文件,以及一个Class类型,导入之后将会返回一个list集合,里面的对象就是传入类型的对象,传入参数后只需一行代码即可导入
实现过程:
首先需要创建三个注解
一个是EnableExport,必须有这个注解才能导出
/***设置允许导出*/@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public@interfaceEnableExport{StringfileName;}
然后就是EnableExportField,有这个注解的字段才会导出到Excel里面,并且可以设置列宽
/***设置该字段允许导出*并且可以设置宽度*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public@interfaceEnableExportField{intcolWidthdefault100;StringcolName;}
再就是ImportIndex,导入的时候设置Excel中的列对应的序号
/***导入时索引*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public@interfaceImportIndex{intindex;}
注解使用示例
三个注解创建好之后就需要开始操作Excel了
首先,导入方法。在后台接收到前端上传的Excel文件之后,使用poi来读取Excel文件
我们根据传入的类型上面的字段注解的顺序来分别为不同的字段赋值,然后存入集合中,再返回
代码如下:
/***将Excel转换为对象集合*@paramexcelExcel文件*@paramclazzpojo类型*@return*/publicstaticList<Object>parseExcelToList(Fileexcel,Classclazz){List<Object>res=newArrayList<>;//创建输入流,读取ExcelInputStreamis=;Sheetsheet=;try{is=newFileInputStream(excel.getAbsolutePath);if(is!=){Workbookworkbook=WorkbookFactory.create(is);//默认只获取第一个工作表sheet=workbook.getSheetAt(0);if(sheet!=){//前两行是标题inti=2;Stringvalues;Rowrow=sheet.getRow(i);while(row!=){//获取单元格数目intcellNum=row.getPhysicalNumberOfCells;values=newString[cellNum];for(intj=0;j<=cellNum;j){Cellcell=row.getCell(j);if(cell!=){//设置单元格内容类型cell.setCellType(Cell.CELL_TYPE_STRING);//获取单元格值Stringvalue=cell.getStringCellValue==?:cell.getStringCellValue;values[j]=value;}}Fieldfields=clazz.getDeclaredFields;Objectobj=clazz.newInstance;for(Fieldf:fields){if(f.isAnnotationPresent(ImportIndex.class)){ImportIndexannotation=f.getDeclaredAnnotation(ImportIndex.class);intindex=annotation.index;f.setAccessible(true);//此处使用了阿里巴巴的fastjson包里面的一个类型转换工具类Objectval=TypeUtils.cast(values[index],f.getType,);f.set(obj,val);}}res.add(obj);i;row=sheet.getRow(i);}}}}catch(Exceptione){e.printStackTrace;}returnres;}
接下来就是导出方法。
导出分为几个步骤:
建立一个工作簿,也就是类型新建一个Excel文件
建立一张sheet表
设置标的行高和列宽
绘制标题和表头
这两个方法是自定义方法,代码会贴在后面
写入数据到Excel
创建下拉列表
写入文件到response
到这里导出工作就完成了
下面是一些自定义方法的代码
/***获取一个基本的带边框的单元格*@paramworkbook*@return*/privatestaticHSSFCellStylegetBasicCellStyle(HSSFWorkbookworkbook){HSSFCellStylehssfcellstyle=workbook.createCellStyle;hssfcellstyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);hssfcellstyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);hssfcellstyle.setBorderRight(HSSFCellStyle.BORDER_THIN);hssfcellstyle.setBorderTop(HSSFCellStyle.BORDER_THIN);hssfcellstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);hssfcellstyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);hssfcellstyle.setWrapText(true);returnhssfcellstyle;}/***获取带有背景色的标题单元格*@paramworkbook*@return*/privatestaticHSSFCellStylegetTitleCellStyle(HSSFWorkbookworkbook){HSSFCellStylehssfcellstyle=getBasicCellStyle(workbook);hssfcellstyle.setFillForegroundColor((short)HSSFColor.CORNFLOWER_BLUE.index);//设置背景色hssfcellstyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);returnhssfcellstyle;}/***创建一个跨列的标题行*@paramworkbook*@paramhssfRow*@paramhssfcell*@paramhssfsheet*@paramallColNum*@paramtitle*/privatestaticvoidcreateTitle(HSSFWorkbookworkbook,HSSFRowhssfRow,HSSFCellhssfcell,HSSFSheethssfsheet,intallColNum,Stringtitle){//在sheet里增加合并单元格CellRangeAddresscra=newCellRangeAddress(0,0,0,allColNum);hssfsheet.addMergedRegion(cra);//使用RegionUtil类为合并后的单元格添加边框RegionUtil.setBorderBottom(1,cra,hssfsheet,workbook);//下边框RegionUtil.setBorderLeft(1,cra,hssfsheet,workbook);//左边框RegionUtil.setBorderRight(1,cra,hssfsheet,workbook);//有边框RegionUtil.setBorderTop(1,cra,hssfsheet,workbook);//上边框//设置表头hssfRow=hssfsheet.getRow(0);hssfcell=hssfRow.getCell(0);hssfcell.setCellStyle(getTitleCellStyle(workbook));hssfcell.setCellType(HSSFCell.CELL_TYPE_STRING);hssfcell.setCellValue(title);}/***设置表头标题栏以及表格高度*@paramworkbook*@paramhssfRow*@paramhssfcell*@paramhssfsheet*@paramcolNames*/privatestaticvoidcreateHeadRow(HSSFWorkbookworkbook,HSSFRowhssfRow,HSSFCellhssfcell,HSSFSheethssfsheet,List<String>colNames){//插入标题行hssfRow=hssfsheet.createRow(1);for(inti=0;i<colNames.size;i){hssfcell=hssfRow.createCell(i);hssfcell.setCellStyle(getTitleCellStyle(workbook));hssfcell.setCellType(HSSFCell.CELL_TYPE_STRING);hssfcell.setCellValue(colNames.get(i));}}/***excel添加下拉数据校验*@paramsheet哪个sheet页添加校验*@return*/publicstaticvoidcreateDataValidation(Sheetsheet,Map<Integer,String[]>selectListMap){if(selectListMap!=){selectListMap.forEach(//第几列校验(0开始)key数据源数组value(key,value)->{if(value.length>0){CellRangeAddressListcellRangeAddressList=newCellRangeAddressList(2,65535,key,key);DataValidationHelperhelper=sheet.getDataValidationHelper;DataValidationConstraintconstraint=helper.createExplicitListConstraint(value);DataValidationdataValidation=helper.createValidation(constraint,cellRangeAddressList);//处理Excel兼容性问题if(dataValidationinstanceofXSSFDataValidation){dataValidation.setSuppressDropDownArrow(true);dataValidation.setShowErrorBox(true);}else{dataValidation.setSuppressDropDownArrow(false);}dataValidation.setEmptyCellAllowed(true);dataValidation.setShowPromptBox(true);dataValidation.createPromptBox("提示","只能选择下拉框里面的数据");sheet.addValidationData(dataValidation);}});}}
使用实例
导出数据
导入数据(返回对象List)