通用excel导入导出

整理旧的博客 2010-10-16 22:28:58

通过Annotation实现通用版本的Excel导入导出

------------------------------------------------------------------------------

从离开学校到现在,快三个月了,一直忙于工作,没有发博文。

现在基本适应了,三个月两本大大的笔记,需要整理下
三个月中学了很多,感觉进步了不少。
下面来点给力的,通用导入导出


需求:在实际J2EE项目中,经常遇到需要导入导出excel文件的情况
解决方案:利用java的annotation,自定义一个annotation ,在声明pojo的时候对需要操作字段的属性进行声明
然后,通用的处理类根据运行时,读取annotation 相关信息,解析
需要资源: poi3.6 jdk1.5以上

对于导入,读入是一个excel文件,输出一个list<pojo> ,如果你用hibernate操作的话相当方便
对于导出,你需要组织一个List<pojo>传入,将得到一个excel

对于annotation可以自己扩展,也可以裁掉不需要的,excel文件合法性校验需要自己写

以下仅供参考:
1.自定义一个annotation
package com.huateng.common.excel.parser; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Excel { //导入时,对应数据库的字段 主要是用户区分每个字段,不能有annocation重名的 //导出时的列名 导出排序跟定义了annotation的字段的顺序有关 public String exportName(); //导出时在excel中每个列的宽 单位为字符,一个汉字=2个字符 //如 以列名列内容中较合适的长度 例如姓名列6 【姓名一般三个字】 性别列4【男女占1,但是列标题两个汉字】 //限制1-255 public int exportFieldWidth(); //导出时是否进行字段转换 例如 性别用int存储,导出时可能转换为男,女 //若是sign为1,则需要在pojo中加入一个方法 get字段名Convert() //例如,字段sex ,需要加入 public String getSexConvert() 返回值为string //若是sign为0,则不必管 public int exportConvertSign(); //导入数据是否需要转化 及 对已有的excel,是否需要将字段转为对应的数据 //若是sign为1,则需要在pojo中加入 void set字段名Convert(String text) public int importConvertSign(); }

2.声明对应的pojo,进行每个字段的注解
package com.huateng.test.pojo; import java.text.SimpleDateFormat; import java.util.Date; import com.huateng.common.excel.parser.ConvertUtil; import com.huateng.common.excel.parser.Excel; public class Student { @Excel(exportName="姓名",exportFieldWidth=18,exportConvertSign=0,importConvertSign=0) private String name; @Excel(exportName="年龄",exportFieldWidth=4,exportConvertSign=0,importConvertSign=0) private Integer age; @Excel(exportName="性别",exportFieldWidth=4,exportConvertSign=1,importConvertSign=1) private Integer sex; @Excel(exportName="出生日期",exportFieldWidth=20,exportConvertSign=1,importConvertSign=1) private Date birthDate; @Excel(exportName="描述",exportFieldWidth=30,exportConvertSign=0,importConvertSign=0) private String desc; @Excel(exportName="是否VIP",exportFieldWidth=7,exportConvertSign=1,importConvertSign=1) private Boolean isVip; //convertSign=1时必须加入转化方法 不加入会报错 返回值为String 用于翻译 //convertSign=0不需翻译,不用书写转化 //导入需要 set ,导出需要get public String getSexConvert() { if(sex == 1) { return "男"; }else if(sex == 2){ return "女"; }else { return ""; } } public void setSexConvert(String text) { if("男".equals(text)) { sex = 1; } if("女".equals(text)) { sex = 2; } } public String getBirthDateConvert() { if(birthDate == null) { return ""; } return ConvertUtil.toDate14(birthDate); } public void setBirthDateConvert(String text) { if(text != null && !"".equals(text.trim())) { birthDate = ConvertUtil.string14toDate(text); } } public String getIsVipConvert() { if(isVip == null) { return ""; } if(isVip) { return "是"; }else{ return "否"; } } public void setIsVipConvert(String text) { if("是".equals(text)) { isVip = true; } if("否".equals(text)) { isVip = false; } } //getter and setters public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getSex() { return sex; } public void setSex(Integer sex) { this.sex = sex; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public Date getBirthDate() { return birthDate; } public void setBirthDate(Date birthDate) { this.birthDate = birthDate; } public Boolean getIsVip() { return isVip; } public void setIsVip(Boolean isVip) { this.isVip = isVip; } }
3.通用导出:
package com.huateng.common.excel.parser; import java.io.FileOutputStream; import java.io.OutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFRichTextString; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.RichTextString; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import com.huateng.test.pojo.Student; public class ExcelExport2 { public static void exportExcel(String title, Class pojoClass,Collection dataSet, OutputStream out) { //使用userModel模式实现的,当excel文档出现10万级别的大数据文件可能导致OOM内存溢出 exportExcelInUserModel(title, pojoClass,dataSet,out); //使用eventModel实现,可以一边读一边处理,效率较高,但是实现复杂,暂时未实现 } private static void exportExcelInUserModel(String title, Class pojoClass,Collection dataSet, OutputStream out) { try { // 首先检查数据看是否是正确的 if (dataSet == null || dataSet.size()==0) { throw new Exception("导出数据为空!"); } if(title == null || out == null || pojoClass == null) { throw new Exception("传入参数不能为空!"); } // 声明一个工作薄 Workbook workbook = new HSSFWorkbook(); // 生成一个表格 Sheet sheet = workbook.createSheet(title); // 标题 List<String> exportFieldTitle = new ArrayList<String>(); List<Integer> exportFieldWidth = new ArrayList<Integer>(); // 拿到所有列名,以及导出的字段的get方法 List<Method> methodObj = new ArrayList<Method>(); Map<String,Method> convertMethod = new HashMap<String,Method>(); // 得到所有字段 Field fileds[] = pojoClass.getDeclaredFields(); // 遍历整个filed for (int i = 0; i < fileds.length; i++) { Field field = fileds[i]; Excel excel = field.getAnnotation(Excel.class); // 如果设置了annottion if (excel != null) { // 添加到标题 exportFieldTitle.add(excel.exportName()); //添加标题的列宽 exportFieldWidth.add(excel.exportFieldWidth()); // 添加到需要导出的字段的方法 String fieldname = field.getName(); //System.out.println(i+"列宽"+excel.exportName()+" "+excel.exportFieldWidth()); StringBuffer getMethodName = new StringBuffer("get"); getMethodName.append(fieldname.substring(0, 1) .toUpperCase()); getMethodName.append(fieldname.substring(1)); Method getMethod = pojoClass.getMethod(getMethodName.toString(), new Class[] {}); methodObj.add(getMethod); if(excel.exportConvertSign()==1) { StringBuffer getConvertMethodName = new StringBuffer("get"); getConvertMethodName.append(fieldname.substring(0, 1) .toUpperCase()); getConvertMethodName.append(fieldname.substring(1)); getConvertMethodName.append("Convert"); //System.out.println("convert: "+getConvertMethodName.toString()); Method getConvertMethod = pojoClass.getMethod(getConvertMethodName.toString(), new Class[] {}); convertMethod.put(getMethodName.toString(), getConvertMethod); } } } int index = 0; // 产生表格标题行 Row row = sheet.createRow(index); for (int i = 0,exportFieldTitleSize = exportFieldTitle.size(); i < exportFieldTitleSize; i++) { Cell cell = row.createCell(i); // cell.setCellStyle(style); RichTextString text = new HSSFRichTextString( exportFieldTitle.get(i)); cell.setCellValue(text); } //设置每行的列宽 for (int i = 0; i < exportFieldWidth.size(); i++) { //256=65280/255 sheet.setColumnWidth(i, 256*exportFieldWidth.get(i)); } Iterator its = dataSet.iterator(); // 循环插入剩下的集合 while (its.hasNext()) { // 从第二行开始写,第一行是标题 index++; row = sheet.createRow(index); Object t = its.next(); for (int k = 0, methodObjSize = methodObj.size(); k < methodObjSize; k++) { Cell cell = row.createCell(k); Method getMethod = methodObj.get(k); Object value = null; if(convertMethod.containsKey(getMethod.getName())) { Method cm = convertMethod.get(getMethod.getName()); value = cm.invoke(t, new Object[] {}); }else { value = getMethod.invoke(t, new Object[] {}); } cell.setCellValue(value.toString()); } } workbook.write(out); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { // 构造一个模拟的List来测试,实际使用时,这个集合用从数据库中查出来 Student pojo2 = new Student(); pojo2.setName("第一行数据"); pojo2.setAge(28); pojo2.setSex(2); pojo2.setDesc("abcdefghijklmnop"); pojo2.setBirthDate(new Date()); pojo2.setIsVip(true); List list = new ArrayList(); list.add(pojo2); for (int i = 0; i < 50000; i++) { Student pojo = new Student(); pojo.setName("一二三四五六七八九"); pojo.setAge(22); pojo.setSex(1); pojo.setDesc("abcdefghijklmnop"); pojo.setBirthDate(new Date()); pojo.setIsVip(false); list.add(pojo); } // 构造输出对象,可以从response输出,直接向用户提供下载 OutputStream out = new FileOutputStream("D://testOne.xls"); // 开始时间 Long l = System.currentTimeMillis(); // 注意 ExcelExport2 ex = new ExcelExport2(); // ex.exportExcel("测试",Student.class,list, out); out.close(); // 结束时间 Long s = System.currentTimeMillis(); System.out.println("excel导出成功"); System.out.println("总共耗时:" + (s - l)); } }
4.通用导入:
package com.huateng.common.excel.parser; import java.io.File; import java.io.FileInputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import com.huateng.test.pojo.Student; public class ExcelImport2 { public Collection importExcel(File file ,Class pojoClass,String... pattern) { Collection dist = new ArrayList(); try { // 得到目标目标类的所有的字段列表 Field filed[] = pojoClass.getDeclaredFields(); // 将所有标有Annotation的字段,也就是允许导入数据的字段,放入到一个map中 Map<String,Method> fieldSetMap = new HashMap<String,Method>(); Map<String,Method> fieldSetConvertMap = new HashMap<String,Method>(); // 循环读取所有字段 for (int i = 0; i < filed.length; i++) { Field f = filed[i]; // 得到单个字段上的Annotation Excel excel = f.getAnnotation(Excel.class); // 如果标识了Annotationd的话 if (excel != null) { // 构造设置了Annotation的字段的Setter方法 String fieldname = f.getName(); String setMethodName = "set" + fieldname.substring(0, 1).toUpperCase() + fieldname.substring(1); // 构造调用的method, Method setMethod = pojoClass.getMethod(setMethodName, new Class[] { f.getType() }); // 将这个method以Annotaion的名字为key来存入。 //对于重名将导致 覆盖失败,对于此处的限制需要 fieldSetMap.put(excel.exportName(), setMethod); if(excel.importConvertSign()==1) { StringBuffer setConvertMethodName = new StringBuffer("set"); setConvertMethodName.append(fieldname.substring(0, 1) .toUpperCase()); setConvertMethodName.append(fieldname.substring(1)); setConvertMethodName.append("Convert"); Method getConvertMethod = pojoClass.getMethod(setConvertMethodName.toString(), new Class[] {String.class}); fieldSetConvertMap.put(excel.exportName(), getConvertMethod); } } } // 将传入的File构造为FileInputStream; FileInputStream in = new FileInputStream(file); // // 得到工作表 HSSFWorkbook book = new HSSFWorkbook(in); // // 得到第一页 HSSFSheet sheet = book.getSheetAt(0); // // 得到第一面的所有行 Iterator<Row> row = sheet.rowIterator(); // 得到第一行,也就是标题行 Row title = row.next(); // 得到第一行的所有列 Iterator<Cell> cellTitle = title.cellIterator(); // 将标题的文字内容放入到一个map中。 Map titlemap = new HashMap(); // 从标题第一列开始 int i = 0; // 循环标题所有的列 while (cellTitle.hasNext()) { Cell cell = cellTitle.next(); String value = cell.getStringCellValue(); titlemap.put(i, value); i = i + 1; } //用来格式化日期的DateFormat SimpleDateFormat sf; if(pattern.length<1) { sf=new SimpleDateFormat("yyyy-MM-dd"); } else sf=new SimpleDateFormat(pattern[0]); while (row.hasNext()) { // 标题下的第一行 Row rown = row.next(); // 行的所有列 Iterator<Cell> cellbody = rown.cellIterator(); // 得到传入类的实例 Object tObject = pojoClass.newInstance(); int k = 0; // 遍历一行的列 while (cellbody.hasNext()) { Cell cell = cellbody.next(); // 这里得到此列的对应的标题 String titleString = (String) titlemap.get(k); // 如果这一列的标题和类中的某一列的Annotation相同,那么则调用此类的的set方法,进行设值 if (fieldSetMap.containsKey(titleString)) { Method setMethod = (Method) fieldSetMap.get(titleString); //得到setter方法的参数 Type[] ts = setMethod.getGenericParameterTypes(); //只要一个参数 String xclass = ts[0].toString(); //判断参数类型 System.out.println("类型: "+xclass); if (fieldSetConvertMap.containsKey(titleString)) { fieldSetConvertMap.get(titleString).invoke(tObject, cell.getStringCellValue()); } else { if (xclass.equals("class java.lang.String")) { setMethod.invoke(tObject, cell .getStringCellValue()); } else if (xclass.equals("class java.util.Date")) { setMethod.invoke(tObject, cell .getDateCellValue()); } else if (xclass.equals("class java.lang.Boolean")) { setMethod.invoke(tObject, cell .getBooleanCellValue()); } else if (xclass.equals("class java.lang.Integer")) { setMethod.invoke(tObject, new Integer(cell .getStringCellValue())); }else if(xclass. equals("class java.lang.Long")) { setMethod.invoke(tObject,new Long( cell.getStringCellValue())); } } } // 下一列 k = k + 1; } dist.add(tObject); } } catch (Exception e) { e.printStackTrace(); return null; } return dist; } public static void main(String[] args) { ExcelImport2 test = new ExcelImport2(); File file = new File("D://testOne.xls"); Long befor = System.currentTimeMillis(); List<Student> result = (ArrayList) test.importExcel(file,Student.class); Long after = System.currentTimeMillis(); System.out.println("此次操作共耗时:" + (after - befor) + "毫秒"); for (int i = 0; i < result.size(); i++) { Student testpojo=result.get(i); System.out.println("导入的信息为:"+testpojo.getName()+ "--"+testpojo.getAge()+"-"+testpojo.getSex()+"--"+testpojo.getBirthDate()+"--"+testpojo.getDesc()+"--"+testpojo.getIsVip()); } System.out.println("共转化为List的行数为:" + result.size()); } } -
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java是一种通用的高级编程语言,通过Java编程序可以实现各种功能,包括Excel导入导出。在Java中,可以使用Apache POI来操作Excel文件,Apache POI是一个流行的用于读Microsoft Office文件的Java库,它包括HSSF(用于读Excel 97-2003),XSSF(用于读Excel 2007+)和SS(实验性的通用Spiral包)。 在Java中使用Apache POI进行Excel导入时,首先需要创建一个Workbook对象,该对象可以是XSSFWorkbook(用于.xlsx文件格式),也可以是HSSFWorkbook(用于.xls文件格式)。一旦获得了Workbook对象,就可以从工作表中获取数据。对于每个工作表,都可以使用Sheet对象访问单元格中的值,并使用Row对象访问单元格中的列数据。 在Excel导出方面,在Java中使用Apache POI可以创建Excel文档并向其中添加数据。要创建一个Excel文档,首先需要创建一个Workbook对象,然后添加一个或多个工作表。对于每个工作表,可以使用Sheet对象访问单元格,并使用Row对象访问列数据。将数据添加到单元格后,可以使用FileOutputStream将文档入指定的文件。 总的来说,使用Java进行Excel导入导出是一种非常灵活和高效的方法,可以通过学习和使用Apache POI等工具来实现。 ### 回答2: Java是一个跨平台的编程语言,它可以很好地进行Excel文件的导入导出。Java提供了一些库,比如Apache POI,用于操作Excel文件。通过这些库,我们可以在Java中进行Excel文件的读取和入。 Excel导入导出可以用来处理各种数据,这对于企业来说非常有用。因为数据是企业的核心资产之一,所以正确导入导出数据是非常重要的。Java对于处理Excel数据非常方便,我们可以很容易地将数据转换成Java对象,然后以任何我们需要的方式进行处理。 在使用Java进行Excel导入导出时,我们需要先导入Apache POI库。通过这个库,我们可以调用其提供的方法来操作Excel文件。例如,我们可以通过创建Workbook对象来读取Excel文件,并通过Sheet对象访问工作表中的单元格。 对于Excel导出,我们首先需要定义Excel模板,然后使用Java代码填充模板。我们可以通过创建Workbook对象来创建新的工作簿。然后,我们可以创建一个Sheet对象,然后使用Row对象和Cell对象来创建表格。最后,我们将表格数据Excel文件中。 总而言之,Java提供了快速,可靠的Excel导入导出解决方案。这对于企业来说非常重要,因为数据是企业运营的核心资产。利用Java的Excel导入导出功能,企业可以更好地处理数据并提高效率。 ### 回答3: Java中导入导出Excel文档是非常常见的操作,可以根据具体需求使用Java自带的API或者开源框架完成。本文将重点介绍Apache POI和EasyExcel两个开源框架的使用。 一、Apache POI Apache POI是Apache软件基金会的一个开源项目,提供基于Java的API用于处理Microsoft Office格式文件。其中包括Word、Excel和PowerPoint等文档的读操作,对于Excel的读操作使用的是XSSF和HSSF两个模块,分别支持.xlsx和.xls格式的文件。 1.导入Excel 首先需要导入POI的jar包,然后使用以下代码读取Excel中的数据: ``` File file = new File("test.xlsx"); InputStream inputStream = new FileInputStream(file); Workbook workbook = new XSSFWorkbook(inputStream);//读取xlsx格式 //Workbook workbook = new HSSFWorkbook(inputStream);//读取xls格式 Sheet sheet = workbook.getSheetAt(0);//获取第一个sheet Iterator<Row> iterator = sheet.iterator(); while(iterator.hasNext()) { Row row = iterator.next(); Iterator<Cell> cellIterator = row.cellIterator(); while(cellIterator .hasNext()) { Cell cell = cellIterator.next(); switch (cell.getCellType()) { case STRING: System.out.print(cell.getStringCellValue() + " "); break; case NUMERIC: System.out.print(cell.getNumericCellValue() + " "); break; case BOOLEAN: System.out.print(cell.getBooleanCellValue() + " "); break; case FORMULA: System.out.print(cell.getCellFormula() + " "); break; default: System.out.print(""); } } System.out.println();//换行 } inputStream.close(); ``` 2.导出Excel 基于POI的Excel导出主要是通过创建Workbook对象、Sheet对象和Cell对象,然后将数据填充到Cell对象中,最后输出到文件中。以下是导出Excel的示例代码: ``` Workbook workbook = new XSSFWorkbook();//创建工作簿 Sheet sheet = workbook.createSheet("sheet0");//创建sheet Row row = sheet.createRow(0);//创建行 Cell cell = row.createCell(0);//创建单元格 cell.setCellValue("姓名"); cell = row.createCell(1); cell.setCellValue("年龄"); cell = row.createCell(2); cell.setCellValue("性别"); row = sheet.createRow(1);//创建行 cell = row.createCell(0); cell.setCellValue("张三"); cell = row.createCell(1); cell.setCellValue(20); cell = row.createCell(2); cell.setCellValue("男"); FileOutputStream outputStream = new FileOutputStream("test.xlsx");//输出到文件 workbook.write(outputStream); outputStream.close(); ``` 二、EasyExcel EasyExcel是一个基于POI封装的Java开源框架,提供简单易用的方式完成Excel导入导出操作。相对于POI,EasyExcel的优点在于它的API更加简单明了,使用起来更加方便快捷。 1.导入Excel EasyExcel导入Excel的方式主要是通过读取监听器实现,可以实现不同sheet的读取、数据转换和对数据的处理等功能。以下是导入Excel的示例代码: ``` //创建读取监听器 public class ExcelListener extends AnalysisEventListener<User> { private List<User> userList = new ArrayList<>(); @Override public void invoke(User user, AnalysisContext analysisContext) { userList.add(user);//每读取一条数据就添加到List中 } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { //读取完成后的操作 } public List<User> getUserList() { return userList; } public void setUserList(List<User> userList) { this.userList = userList; } } //使用监听器读取Excel数据 File file = new File("test.xlsx"); EasyExcel.read(file, User.class, new ExcelListener()).sheet().doRead(); ``` 2.导出Excel EasyExcel导出Excel的方式主要是通过生成器模式创建入对象、构造sheet页和单元格,最后输出到文件或者流中。以下是导出Excel的示例代码: ``` //创建入对象 ExcelWriter writer = EasyExcel.write("test.xlsx", User.class).build(); //构造sheet页和单元格 WriteSheet sheet = EasyExcel.writerSheet("sheet0").build(); //填充数据到单元格 List<User> userList = new ArrayList<>(); userList.add(new User("张三", 20, "男")); userList.add(new User("李四", 22, "女")); writer.write(userList, sheet); //输出到文件或者流中 writer.finish(); ``` 总结 以上是Apache POI和EasyExcel两个框架的Excel导入导出操作,两者都十分流行和实用,可以根据项目需求进行选择。在实际开发中,需要注意的是Excel的版本问题、数据类型的转换、异常处理等,并加以优化和完善,从而提高代码的可维护性和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值