Java如何使用poi做加自定义注解实现对象与Excel相互转换
作者
这篇文章将为大家详细讲解有关Java如何使用poi做加自定义注解实现对象与Excel相互转换,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
引入依赖
maven
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency>
Gradle
implementationgroup:'org.apache.poi',name:'poi',version:'3.17'
代码展示
1、自定义注解类
@Retention(value=RetentionPolicy.RUNTIME) @Target(value=ElementType.FIELD) public@interfaceExcel{ Stringname();//列的名字 intwidth()default6000;//列的宽度 intindex()default-1;//决定生成的顺序 booleanisMust()defaulttrue;//是否为必须值,默认是必须的 }
2、Java的Excel对象,只展现了field,get与set方法就忽略了
publicclassGoodsExcelModel{ @Excel(name="ID_禁止改动",index=0,width=0) privateLongpicId;//picId @Excel(name="产品ID_禁止改动",index=1,width=0) privateLongproductId; @Excel(name="型号",index=3) privateStringproductName;//产品型号 @Excel(name="系列",index=2) privateStringseriesName;//系列名字 @Excel(name="库存",index=5) privateLongquantity; @Excel(name="属性值",index=4) privateStringpropValue; @Excel(name="价格",index=6) privateDoubleprice; @Excel(name="商品编码",index=7,isMust=false) privateStringouterId; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) privateLongdbId;//数据库自增长id privateDatecreateTime;//记录创建时间 }
3、Excel表格与对象转换的工具类,使用时指定泛型参数和泛型的class即可
publicclassExcelUtil{ privatestaticfinalStringGET="get"; privatestaticfinalStringSET="set"; privatestaticLoggerlogger=LoggerFactory.getLogger(ExcelUtil.class); /** *将对象转换成Excel * *@paramobjList需要转换的对象 *@return返回是poi中的对象 */ publicstaticHSSFWorkbooktoExcel(ListobjList){ if(CollectionUtils.isEmpty(objList))thrownewNullPointerException("无效的数据"); ClassaClass=objList.get(0).getClass(); Field[]fields=aClass.getDeclaredFields(); HSSFWorkbookworkbook=newHSSFWorkbook(); HSSFSheetsheet=workbook.createSheet(); for(inti=0;i<objList.size();i++){ HSSFRowrow=sheet.createRow(i+1);//要从第二行开始写 HSSFRowtopRow=null; if(i==0)topRow=sheet.createRow(0); for(Fieldfield:fields){ Excelexcel=field.getAnnotation(Excel.class);//得到字段是否使用了Excel注解 if(excel==null)continue; HSSFCellcell=row.createCell(excel.index());//设置当前值放到第几列 StringstartName=field.getName().substring(0,1); StringendName=field.getName().substring(1,field.getName().length()); StringmethodName=newStringBuffer(GET).append(startName.toUpperCase()).append(endName).toString(); try{ Methodmethod=aClass.getMethod(methodName);//根据方法名获取方法,用于调用 Objectinvoke=method.invoke(objList.get(i)); if(invoke==null)continue; cell.setCellValue(invoke.toString()); }catch(NoSuchMethodExceptione){ e.printStackTrace(); }catch(IllegalAccessExceptione){ e.printStackTrace(); }catch(InvocationTargetExceptione){ e.printStackTrace(); } if(topRow==null)continue; HSSFCelltopRowCell=topRow.createCell(excel.index()); topRowCell.setCellValue(excel.name()); sheet.setColumnWidth(excel.index(),excel.width()); } } returnworkbook; } /** *将Excel文件转换为指定对象 * *@paramfile传入的Excel *@paramc需要被指定的class *@return *@throwsIOException *@throwsIllegalAccessException *@throwsInstantiationException */ publicstatic<T>List<T>excelFileToObject(MultipartFilefile,Class<T>c)throwsIOException,IllegalAccessException,InstantiationException{ //key为反射得到的下标,value为对于的set方法 Map<Integer,String>methodMap=newHashMap<>(); //保存第一列的值与对应的下标,用于验证用户是否删除了该列,key为下标,value为名字 Map<Integer,String>startRowNameMap=newHashMap<>(); //用来记录当前参数是否为必须的 Map<Integer,Boolean>fieldIsMustMap=newHashMap<>(); //得到所有的字段 Field[]fields=c.getDeclaredFields(); for(Fieldfield:fields){ Excelexcel=field.getAnnotation(Excel.class); if(excel==null)continue; StringstartName=field.getName().substring(0,1); StringendName=field.getName().substring(1,field.getName().length()); StringmethodName=newStringBuffer(SET).append(startName.toUpperCase()).append(endName).toString(); methodMap.put(excel.index(),methodName); startRowNameMap.put(excel.index(),excel.name()); fieldIsMustMap.put(excel.index(),excel.isMust()); } StringfileName=file.getOriginalFilename(); Workbookwb=fileName.endsWith(".xlsx")?newXSSFWorkbook(file.getInputStream()):newHSSFWorkbook(file.getInputStream()); Sheetsheet=wb.getSheetAt(0); RowsheetRow=sheet.getRow(0); for(Cellcell:sheetRow){ IntegercolumnIndex=cell.getColumnIndex(); if(cell.getCellTypeEnum()!=CellType.STRING)thrownewExcelException("excel校验失败,请勿删除文件中第一行数据!!!"); Stringvalue=cell.getStringCellValue(); Stringname=startRowNameMap.get(columnIndex); if(name==null)thrownewExcelException("excel校验失败,请勿移动文件中任何列的顺序!!!"); if(!name.equals(value))thrownewExcelException("excel校验失败,【"+name+"】列被删除,请勿删除文件中任何列!!!"); } sheet.removeRow(sheetRow);//第一行是不需要被反射赋值的 List<T>models=newArrayList<>(); for(Rowrow:sheet){ if(row==null||!checkRow(row))continue; Tobj=c.newInstance();//创建新的实例化对象 ClassexcelModelClass=obj.getClass(); startRowNameMap.entrySet().forEach(x->{ Integerindex=x.getKey(); Cellcell=row.getCell(index); StringmethodName=methodMap.get(index); if(StringUtils.isEmpty(methodName))return; List<Method>methods=Lists.newArrayList(excelModelClass.getMethods()).stream() .filter(m->m.getName().startsWith(SET)).collect(Collectors.toList()); StringrowName=startRowNameMap.get(index);//列的名字 for(Methodmethod:methods){ if(!method.getName().startsWith(methodName))continue; //检测value属性 Stringvalue=valueCheck(cell,rowName,fieldIsMustMap.get(index)); //开始进行调用方法反射赋值 methodInvokeHandler(obj,method,value); } }); models.add(obj); } returnmodels; } /** *检测当前需要赋值的value * *@paramcell当前循环行中的列对象 *@paramrowName列的名字{@linkExcel}中的name *@paramisMust是否为必须的 *@return值 */ privatestaticStringvalueCheck(Cellcell,StringrowName,BooleanisMust){ //有时候删除单个数据会造成cell为空,也可能是value为空 if(cell==null&&isMust){ thrownewExcelException("excel校验失败,【"+rowName+"】中的数据禁止单个删除"); } if(cell==null)returnnull; cell.setCellType(CellType.STRING); Stringvalue=cell.getStringCellValue(); if((value==null||value.trim().isEmpty())&&isMust){ thrownewExcelException("excel校验失败,【"+rowName+"】中的数据禁止单个删除"); } returnvalue; } /** *反射赋值的处理的方法 * *@paramobj循环创建的需要赋值的对象 *@parammethod当前对象期中一个set方法 *@paramvalue要被赋值的内容 */ privatestaticvoidmethodInvokeHandler(Objectobj,Methodmethod,Stringvalue){ Class<?>parameterType=method.getParameterTypes()[0]; try{ if(parameterType==null){ method.invoke(obj); return; } Stringname=parameterType.getName(); if(name.equals(String.class.getName())){ method.invoke(obj,value); return; } if(name.equals(Long.class.getName())){ method.invoke(obj,Long.valueOf(value)); return; } if(name.equals(Double.class.getName())){ method.invoke(obj,Double.valueOf(value)); } }catch(IllegalAccessExceptione){ e.printStackTrace(); }catch(InvocationTargetExceptione){ e.printStackTrace(); } } privatestaticbooleancheckRow(Rowrow){ try{ if(row==null)returnfalse; shortfirstCellNum=row.getFirstCellNum(); shortlastCellNum=row.getLastCellNum(); if(firstCellNum<0&&lastCellNum<0)returnfalse; if(firstCellNum!=0){ for(shorti=firstCellNum;i<lastCellNum;i++){ Cellcell=row.getCell(i); StringcellValue=cell.getStringCellValue(); if(!StringUtils.isBlank(cellValue))returntrue; } returnfalse; } returntrue; }catch(Exceptione){ returntrue; } }
4、导出Excel与导入Excel的示例代码
使用展示
1、选择数据
2、设置基本数据,然后导出表格
3、导出表格效果,在图片中看到A和B列没有显示出来,这是因为我将其宽度配置为了0
4、将必须参数删除后上传测试,如下图中,商品编码我设置isMust为false所以删除数据就不会出现此问题。会提示验证失败,具体错误查看图片
5、将列中值的顺序调整测试,也会提示验证失败,具体效果如下图
6、正常上传测试,具体效果下如图
关于“Java如何使用poi做加自定义注解实现对象与Excel相互转换”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
目录
推荐阅读
0 条评论
本站已关闭游客评论,请登录或者注册后再评论吧~