導入導出Excel工具類ExcelUtil


前言

 

 

 

前段時間做的分布式集成平台項目中,許多模塊都用到了導入導出Excel的功能,於是決定封裝一個ExcelUtil類,專門用來處理Excel的導入和導出

 

 

 

本項目的持久化層用的是JPA(底層用hibernate實現),所以導入和導出也都是基於實體類的。

 

 

 

在編寫ExcelUtil之前,在網上查了一些資料。java中用來處理Excel的第三方開源項目主要就是POIJXLpoi功能強大,但是比較耗資源,對於大數據量的導入導出性能不是太好;jxl功能簡單,但是性能比較好。

 

 

 

由於本項目的導入導出更多關注性能問題,而且jxl提供的功能基本也都夠用了,於是選擇了jxl作為支持。

 

 

 


 


 

實戰

 

 

 

導出就是將List轉化為ExcellistToExcel

 

導入就是將Excel轉化為ListexcelToList

 

 

 

導入導出中會出現各種各樣的問題,比如:數據源為空、有重復行等,我自定義了一個ExcelException異常類,用來處理這些問題。

 

 

 

ExcelException

 

 

 

[java] view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. package common.tool.excel;  
  2.   
  3. public class ExcelException extends Exception {  
  4.   
  5.     public ExcelException() {  
  6.         // TODO Auto-generated constructor stub  
  7.     }  
  8.   
  9.     public ExcelException(String message) {  
  10.         super(message);  
  11.         // TODO Auto-generated constructor stub  
  12.     }  
  13.   
  14.     public ExcelException(Throwable cause) {  
  15.         super(cause);  
  16.         // TODO Auto-generated constructor stub  
  17.     }  
  18.   
  19.     public ExcelException(String message, Throwable cause) {  
  20.         super(message, cause);  
  21.         // TODO Auto-generated constructor stub  
  22.     }  
  23.   
  24.   
  25. }  


下面就是該文的主角ExcelUtil登場了,作為一個工具類,其內的所有方法都是靜態的,方便使用。


 

ExcelUitl類

 

 

 

[java] view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. /** 
  2.  * @author     : WH 
  3.  * @group      : tgb8 
  4.  * @Date       : 2014-1-2 下午9:13:21 
  5.  * @Comments   : 導入導出Excel工具類 
  6.  * @Version    : 1.0.0 
  7.  */  
  8.   
  9. public class ExcelUtil  {  
  10.       
  11.     /** 
  12.      * @MethodName  : listToExcel 
  13.      * @Description : 導出Excel(可以導出到本地文件系統,也可以導出到瀏覽器,可自定義工作表大小) 
  14.      * @param list      數據源 
  15.      * @param fieldMap      類的英文屬性和Excel中的中文列名的對應關系 
  16.      * 如果需要的是引用對象的屬性,則英文屬性使用類似於EL表達式的格式 
  17.      * 如:list中存放的都是student,student中又有college屬性,而我們需要學院名稱,則可以這樣寫 
  18.      * fieldMap.put("college.collegeName","學院名稱") 
  19.      * @param sheetName 工作表的名稱 
  20.      * @param sheetSize 每個工作表中記錄的最大個數 
  21.      * @param out       導出流 
  22.      * @throws ExcelException 
  23.      */  
  24.     public static <T>  void   listToExcel (  
  25.             List<T> list ,  
  26.             LinkedHashMap<String,String> fieldMap,  
  27.             String sheetName,  
  28.             int sheetSize,  
  29.             OutputStream out  
  30.             ) throws ExcelException{  
  31.           
  32.           
  33.         if(list.size()==0 || list==null){  
  34.             throw new ExcelException("數據源中沒有任何數據");  
  35.         }  
  36.           
  37.         if(sheetSize>65535 || sheetSize<1){  
  38.             sheetSize=65535;  
  39.         }  
  40.           
  41.         //創建工作簿並發送到OutputStream指定的地方  
  42.         WritableWorkbook wwb;  
  43.         try {  
  44.             wwb = Workbook.createWorkbook(out);  
  45.               
  46.             //因為2003的Excel一個工作表最多可以有65536條記錄,除去列頭剩下65535條  
  47.             //所以如果記錄太多,需要放到多個工作表中,其實就是個分頁的過程  
  48.             //1.計算一共有多少個工作表  
  49.             double sheetNum=Math.ceil(list.size()/new Integer(sheetSize).doubleValue());  
  50.               
  51.             //2.創建相應的工作表,並向其中填充數據  
  52.             for(int i=0; i<sheetNum; i++){  
  53.                 //如果只有一個工作表的情況  
  54.                 if(1==sheetNum){  
  55.                     WritableSheet sheet=wwb.createSheet(sheetName, i);  
  56.                     fillSheet(sheet, list, fieldMap, 0, list.size()-1);  
  57.                   
  58.                 //有多個工作表的情況  
  59.                 }else{  
  60.                     WritableSheet sheet=wwb.createSheet(sheetName+(i+1), i);  
  61.                       
  62.                     //獲取開始索引和結束索引  
  63.                     int firstIndex=i*sheetSize;  
  64.                     int lastIndex=(i+1)*sheetSize-1>list.size()-1 ? list.size()-1 : (i+1)*sheetSize-1;  
  65.                     //填充工作表  
  66.                     fillSheet(sheet, list, fieldMap, firstIndex, lastIndex);  
  67.                 }  
  68.             }  
  69.               
  70.             wwb.write();  
  71.             wwb.close();  
  72.           
  73.         }catch (Exception e) {  
  74.             e.printStackTrace();  
  75.             //如果是ExcelException,則直接拋出  
  76.             if(e instanceof ExcelException){  
  77.                 throw (ExcelException)e;  
  78.               
  79.             //否則將其它異常包裝成ExcelException再拋出  
  80.             }else{  
  81.                 throw new ExcelException("導出Excel失敗");  
  82.             }  
  83.         }  
  84.               
  85.     }  
  86.       
  87.     /** 
  88.      * @MethodName  : listToExcel 
  89.      * @Description : 導出Excel(可以導出到本地文件系統,也可以導出到瀏覽器,工作表大小為2003支持的最大值) 
  90.      * @param list      數據源 
  91.      * @param fieldMap      類的英文屬性和Excel中的中文列名的對應關系 
  92.      * @param out       導出流 
  93.      * @throws ExcelException 
  94.      */  
  95.     public static  <T>  void   listToExcel (  
  96.             List<T> list ,  
  97.             LinkedHashMap<String,String> fieldMap,  
  98.             String sheetName,  
  99.             OutputStream out  
  100.             ) throws ExcelException{  
  101.           
  102.         listToExcel(list, fieldMap, sheetName, 65535, out);  
  103.           
  104.     }  
  105.       
  106.       
  107.     /** 
  108.      * @MethodName  : listToExcel 
  109.      * @Description : 導出Excel(導出到瀏覽器,可以自定義工作表的大小) 
  110.      * @param list      數據源 
  111.      * @param fieldMap      類的英文屬性和Excel中的中文列名的對應關系 
  112.      * @param sheetSize    每個工作表中記錄的最大個數 
  113.      * @param response  使用response可以導出到瀏覽器 
  114.      * @throws ExcelException 
  115.      */  
  116.     public static  <T>  void   listToExcel (  
  117.             List<T> list ,  
  118.             LinkedHashMap<String,String> fieldMap,  
  119.             String sheetName,  
  120.             int sheetSize,  
  121.             HttpServletResponse response   
  122.             ) throws ExcelException{  
  123.           
  124.         //設置默認文件名為當前時間:年月日時分秒  
  125.         String fileName=new SimpleDateFormat("yyyyMMddhhmmss").format(new Date()).toString();  
  126.           
  127.         //設置response頭信息  
  128.         response.reset();            
  129.         response.setContentType("application/vnd.ms-excel");        //改成輸出excel文件  
  130.         response.setHeader("Content-disposition","attachment; filename="+fileName+".xls" );  
  131.   
  132.         //創建工作簿並發送到瀏覽器  
  133.         try {  
  134.               
  135.             OutputStream out=response.getOutputStream();  
  136.             listToExcel(list, fieldMap, sheetName, sheetSize,out );  
  137.               
  138.         } catch (Exception e) {  
  139.             e.printStackTrace();  
  140.               
  141.             //如果是ExcelException,則直接拋出  
  142.             if(e instanceof ExcelException){  
  143.                 throw (ExcelException)e;  
  144.               
  145.             //否則將其它異常包裝成ExcelException再拋出  
  146.             }else{  
  147.                 throw new ExcelException("導出Excel失敗");  
  148.             }  
  149.         }  
  150.     }  
  151.       
  152.       
  153.     /** 
  154.      * @MethodName  : listToExcel 
  155.      * @Description : 導出Excel(導出到瀏覽器,工作表的大小是2003支持的最大值) 
  156.      * @param list      數據源 
  157.      * @param fieldMap      類的英文屬性和Excel中的中文列名的對應關系 
  158.      * @param response  使用response可以導出到瀏覽器 
  159.      * @throws ExcelException 
  160.      */  
  161.     public static <T>  void   listToExcel (  
  162.             List<T> list ,  
  163.             LinkedHashMap<String,String> fieldMap,  
  164.             String sheetName,  
  165.             HttpServletResponse response   
  166.             ) throws ExcelException{  
  167.           
  168.         listToExcel(list, fieldMap, sheetName, 65535, response);  
  169.     }  
  170.       
  171.     /** 
  172.      * @MethodName          : excelToList 
  173.      * @Description             : 將Excel轉化為List 
  174.      * @param in                    :承載着Excel的輸入流 
  175.      * @param sheetIndex        :要導入的工作表序號 
  176.      * @param entityClass       :List中對象的類型(Excel中的每一行都要轉化為該類型的對象) 
  177.      * @param fieldMap          :Excel中的中文列頭和類的英文屬性的對應關系Map 
  178.      * @param uniqueFields  :指定業務主鍵組合(即復合主鍵),這些列的組合不能重復 
  179.      * @return                      :List 
  180.      * @throws ExcelException 
  181.      */  
  182.     public static <T>  List<T>  excelToList(  
  183.             InputStream in,  
  184.             String sheetName,  
  185.             Class<T> entityClass,  
  186.             LinkedHashMap<String, String> fieldMap,  
  187.             String[] uniqueFields  
  188.             ) throws ExcelException{  
  189.           
  190.         //定義要返回的list  
  191.         List<T> resultList=new ArrayList<T>();  
  192.           
  193.         try {  
  194.               
  195.             //根據Excel數據源創建WorkBook  
  196.             Workbook wb=Workbook.getWorkbook(in);  
  197.             //獲取工作表  
  198.             Sheet sheet=wb.getSheet(sheetName);  
  199.               
  200.             //獲取工作表的有效行數  
  201.             int realRows=0;  
  202.             for(int i=0;i<sheet.getRows();i++){  
  203.                   
  204.                 int nullCols=0;  
  205.                 for(int j=0;j<sheet.getColumns();j++){  
  206.                     Cell currentCell=sheet.getCell(j,i);  
  207.                     if(currentCell==null || "".equals(currentCell.getContents().toString())){  
  208.                         nullCols++;  
  209.                     }  
  210.                 }  
  211.                   
  212.                 if(nullCols==sheet.getColumns()){  
  213.                     break;  
  214.                 }else{  
  215.                     realRows++;  
  216.                 }  
  217.             }  
  218.               
  219.               
  220.             //如果Excel中沒有數據則提示錯誤  
  221.             if(realRows<=1){  
  222.                 throw new ExcelException("Excel文件中沒有任何數據");  
  223.             }  
  224.               
  225.               
  226.             Cell[] firstRow=sheet.getRow(0);  
  227.   
  228.             String[] excelFieldNames=new String[firstRow.length];  
  229.               
  230.             //獲取Excel中的列名  
  231.             for(int i=0;i<firstRow.length;i++){  
  232.                 excelFieldNames[i]=firstRow[i].getContents().toString().trim();  
  233.             }  
  234.               
  235.             //判斷需要的字段在Excel中是否都存在  
  236.             boolean isExist=true;  
  237.             List<String> excelFieldList=Arrays.asList(excelFieldNames);  
  238.             for(String cnName : fieldMap.keySet()){  
  239.                 if(!excelFieldList.contains(cnName)){  
  240.                     isExist=false;  
  241.                     break;  
  242.                 }  
  243.             }  
  244.               
  245.             //如果有列名不存在,則拋出異常,提示錯誤  
  246.             if(!isExist){  
  247.                 throw new ExcelException("Excel中缺少必要的字段,或字段名稱有誤");  
  248.             }  
  249.               
  250.               
  251.             //將列名和列號放入Map中,這樣通過列名就可以拿到列號  
  252.             LinkedHashMap<String, Integer> colMap=new LinkedHashMap<String, Integer>();  
  253.             for(int i=0;i<excelFieldNames.length;i++){  
  254.                 colMap.put(excelFieldNames[i], firstRow[i].getColumn());  
  255.             }   
  256.               
  257.               
  258.               
  259.             //判斷是否有重復行  
  260.             //1.獲取uniqueFields指定的列  
  261.             Cell[][] uniqueCells=new Cell[uniqueFields.length][];  
  262.             for(int i=0;i<uniqueFields.length;i++){  
  263.                 int col=colMap.get(uniqueFields[i]);  
  264.                 uniqueCells[i]=sheet.getColumn(col);  
  265.             }  
  266.               
  267.             //2.從指定列中尋找重復行  
  268.             for(int i=1;i<realRows;i++){  
  269.                 int nullCols=0;  
  270.                 for(int j=0;j<uniqueFields.length;j++){  
  271.                     String currentContent=uniqueCells[j][i].getContents();  
  272.                     Cell sameCell=sheet.findCell(currentContent,   
  273.                             uniqueCells[j][i].getColumn(),  
  274.                             uniqueCells[j][i].getRow()+1,   
  275.                             uniqueCells[j][i].getColumn(),   
  276.                             uniqueCells[j][realRows-1].getRow(),   
  277.                             true);  
  278.                     if(sameCell!=null){  
  279.                         nullCols++;  
  280.                     }  
  281.                 }  
  282.                   
  283.                 if(nullCols==uniqueFields.length){  
  284.                     throw new ExcelException("Excel中有重復行,請檢查");  
  285.                 }  
  286.             }  
  287.   
  288.             //將sheet轉換為list  
  289.             for(int i=1;i<realRows;i++){  
  290.                 //新建要轉換的對象  
  291.                 T entity=entityClass.newInstance();  
  292.                   
  293.                 //給對象中的字段賦值  
  294.                 for(Entry<String, String> entry : fieldMap.entrySet()){  
  295.                     //獲取中文字段名  
  296.                     String cnNormalName=entry.getKey();  
  297.                     //獲取英文字段名  
  298.                     String enNormalName=entry.getValue();  
  299.                     //根據中文字段名獲取列號  
  300.                     int col=colMap.get(cnNormalName);  
  301.                       
  302.                     //獲取當前單元格中的內容  
  303.                     String content=sheet.getCell(col, i).getContents().toString().trim();  
  304.                       
  305.                     //給對象賦值  
  306.                     setFieldValueByName(enNormalName, content, entity);  
  307.                 }  
  308.                   
  309.                 resultList.add(entity);  
  310.             }  
  311.         } catch(Exception e){  
  312.             e.printStackTrace();  
  313.             //如果是ExcelException,則直接拋出  
  314.             if(e instanceof ExcelException){  
  315.                 throw (ExcelException)e;  
  316.               
  317.             //否則將其它異常包裝成ExcelException再拋出  
  318.             }else{  
  319.                 e.printStackTrace();  
  320.                 throw new ExcelException("導入Excel失敗");  
  321.             }  
  322.         }  
  323.         return resultList;  
  324.     }  
  325.       
  326.       
  327.       
  328.       
  329.       
  330.     /*<-------------------------輔助的私有方法----------------------------------------------->*/  
  331.     /** 
  332.      * @MethodName  : getFieldValueByName 
  333.      * @Description : 根據字段名獲取字段值 
  334.      * @param fieldName 字段名 
  335.      * @param o 對象 
  336.      * @return  字段值 
  337.      */  
  338.     private static  Object getFieldValueByName(String fieldName, Object o) throws Exception{  
  339.           
  340.         Object value=null;  
  341.         Field field=getFieldByName(fieldName, o.getClass());  
  342.           
  343.         if(field !=null){  
  344.             field.setAccessible(true);  
  345.             value=field.get(o);  
  346.         }else{  
  347.             throw new ExcelException(o.getClass().getSimpleName() + "類不存在字段名 "+fieldName);  
  348.         }  
  349.           
  350.         return value;  
  351.     }  
  352.       
  353.     /** 
  354.      * @MethodName  : getFieldByName 
  355.      * @Description : 根據字段名獲取字段 
  356.      * @param fieldName 字段名 
  357.      * @param clazz 包含該字段的類 
  358.      * @return 字段 
  359.      */  
  360.     private static Field getFieldByName(String fieldName, Class<?>  clazz){  
  361.         //拿到本類的所有字段  
  362.         Field[] selfFields=clazz.getDeclaredFields();  
  363.           
  364.         //如果本類中存在該字段,則返回  
  365.         for(Field field : selfFields){  
  366.             if(field.getName().equals(fieldName)){  
  367.                 return field;  
  368.             }  
  369.         }  
  370.           
  371.         //否則,查看父類中是否存在此字段,如果有則返回  
  372.         Class<?> superClazz=clazz.getSuperclass();  
  373.         if(superClazz!=null  &&  superClazz !=Object.class){  
  374.             return getFieldByName(fieldName, superClazz);  
  375.         }  
  376.           
  377.         //如果本類和父類都沒有,則返回空  
  378.         return null;  
  379.     }  
  380.       
  381.       
  382.       
  383.     /** 
  384.      * @MethodName  : getFieldValueByNameSequence 
  385.      * @Description :  
  386.      * 根據帶路徑或不帶路徑的屬性名獲取屬性值 
  387.      * 即接受簡單屬性名,如userName等,又接受帶路徑的屬性名,如student.department.name等 
  388.      *  
  389.      * @param fieldNameSequence  帶路徑的屬性名或簡單屬性名 
  390.      * @param o 對象 
  391.      * @return  屬性值 
  392.      * @throws Exception 
  393.      */  
  394.     private static  Object getFieldValueByNameSequence(String fieldNameSequence, Object o) throws Exception{  
  395.           
  396.         Object value=null;  
  397.           
  398.         //將fieldNameSequence進行拆分  
  399.         String[] attributes=fieldNameSequence.split("\\.");  
  400.         if(attributes.length==1){  
  401.             value=getFieldValueByName(fieldNameSequence, o);  
  402.         }else{  
  403.             //根據屬性名獲取屬性對象  
  404.             Object fieldObj=getFieldValueByName(attributes[0], o);  
  405.             String subFieldNameSequence=fieldNameSequence.substring(fieldNameSequence.indexOf(".")+1);  
  406.             value=getFieldValueByNameSequence(subFieldNameSequence, fieldObj);  
  407.         }  
  408.         return value;   
  409.           
  410.     }   
  411.       
  412.       
  413.     /** 
  414.      * @MethodName  : setFieldValueByName 
  415.      * @Description : 根據字段名給對象的字段賦值 
  416.      * @param fieldName  字段名 
  417.      * @param fieldValue    字段值 
  418.      * @param o 對象 
  419.      */  
  420.     private static void setFieldValueByName(String fieldName,Object fieldValue,Object o) throws Exception{  
  421.           
  422.             Field field=getFieldByName(fieldName, o.getClass());  
  423.             if(field!=null){  
  424.                 field.setAccessible(true);  
  425.                 //獲取字段類型  
  426.                 Class<?> fieldType = field.getType();    
  427.                   
  428.                 //根據字段類型給字段賦值  
  429.                 if (String.class == fieldType) {    
  430.                     field.set(o, String.valueOf(fieldValue));    
  431.                 } else if ((Integer.TYPE == fieldType)    
  432.                         || (Integer.class == fieldType)) {    
  433.                     field.set(o, Integer.parseInt(fieldValue.toString()));    
  434.                 } else if ((Long.TYPE == fieldType)    
  435.                         || (Long.class == fieldType)) {    
  436.                     field.set(o, Long.valueOf(fieldValue.toString()));    
  437.                 } else if ((Float.TYPE == fieldType)    
  438.                         || (Float.class == fieldType)) {    
  439.                     field.set(o, Float.valueOf(fieldValue.toString()));    
  440.                 } else if ((Short.TYPE == fieldType)    
  441.                         || (Short.class == fieldType)) {    
  442.                     field.set(o, Short.valueOf(fieldValue.toString()));    
  443.                 } else if ((Double.TYPE == fieldType)    
  444.                         || (Double.class == fieldType)) {    
  445.                     field.set(o, Double.valueOf(fieldValue.toString()));    
  446.                 } else if (Character.TYPE == fieldType) {    
  447.                     if ((fieldValue!= null) && (fieldValue.toString().length() > 0)) {    
  448.                         field.set(o, Character    
  449.                                 .valueOf(fieldValue.toString().charAt(0)));    
  450.                     }    
  451.                 }else if(Date.class==fieldType){  
  452.                     field.set(o, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(fieldValue.toString()));  
  453.                 }else{  
  454.                     field.set(o, fieldValue);  
  455.                 }  
  456.             }else{  
  457.                 throw new ExcelException(o.getClass().getSimpleName() + "類不存在字段名 "+fieldName);  
  458.             }  
  459.     }  
  460.       
  461.       
  462.     /** 
  463.      * @MethodName  : setColumnAutoSize 
  464.      * @Description : 設置工作表自動列寬和首行加粗 
  465.      * @param ws 
  466.      */  
  467.     private static void setColumnAutoSize(WritableSheet ws,int extraWith){  
  468.         //獲取本列的最寬單元格的寬度  
  469.         for(int i=0;i<ws.getColumns();i++){  
  470.             int colWith=0;  
  471.             for(int j=0;j<ws.getRows();j++){  
  472.                 String content=ws.getCell(i,j).getContents().toString();  
  473.                 int cellWith=content.length();  
  474.                 if(colWith<cellWith){  
  475.                     colWith=cellWith;  
  476.                 }  
  477.             }  
  478.             //設置單元格的寬度為最寬寬度+額外寬度  
  479.             ws.setColumnView(i, colWith+extraWith);  
  480.         }  
  481.           
  482.     }  
  483.       
  484.     /** 
  485.      * @MethodName  : fillSheet 
  486.      * @Description : 向工作表中填充數據 
  487.      * @param sheet     工作表  
  488.      * @param list  數據源 
  489.      * @param fieldMap 中英文字段對應關系的Map 
  490.      * @param firstIndex    開始索引 
  491.      * @param lastIndex 結束索引 
  492.      */  
  493.     private static <T> void fillSheet(  
  494.             WritableSheet sheet,  
  495.             List<T> list,  
  496.             LinkedHashMap<String,String> fieldMap,  
  497.             int firstIndex,  
  498.             int lastIndex  
  499.             )throws Exception{  
  500.           
  501.         //定義存放英文字段名和中文字段名的數組  
  502.         String[] enFields=new String[fieldMap.size()];  
  503.         String[] cnFields=new String[fieldMap.size()];  
  504.           
  505.         //填充數組  
  506.         int count=0;  
  507.         for(Entry<String,String> entry:fieldMap.entrySet()){  
  508.             enFields[count]=entry.getKey();  
  509.             cnFields[count]=entry.getValue();  
  510.             count++;  
  511.         }  
  512.         //填充表頭  
  513.         for(int i=0;i<cnFields.length;i++){  
  514.             Label label=new Label(i,0,cnFields[i]);  
  515.             sheet.addCell(label);  
  516.         }  
  517.           
  518.         //填充內容  
  519.         int rowNo=1;  
  520.         for(int index=firstIndex;index<=lastIndex;index++){  
  521.             //獲取單個對象  
  522.             T item=list.get(index);  
  523.             for(int i=0;i<enFields.length;i++){  
  524.                 Object objValue=getFieldValueByNameSequence(enFields[i], item);  
  525.                 String fieldValue=objValue==null ? "" : objValue.toString();  
  526.                 Label label =new Label(i,rowNo,fieldValue);  
  527.                 sheet.addCell(label);  
  528.             }  
  529.               
  530.             rowNo++;  
  531.         }  
  532.           
  533.         //設置自動列寬  
  534.         setColumnAutoSize(sheet, 5);  
  535.     }  
  536.       
  537. }  


該工具類有4個重載的導出方法和1個導入方法,大家可以根據實際情況進行選擇。

 

 

 

總結

 

導入和導出方法都是通過傳一個fieldMap參數(類的英文屬性和Excel的中文列頭的對應關系)來連接實體類和Excel

 

導出的時候可以選擇導出到本地文件系統或導出到瀏覽器,也可以自定義每個工作表的大小

 

導入的時候可以自定義業務主鍵組合uniqueFields,這樣就可以檢測Excel中是否有重復行了

 

 

來自:http://blog.csdn.net/wzwenhuan/article/details/18838821

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM