Excel导入导出

来源:互联网 发布:idm mac破解版 编辑:程序博客网 时间:2024/06/04 18:28

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

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

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

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


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

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

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

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

2.声明对应的pojo,进行每个字段的注解
[java] view plaincopyprint?
  1. package com.huateng.test.pojo;  
  2.   
  3.   
  4. import java.text.SimpleDateFormat;  
  5. import java.util.Date;  
  6.   
  7.   
  8. import com.huateng.common.excel.parser.ConvertUtil;  
  9. import com.huateng.common.excel.parser.Excel;  
  10.   
  11.   
  12. public class Student {  
  13. @Excel(exportName="姓名",exportFieldWidth=18,exportConvertSign=0,importConvertSign=0)  
  14. private String name;  
  15. @Excel(exportName="年龄",exportFieldWidth=4,exportConvertSign=0,importConvertSign=0)  
  16. private Integer age;  
  17. @Excel(exportName="性别",exportFieldWidth=4,exportConvertSign=1,importConvertSign=1)  
  18. private Integer sex;  
  19. @Excel(exportName="出生日期",exportFieldWidth=20,exportConvertSign=1,importConvertSign=1)  
  20. private Date birthDate;  
  21. @Excel(exportName="描述",exportFieldWidth=30,exportConvertSign=0,importConvertSign=0)  
  22. private String desc;  
  23. @Excel(exportName="是否VIP",exportFieldWidth=7,exportConvertSign=1,importConvertSign=1)  
  24. private Boolean isVip;  
  25. //convertSign=1时必须加入转化方法   不加入会报错    返回值为String  用于翻译  
  26. //convertSign=0不需翻译,不用书写转化  
  27. //导入需要 set ,导出需要get  
  28. public String getSexConvert()  
  29. {  
  30. if(sex == 1)  
  31. {  
  32. return "男";  
  33. }else if(sex == 2){  
  34. return "女";  
  35. }else  
  36. {  
  37. return "";  
  38. }  
  39. }  
  40. public void setSexConvert(String text)  
  41. {  
  42. if("男".equals(text))  
  43. {  
  44. sex = 1;  
  45. }  
  46. if("女".equals(text))  
  47. {  
  48. sex = 2;  
  49. }  
  50. }  
  51. public String getBirthDateConvert()  
  52. {  
  53. if(birthDate == null)  
  54. {  
  55. return "";  
  56. }  
  57. return ConvertUtil.toDate14(birthDate);   
  58. }  
  59. public void setBirthDateConvert(String text)  
  60. {  
  61. if(text != null && !"".equals(text.trim()))  
  62. {  
  63. birthDate = ConvertUtil.string14toDate(text);  
  64. }  
  65. }  
  66. public String getIsVipConvert()  
  67. {  
  68. if(isVip == null)  
  69. {  
  70. return "";  
  71. }  
  72. if(isVip)  
  73. {  
  74. return "是";  
  75. }else{  
  76. return "否";  
  77. }  
  78. }  
  79. public void setIsVipConvert(String text)  
  80. {  
  81. if("是".equals(text))  
  82. {  
  83. isVip = true;  
  84. }  
  85. if("否".equals(text))  
  86. {  
  87. isVip = false;  
  88. }  
  89. }  
  90. //getter and setters  
  91. public String getName() {  
  92. return name;  
  93. }  
  94.   
  95.   
  96. public void setName(String name) {  
  97. this.name = name;  
  98. }  
  99.   
  100.   
  101. public Integer getAge() {  
  102. return age;  
  103. }  
  104.   
  105.   
  106. public void setAge(Integer age) {  
  107. this.age = age;  
  108. }  
  109.   
  110.   
  111. public Integer getSex() {  
  112. return sex;  
  113. }  
  114.   
  115.   
  116. public void setSex(Integer sex) {  
  117. this.sex = sex;  
  118. }  
  119.   
  120.   
  121. public String getDesc() {  
  122. return desc;  
  123. }  
  124.   
  125.   
  126. public void setDesc(String desc) {  
  127. this.desc = desc;  
  128. }  
  129.   
  130.   
  131.   
  132.   
  133. public Date getBirthDate() {  
  134. return birthDate;  
  135. }  
  136.   
  137.   
  138.   
  139.   
  140. public void setBirthDate(Date birthDate) {  
  141. this.birthDate = birthDate;  
  142. }  
  143. public Boolean getIsVip() {  
  144. return isVip;  
  145. }  
  146. public void setIsVip(Boolean isVip) {  
  147. this.isVip = isVip;  
  148. }  
  149.   
  150.   
  151. }  
3.通用导出:
[java] view plaincopyprint?
  1. package com.huateng.common.excel.parser;  
  2.   
  3.   
  4. import java.io.FileOutputStream;  
  5. import java.io.OutputStream;  
  6. import java.lang.reflect.Field;  
  7. import java.lang.reflect.Method;  
  8. import java.util.ArrayList;  
  9. import java.util.Collection;  
  10. import java.util.Date;  
  11. import java.util.HashMap;  
  12. import java.util.Iterator;  
  13. import java.util.List;  
  14. import java.util.Map;  
  15.   
  16.   
  17. import org.apache.poi.hssf.usermodel.HSSFRichTextString;  
  18. import org.apache.poi.hssf.usermodel.HSSFWorkbook;  
  19. import org.apache.poi.ss.usermodel.Cell;  
  20. import org.apache.poi.ss.usermodel.RichTextString;  
  21. import org.apache.poi.ss.usermodel.Row;  
  22. import org.apache.poi.ss.usermodel.Sheet;  
  23. import org.apache.poi.ss.usermodel.Workbook;  
  24.   
  25.   
  26. import com.huateng.test.pojo.Student;  
  27.   
  28.   
  29. public class ExcelExport2 {  
  30.   
  31.   
  32. public static void exportExcel(String title, Class pojoClass,Collection dataSet,  
  33. OutputStream out) {  
  34. //使用userModel模式实现的,当excel文档出现10万级别的大数据文件可能导致OOM内存溢出  
  35. exportExcelInUserModel(title, pojoClass,dataSet,out);  
  36. //使用eventModel实现,可以一边读一边处理,效率较高,但是实现复杂,暂时未实现  
  37. }  
  38. private static void exportExcelInUserModel(String title, Class pojoClass,Collection dataSet,  
  39. OutputStream out) {  
  40. try {  
  41. // 首先检查数据看是否是正确的  
  42. if (dataSet == null || dataSet.size()==0) {  
  43. throw new Exception("导出数据为空!");  
  44. }  
  45. if(title == null || out == null || pojoClass == null)  
  46. {  
  47. throw new Exception("传入参数不能为空!");  
  48. }  
  49. // 声明一个工作薄    
  50. Workbook workbook = new HSSFWorkbook();  
  51. // 生成一个表格  
  52. Sheet sheet = workbook.createSheet(title);  
  53.   
  54.   
  55. // 标题  
  56. List<String> exportFieldTitle = new ArrayList<String>();  
  57. List<Integer> exportFieldWidth = new ArrayList<Integer>();  
  58. // 拿到所有列名,以及导出的字段的get方法  
  59. List<Method> methodObj = new ArrayList<Method>();  
  60. Map<String,Method> convertMethod = new HashMap<String,Method>();  
  61. // 得到所有字段  
  62. Field fileds[] = pojoClass.getDeclaredFields();  
  63. // 遍历整个filed  
  64. for (int i = 0; i < fileds.length; i++) {  
  65. Field field = fileds[i];  
  66. Excel excel = field.getAnnotation(Excel.class);  
  67. // 如果设置了annottion  
  68. if (excel != null) {  
  69. // 添加到标题  
  70. exportFieldTitle.add(excel.exportName());  
  71. //添加标题的列宽  
  72. exportFieldWidth.add(excel.exportFieldWidth());  
  73. // 添加到需要导出的字段的方法  
  74. String fieldname = field.getName();  
  75. //System.out.println(i+"列宽"+excel.exportName()+" "+excel.exportFieldWidth());  
  76. StringBuffer getMethodName = new StringBuffer("get");  
  77. getMethodName.append(fieldname.substring(01)  
  78. .toUpperCase());  
  79. getMethodName.append(fieldname.substring(1));  
  80.   
  81.   
  82. Method getMethod = pojoClass.getMethod(getMethodName.toString(),  
  83. new Class[] {});  
  84.   
  85.   
  86. methodObj.add(getMethod);  
  87. if(excel.exportConvertSign()==1)  
  88. {  
  89. StringBuffer getConvertMethodName = new StringBuffer("get");  
  90. getConvertMethodName.append(fieldname.substring(01)  
  91. .toUpperCase());  
  92. getConvertMethodName.append(fieldname.substring(1));  
  93. getConvertMethodName.append("Convert");  
  94. //System.out.println("convert: "+getConvertMethodName.toString());  
  95. Method getConvertMethod = pojoClass.getMethod(getConvertMethodName.toString(),  
  96. new Class[] {});  
  97. convertMethod.put(getMethodName.toString(), getConvertMethod);  
  98. }  
  99. }  
  100. }  
  101. int index = 0;  
  102. // 产生表格标题行  
  103. Row row = sheet.createRow(index);  
  104. for (int i = 0,exportFieldTitleSize = exportFieldTitle.size(); i < exportFieldTitleSize; i++) {  
  105. Cell cell = row.createCell(i);  
  106.  //  cell.setCellStyle(style);  
  107. RichTextString text = new HSSFRichTextString(  
  108. exportFieldTitle.get(i));  
  109. cell.setCellValue(text);  
  110. }  
  111.   
  112.   
  113. //设置每行的列宽  
  114. for (int i = 0; i < exportFieldWidth.size(); i++) {  
  115. //256=65280/255  
  116. sheet.setColumnWidth(i, 256*exportFieldWidth.get(i));  
  117. }  
  118. Iterator its = dataSet.iterator();  
  119. // 循环插入剩下的集合  
  120. while (its.hasNext()) {  
  121. // 从第二行开始写,第一行是标题  
  122. index++;  
  123. row = sheet.createRow(index);  
  124. Object t = its.next();  
  125. for (int k = 0, methodObjSize = methodObj.size(); k < methodObjSize; k++) {  
  126. Cell cell = row.createCell(k);  
  127. Method getMethod = methodObj.get(k);  
  128. Object value = null;  
  129. if(convertMethod.containsKey(getMethod.getName()))  
  130. {  
  131. Method cm = convertMethod.get(getMethod.getName());  
  132. value = cm.invoke(t, new Object[] {});  
  133. }else  
  134. {  
  135. value = getMethod.invoke(t, new Object[] {});  
  136. }  
  137. cell.setCellValue(value.toString());  
  138. }  
  139. }  
  140.   
  141.   
  142. workbook.write(out);  
  143. catch (Exception e) {  
  144. e.printStackTrace();  
  145. }  
  146.   
  147.   
  148. }  
  149.   
  150.   
  151. public static void main(String[] args) throws Exception {  
  152.   
  153.   
  154. // 构造一个模拟的List来测试,实际使用时,这个集合用从数据库中查出来  
  155. Student pojo2 = new Student();  
  156. pojo2.setName("第一行数据");  
  157. pojo2.setAge(28);  
  158. pojo2.setSex(2);  
  159. pojo2.setDesc("abcdefghijklmnop");  
  160. pojo2.setBirthDate(new Date());  
  161. pojo2.setIsVip(true);  
  162. List list = new ArrayList();  
  163. list.add(pojo2);  
  164. for (int i = 0; i < 50000; i++) {  
  165. Student pojo = new Student();  
  166. pojo.setName("一二三四五六七八九");  
  167. pojo.setAge(22);  
  168. pojo.setSex(1);  
  169. pojo.setDesc("abcdefghijklmnop");  
  170. pojo.setBirthDate(new Date());  
  171. pojo.setIsVip(false);  
  172. list.add(pojo);  
  173. }  
  174. // 构造输出对象,可以从response输出,直接向用户提供下载  
  175. OutputStream out = new FileOutputStream("D://testOne.xls");  
  176. // 开始时间  
  177. Long l = System.currentTimeMillis();  
  178. // 注意  
  179. ExcelExport2 ex = new ExcelExport2();  
  180. //     
  181. ex.exportExcel("测试",Student.class,list, out);  
  182. out.close();  
  183. // 结束时间  
  184. Long s = System.currentTimeMillis();  
  185. System.out.println("excel导出成功");  
  186. System.out.println("总共耗时:" + (s - l));  
  187.   
  188.   
  189. }  
  190.   
  191.   
  192. }  
4.通用导入:
[java] view plaincopyprint?
  1. package com.huateng.common.excel.parser;  
  2.   
  3.   
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.lang.reflect.Field;  
  7. import java.lang.reflect.Method;  
  8. import java.lang.reflect.Type;  
  9. import java.text.SimpleDateFormat;  
  10. import java.util.ArrayList;  
  11. import java.util.Collection;  
  12. import java.util.HashMap;  
  13. import java.util.Iterator;  
  14. import java.util.List;  
  15. import java.util.Map;  
  16.   
  17.   
  18. import org.apache.poi.hssf.usermodel.HSSFSheet;  
  19. import org.apache.poi.hssf.usermodel.HSSFWorkbook;  
  20. import org.apache.poi.ss.usermodel.Cell;  
  21. import org.apache.poi.ss.usermodel.Row;  
  22.   
  23.   
  24. import com.huateng.test.pojo.Student;  
  25.   
  26.   
  27. public class ExcelImport2 {  
  28.     
  29.     public Collection importExcel(File file ,Class pojoClass,String...  pattern) {     
  30.          
  31.      Collection dist = new ArrayList();     
  32.      try {     
  33.             // 得到目标目标类的所有的字段列表     
  34.             Field filed[] = pojoClass.getDeclaredFields();     
  35.             // 将所有标有Annotation的字段,也就是允许导入数据的字段,放入到一个map中     
  36.             Map<String,Method> fieldSetMap = new HashMap<String,Method>();     
  37.               
  38.             Map<String,Method> fieldSetConvertMap = new HashMap<String,Method>();  
  39.               
  40.               
  41.             // 循环读取所有字段     
  42.             for (int i = 0; i < filed.length; i++) {     
  43.                 Field f = filed[i];     
  44.                   
  45.                 // 得到单个字段上的Annotation     
  46.                 Excel excel = f.getAnnotation(Excel.class);     
  47.                  
  48.                 // 如果标识了Annotationd的话     
  49.                 if (excel != null) {     
  50.                     // 构造设置了Annotation的字段的Setter方法     
  51.                     String fieldname = f.getName();     
  52.                     String setMethodName = "set"    
  53.                             + fieldname.substring(01).toUpperCase()     
  54.                             + fieldname.substring(1);     
  55.                     // 构造调用的method,     
  56.                     Method setMethod = pojoClass.getMethod(setMethodName,     
  57.                             new Class[] { f.getType() });     
  58.                     // 将这个method以Annotaion的名字为key来存入。   
  59.                       
  60.                     //对于重名将导致 覆盖失败,对于此处的限制需要  
  61.                     fieldSetMap.put(excel.exportName(), setMethod);     
  62.                       
  63.                     if(excel.importConvertSign()==1)  
  64. {  
  65. StringBuffer setConvertMethodName = new StringBuffer("set");  
  66. setConvertMethodName.append(fieldname.substring(01)  
  67. .toUpperCase());  
  68. setConvertMethodName.append(fieldname.substring(1));  
  69. setConvertMethodName.append("Convert");  
  70. Method getConvertMethod = pojoClass.getMethod(setConvertMethodName.toString(),  
  71. new Class[] {String.class});  
  72. fieldSetConvertMap.put(excel.exportName(), getConvertMethod);  
  73. }  
  74.                  
  75.                 }     
  76.             }     
  77.               
  78.               
  79.               
  80.               
  81.                 
  82.             // 将传入的File构造为FileInputStream;     
  83.             FileInputStream in = new FileInputStream(file);     
  84.             // // 得到工作表     
  85.             HSSFWorkbook book = new HSSFWorkbook(in);     
  86.             // // 得到第一页     
  87.             HSSFSheet sheet = book.getSheetAt(0);     
  88.             // // 得到第一面的所有行     
  89.             Iterator<Row> row = sheet.rowIterator();     
  90.     
  91.                 
  92.             // 得到第一行,也就是标题行     
  93.             Row title = row.next();     
  94.             // 得到第一行的所有列     
  95.             Iterator<Cell> cellTitle = title.cellIterator();     
  96.             // 将标题的文字内容放入到一个map中。     
  97.             Map titlemap = new HashMap();     
  98.             // 从标题第一列开始     
  99.             int i = 0;     
  100.             // 循环标题所有的列     
  101.             while (cellTitle.hasNext()) {     
  102.                 Cell cell = cellTitle.next();     
  103.                 String value = cell.getStringCellValue();     
  104.                 titlemap.put(i, value);     
  105.                 i = i + 1;     
  106.             }     
  107.               
  108.                 
  109.             //用来格式化日期的DateFormat     
  110.             SimpleDateFormat sf;     
  111.             if(pattern.length<1)     
  112.             {     
  113.                 sf=new SimpleDateFormat("yyyy-MM-dd");       
  114.             }     
  115.             else    
  116.                 sf=new SimpleDateFormat(pattern[0]);   
  117.               
  118.               
  119.             while (row.hasNext()) {     
  120.                 // 标题下的第一行     
  121.                 Row rown = row.next();     
  122.     
  123.                 // 行的所有列     
  124.                 Iterator<Cell> cellbody = rown.cellIterator();   
  125.                   
  126.                 // 得到传入类的实例     
  127.                 Object tObject = pojoClass.newInstance();    
  128.                   
  129.                 int k = 0;     
  130.                 // 遍历一行的列     
  131.                 while (cellbody.hasNext()) {     
  132.                     Cell cell = cellbody.next();     
  133.                     // 这里得到此列的对应的标题     
  134.                     String titleString = (String) titlemap.get(k);     
  135.                     // 如果这一列的标题和类中的某一列的Annotation相同,那么则调用此类的的set方法,进行设值     
  136.                     if (fieldSetMap.containsKey(titleString)) {    
  137.                       
  138.                         Method setMethod = (Method) fieldSetMap.get(titleString);     
  139.                         //得到setter方法的参数     
  140.                         Type[] ts = setMethod.getGenericParameterTypes();     
  141.                         //只要一个参数     
  142.                         String xclass = ts[0].toString();     
  143.                         //判断参数类型     
  144.                         System.out.println("类型: "+xclass);  
  145.                           
  146.                         if (fieldSetConvertMap.containsKey(titleString)) {  
  147.   
  148.   
  149. fieldSetConvertMap.get(titleString).invoke(tObject,  
  150. cell.getStringCellValue());  
  151.   
  152.   
  153. else {  
  154. if (xclass.equals("class java.lang.String")) {  
  155. setMethod.invoke(tObject, cell  
  156. .getStringCellValue());  
  157. }  
  158. else if (xclass.equals("class java.util.Date")) {  
  159. setMethod.invoke(tObject, cell  
  160. .getDateCellValue());  
  161. }  
  162. else if (xclass.equals("class java.lang.Boolean")) {  
  163. setMethod.invoke(tObject, cell  
  164. .getBooleanCellValue());  
  165. }  
  166. else if (xclass.equals("class java.lang.Integer")) {  
  167. setMethod.invoke(tObject, new Integer(cell  
  168. .getStringCellValue()));  
  169. }else if(xclass. equals("class java.lang.Long"))  
  170. {  
  171. setMethod.invoke(tObject,new Long( cell.getStringCellValue()));     
  172. }  
  173. }  
  174.                     }     
  175.                     // 下一列     
  176.                     k = k + 1;     
  177.                 }     
  178.                 dist.add(tObject);     
  179.             }     
  180.         } catch (Exception e) {     
  181.             e.printStackTrace();     
  182.             return null;     
  183.         }     
  184.         return dist;     
  185.     }     
  186.     
  187.     public static void main(String[] args) {     
  188.         ExcelImport2 test = new ExcelImport2();     
  189.         File file = new File("D://testOne.xls");     
  190.         Long befor = System.currentTimeMillis();     
  191.         List<Student> result = (ArrayList) test.importExcel(file,Student.class);     
  192.     
  193.         Long after = System.currentTimeMillis();     
  194.         System.out.println("此次操作共耗时:" + (after - befor) + "毫秒");   
  195.           
  196.          for (int i = 0; i < result.size(); i++) {     
  197.          Student testpojo=result.get(i);     
  198.          System.out.println("导入的信息为:"+testpojo.getName()+     
  199.                  "--"+testpojo.getAge()+"-"+testpojo.getSex()+"--"+testpojo.getBirthDate()+"--"+testpojo.getDesc()+"--"+testpojo.getIsVip());     
  200.          }     
  201.     
  202.         System.out.println("共转化为List的行数为:" + result.size());     
  203.     }     
  204.   
  205.   
  206. }  
  207. -