java通过poi模板导出excel

java通过poi来读写excel目前很方便,支持xls和xlsx格式,目前代码支持按照sheet模板导出,并且支持sheet页级的模板复制功能。

 附上poi的maven配置:

 

Java代码   收藏代码
  1.   
  2.      org.apache.poi  
  3.      poi-ooxml  
  4.      3.16  
  5.    

 我使用了最新的版本。

 

先贴一下sheet页模板数据的封装:

 

Java代码   收藏代码
  1. /** 
  2.  * sheet页数据定制 
  3.  * @author lyf 
  4.  * 
  5.  */  
  6. public class SheetData  {  
  7.   
  8.     /** 
  9.      * sheet页中存储 #{key} 的数据 
  10.      */  
  11.     private Map map = new HashMap();  
  12.       
  13.     /** 
  14.      * 列表数据存储 sheet页中替换${key} 并以列为单位向下赋值 
  15.      */  
  16.     private List  datas = new LinkedList ();  
  17.       
  18.     private String name ;  
  19.       
  20.     public void setName(String name) {  
  21.         this.name = name;  
  22.     }  
  23.       
  24.     public String getName() {  
  25.         return name;  
  26.     }  
  27.       
  28.       
  29.       
  30.     public SheetData(String name) {  
  31.         super();  
  32.         this.name = name;  
  33.     }  
  34.   
  35.     public void put(String key , Object value) {  
  36.         map.put(key, value);  
  37.     }  
  38.       
  39.     public void remove(String key) {  
  40.         map.remove(key);  
  41.     }  
  42.       
  43.     public Object get(String key) {  
  44.         return map.get(key);  
  45.     }  
  46.       
  47.     /** 
  48.      * 清理map存储和数据存储 
  49.      */  
  50.     public void clear() {  
  51.         map.clear();  
  52.         datas.clear();  
  53.     }  
  54.       
  55.     public void addData(Object t){  
  56.         datas.add(t);  
  57.     }  
  58.       
  59.     public void addDatas(Listextends Object> list) {  
  60.         datas.addAll(list);  
  61.     }  
  62.       
  63.    
  64.     public List  getDatas() {  
  65.         return datas;  
  66.     }  
  67.       
  68. }  
  69.  

     以下是针对sheet模板的封装类:

    Java代码   收藏代码
    1. /** 
    2.  * excel操作公共类-提供excel按照模板输出 
    3.  * @author lyf 
    4.  * 
    5.  */  
    6. public class ExcelUtils {  
    7.    
    8.       
    9.         
    10.     /** 
    11.      * Sheet复制 
    12.      * @param fromSheet 
    13.      * @param toSheet 
    14.      * @param copyValueFlag 
    15.      */  
    16.     public static void copySheet(Workbook wb,Sheet fromSheet, Sheet toSheet,  
    17.             boolean copyValueFlag) {  
    18.         //合并区域处理  
    19.           
    20.         mergerRegion(fromSheet, toSheet);  
    21.         int index = 0;  
    22.         for (Iterator rowIt = fromSheet.rowIterator(); rowIt.hasNext();) {  
    23.             Row tmpRow =  rowIt.next();  
    24.             Row newRow = toSheet.createRow(tmpRow.getRowNum());  
    25.                
    26.             CellStyle style = tmpRow.getRowStyle();  
    27.             if(style != null)  
    28.                 newRow.setRowStyle(tmpRow.getRowStyle());  
    29.               
    30.             newRow.setHeight(tmpRow.getHeight());  
    31.               
    32.             //针对第一行设置行宽  
    33.             if(index == 0) {  
    34.                 int first = tmpRow.getFirstCellNum();  
    35.                 int last = tmpRow.getLastCellNum();  
    36.                 for(int i = first ; i < last ; i++) {  
    37.                     int w = fromSheet.getColumnWidth(i);  
    38.                     toSheet.setColumnWidth(i, w + 1);  
    39.                 }  
    40.                 toSheet.setDefaultColumnWidth(fromSheet.getDefaultColumnWidth());  
    41.             }  
    42.               
    43.             //行复制  
    44.             copyRow(wb,tmpRow,newRow,copyValueFlag);  
    45.               
    46.             index++ ;  
    47.         }  
    48.     }  
    49.     /** 
    50.      * 行复制功能 
    51.      * @param fromRow 
    52.      * @param toRow 
    53.      */  
    54.      static void copyRow(Workbook wb,Row fromRow,Row toRow,boolean copyValueFlag){  
    55.         for (Iterator cellIt = fromRow.cellIterator(); cellIt.hasNext();) {  
    56.             Cell tmpCell = cellIt.next();  
    57.             Cell newCell = toRow.createCell(tmpCell.getColumnIndex());  
    58.             copyCell(wb,tmpCell, newCell, copyValueFlag);  
    59.         }  
    60.     }  
    61.     /** 
    62.     * 复制原有sheet的合并单元格到新创建的sheet 
    63.     *  
    64.     * @param sheetCreat 新创建sheet 
    65.     * @param sheet      原有的sheet 
    66.     */  
    67.      static void mergerRegion(Sheet fromSheet, Sheet toSheet) {  
    68.        int sheetMergerCount = fromSheet.getNumMergedRegions();  
    69.        for (int i = 0; i < sheetMergerCount; i++) {  
    70.              
    71.            CellRangeAddress cra = fromSheet.getMergedRegion(i);  
    72.           
    73.            toSheet.addMergedRegion(cra);  
    74.        }  
    75.     }  
    76.     /** 
    77.      * 复制单元格 
    78.      *  
    79.      * @param srcCell 
    80.      * @param distCell 
    81.      * @param copyValueFlag 
    82.      *            true则连同cell的内容一起复制 
    83.      */  
    84.     public static void copyCell(Workbook wb,Cell srcCell, Cell distCell,  
    85.             boolean copyValueFlag) {  
    86.           
    87.            
    88.           
    89.         CellStyle newstyle=wb.createCellStyle();  
    90.         //copyCellStyle(srcCell.getCellStyle(), newstyle);  
    91.         //distCell.setEncoding(srcCell.);  
    92.         newstyle.cloneStyleFrom(srcCell.getCellStyle());  
    93.         //样式  
    94.         distCell.setCellStyle(newstyle);  
    95.         //评论  
    96.         if (srcCell.getCellComment() != null) {  
    97.             distCell.setCellComment(srcCell.getCellComment());  
    98.         }  
    99.         // 不同数据类型处理  
    100.         CellType srcCellType = srcCell.getCellTypeEnum();  
    101.         distCell.setCellType(srcCellType);  
    102.           
    103.            
    104.         if (copyValueFlag) {  
    105.             if (srcCellType == CellType.NUMERIC) {  
    106.                 if (DateUtil.isCellDateFormatted(srcCell)) {  
    107.                     distCell.setCellValue(srcCell.getDateCellValue());  
    108.                 } else {  
    109.                     distCell.setCellValue(srcCell.getNumericCellValue());  
    110.                 }  
    111.             } else if (srcCellType == CellType.STRING ) {  
    112.                 distCell.setCellValue(srcCell.getRichStringCellValue());  
    113.             } else if (srcCellType == CellType.BLANK ) {  
    114.                 // nothing21  
    115.             } else if (srcCellType == CellType.BOOLEAN  ) {  
    116.                 distCell.setCellValue(srcCell.getBooleanCellValue());  
    117.             } else if (srcCellType == CellType.ERROR ) {  
    118.                 distCell.setCellErrorValue(srcCell.getErrorCellValue());  
    119.                
    120.             } else if (srcCellType == CellType.FORMULA  ) {  
    121.                 distCell.setCellFormula(srcCell.getCellFormula());  
    122.             } else { // nothing29  
    123.             }  
    124.         }  
    125.     }  
    126.       
    127.       
    128.     /** 
    129.      * 写入excel数据 
    130.      * @param model 采用的模板 位置在 src/model/下 模板第一个sheet页必须是模板sheet 
    131.      * @param sheetDatas 模板数据 
    132.      */  
    133.        
    134.     public static void writeData(String model , OutputStream out,SheetData... sheetDatas ) {  
    135.           
    136.         Workbook wb = null;  
    137.         try {  
    138.               
    139.             InputStream input = ExcelUtils.class.getResourceAsStream("/model/" + model);  
    140.               
    141.             if(input == null) {  
    142.                 throw new RuntimeException("model excel file load error :/model/" + model + " , check model file is exists !");  
    143.             }  
    144.               
    145.             if(model.endsWith(".xlsx"))  
    146.                 wb = new XSSFWorkbook(input);  
    147.             else if(model.endsWith(".xls"))  
    148.                 wb = new HSSFWorkbook(input);  
    149.             else  
    150.                 throw new RuntimeException("model file format is not valid , this : " + model + " , eg:.xlsx or xls");  
    151.         } catch (IOException e) {  
    152.             // TODO Auto-generated catch block  
    153.             //e.printStackTrace();  
    154.   
    155.             throw new RuntimeException("model excel file load error :/model/" + model);  
    156.         }  
    157.   
    158.         Sheet source =  wb.getSheetAt(0);  
    159.            
    160.         //就一个的话 直接用模板  
    161.         int size = sheetDatas.length ;  
    162.         for(int i = 0 ; i < size  ; i++) {  
    163.               
    164.             if(i == 0) {  
    165.                 wb.setSheetName(0, sheetDatas[0].getName());  
    166.                   
    167.             } else {  
    168.                 Sheet toSheet = wb.createSheet(sheetDatas[i].getName());  
    169.                 //复制格式  
    170.                 copySheet(wb, source, toSheet, true);  
    171.             }  
    172.                
    173.                
    174.         }  
    175.           
    176.         for(int i = 0 ; i < size  ; i++) {  
    177.             //写数据  
    178.             writeData(sheetDatas[i], wb.getSheetAt(i));  
    179.         }  
    180.            
    181.         try {  
    182.             wb.write(out);  
    183.             out.flush();  
    184.             wb.close();  
    185.             out.close();  
    186.         } catch (IOException e) {  
    187.             // TODO Auto-generated catch block  
    188.             e.printStackTrace();  
    189.         }  
    190.           
    191.           
    192.     }  
    193.       
    194.     /** 
    195.      * 向sheet页中写入数据 
    196.      * @param values 数据Map 
    197.      * @param sheet sheet 
    198.      */  
    199.       public static void writeData(SheetData sheetData , Sheet sheet) {  
    200.           
    201.         //从sheet中找到匹配符 #{}表示单个 , ${}表示集合,从该单元格开始向下追加  
    202.        
    203.         for(Iterator rowIt = sheet.rowIterator(); rowIt.hasNext();) {  
    204.             Row row = rowIt.next();  
    205.             //取cell  
    206.             for(int j = row.getFirstCellNum() ; j < row.getLastCellNum() ; j++) {  
    207.                   
    208.                 Cell cell = row.getCell(j);  
    209.    
    210.                 //判断cell的内容是否包含 $ 或者#  
    211.                 if(cell != null && cell.getCellTypeEnum() == CellType.STRING && cell.getStringCellValue() != null   
    212.                             && (cell.getStringCellValue().contains("$") || cell.getStringCellValue().contains("#") )) {  
    213.                     //剥离# $  
    214.                     String[] winds = CommonUtils.getWildcard(cell.getStringCellValue().trim());  
    215.                       
    216.                     for(String wind : winds) {  
    217.                           
    218.                         writeData(sheetData, wind , cell , sheet);  
    219.                     }  
    220.                       
    221.                       
    222.                 }  
    223.                   
    224.             }  
    225.               
    226.         }  
    227.     }  
    228.       
    229.     /** 
    230.      * 填充数据 
    231.      * @param values 
    232.      * @param keyWind #{name}只替换当前 or ${names} 从当前行开始向下替换 
    233.      */  
    234.     static void writeData(SheetData sheetData , String keyWind , Cell cell , Sheet sheet) {  
    235.         String key = keyWind.substring(2 , keyWind.length() - 1);  
    236.           
    237.         if(keyWind.startsWith("#")) {  
    238.               
    239.             //简单替换  
    240.                   
    241.             Object value = sheetData.get(key);  
    242.             //为空则替换为空字符串  
    243.             if(value == null)   
    244.                 value = "" ;  
    245.               
    246.             String cellValue = cell.getStringCellValue();  
    247.             cellValue = cellValue.replace(keyWind, value.toString());  
    248.               
    249.             cell.setCellValue(cellValue);  
    250.               
    251.         } else  if(keyWind.startsWith("$")) {  
    252.               
    253.             //从list中每个实体开始解,行数从当前开始  
    254.             int rowindex = cell.getRowIndex();  
    255.             int columnindex = cell.getColumnIndex();  
    256.               
    257.             Listextends Object> listdata = sheetData.getDatas();  
    258.         
    259.             //不为空的时候开始填充  
    260.             if(listdata != null && !listdata.isEmpty()){  
    261.                 for(Object o : listdata) {  
    262.                     Object cellValue = CommonUtils.getValue(o, key);  
    263.                       
    264.                     Row row = sheet.getRow(rowindex);  
    265.                     if(row == null) {  
    266.                         row = sheet.createRow(rowindex);  
    267.                     }  
    268.                       
    269.                        
    270.                     //取出cell  
    271.                     Cell c = row.getCell(columnindex);  
    272.                     if(c == null)   
    273.                         c = row.createCell(columnindex);  
    274.                     if(cell.getCellStyle() != null){   
    275.                         c.setCellStyle(cell.getCellStyle());  
    276.                           
    277.                     }  
    278.                            
    279.                     if(cell.getCellTypeEnum() != null) {  
    280.                         c.setCellType(cell.getCellTypeEnum());  
    281.                        
    282.                     }  
    283.                        
    284.                     if(cellValue != null) {  
    285.                         if(cellValue instanceof Number || CommonUtils.isNumber(cellValue) )  
    286.                             c.setCellValue( Double.valueOf(cellValue.toString()));  
    287.                         else if(cellValue instanceof Boolean)  
    288.                             c.setCellValue((Boolean)cellValue);  
    289.                         else if(cellValue instanceof Date)  
    290.                             c.setCellValue((Date)cellValue);  
    291.                         else  
    292.                             c.setCellValue(cellValue.toString());  
    293.                     } else {  
    294.                           
    295.                         //数据为空 如果当前单元格已经有数据则重置为空  
    296.                         if(c.getStringCellValue() != null) {  
    297.                             c.setCellValue("");  
    298.                         }  
    299.                           
    300.                     }  
    301.                       
    302.                       
    303.                       
    304.                     rowindex++ ;  
    305.                 }  
    306.             } else {  
    307.                 //list数据为空则将$全部替换空字符串  
    308.                 String cellValue = "" ;  
    309.                    
    310.                 cell.setCellValue(cellValue);  
    311.                   
    312.             }  
    313.               
    314.               
    315.               
    316.         }  
    317.           
    318.     }  
    319.       
    320. }  

     

     其中注意我的 模板文件全部放在 source/model/  目录下,大家用的时候改成自己实际的位置。

     

     

    其中用到了CommonUtils公共类中封装的几个静态方法:

    Java代码   收藏代码
    1. /** 
    2.    * 从实体中解析出字段数据 
    3.    * @param data 可能为pojo或者map 从field中解析 
    4.    * @param field 字段名称 
    5.    * @return 
    6.    */  
    7.      
    8.   @SuppressWarnings("rawtypes")  
    9. public static Object getValue(Object data , String field) {  
    10.         
    11.       if(data instanceof Map) {  
    12.             
    13.           Map map = (Map) data;  
    14.           return map.get(field);  
    15.       }  
    16.       try {  
    17.             
    18.           String method = "get" + field.substring(0 , 1).toUpperCase() + field.substring(1);  
    19.             
    20.           Method m = data.getClass().getMethod(method, null);  
    21.             
    22.           if(m != null) {  
    23.               return m.invoke(data, null);  
    24.           }  
    25.             
    26.       } catch (Exception e) {  
    27.           // TODO Auto-generated catch block  
    28.          // e.printStackTrace();  
    29.           logger.error("data invoke error , data:" + data + " , key:" + field);  
    30.           return null;  
    31.       }   
    32.         
    33.         
    34.       return null ;  
    35.         
    36.   }  
    37.     
    38.   /** 
    39.    * 判断是否为数字 
    40.    * @param v 
    41.    * @return 
    42.    */  
    43.   public static boolean isNumber(Object v) {  
    44.         
    45.       if(v == nullreturn false;   
    46.         
    47.       if(v instanceof Number) {  
    48.           return true ;  
    49.       } else if(v.toString().matches("^\\d+$")) {  
    50.           return true ;  
    51.       } else if(v.toString().matches("^-?\\d+\\.?\\d+$")) {  
    52.           return true ;  
    53.       } else {  
    54.           try{  
    55.               Double.parseDouble(v.toString());  
    56.               return true ;  
    57.           }catch(Exception e) {  
    58.               return false;  
    59.           }  
    60.            
    61.             
    62.       }  
    63.         
    64.   }  
    65.   
    66. /** 
    67.    * 返回 #{} 或者 ${} 中包含的值 
    68.    * @param str 
    69.    * @param type 
    70.    * @return eg:#{name} ${ages}  
    71.    */  
    72.   public static String[] getWildcard(String str ) {  
    73.         
    74.      List list = new ArrayList();  
    75.        
    76.      int start = 0;  
    77.      while(start < str.length() && start >= 0) {  
    78.            
    79.          start = str.indexOf("{", start);  
    80.            
    81.          int end = str.indexOf("}", start);  
    82.          if(start > 0) {  
    83.              String wc = str.substring(start - 1 , end + 1);  
    84.                
    85.              list.add(wc);  
    86.          }  
    87.           
    88.          if(start < 0break ;  
    89.            
    90.          start = end + 1;  
    91.            
    92.      }  
    93.        
    94.      return list.toArray(new String[0]);  
    95.         
    96.   }  

     

     

     

    下面开始写测试,编辑一个excel模板:



     

     

    编写一个测试数据实体(实际使用Map效率会更好一些):

    Java代码   收藏代码
    1. public class TestData {  
    2.     private int id ;  
    3.     private int p_id ;  
    4.     private String name ;  
    5.     public int getId() {  
    6.         return id;  
    7.     }  
    8.     public void setId(int id) {  
    9.         this.id = id;  
    10.     }  
    11.     public int getP_id() {  
    12.         return p_id;  
    13.     }  
    14.     public void setP_id(int p_id) {  
    15.         this.p_id = p_id;  
    16.     }  
    17.     public String getName() {  
    18.         return name;  
    19.     }  
    20.     public void setName(String name) {  
    21.         this.name = name;  
    22.     }  
    23.     public TestData(int id, int p_id, String name) {  
    24.         super();  
    25.         this.id = id;  
    26.         this.p_id = p_id;  
    27.         this.name = name;  
    28.     }  
    29.       
    30.       
    31. }  

     

    编写测试类,注意模型test.xlsx 已经放入src/model/ 目录下:

    Java代码   收藏代码
    1. import java.io.File;  
    2. import java.io.FileNotFoundException;  
    3. import java.io.FileOutputStream;  
    4.   
    5. import com.xahl.data.common.ExcelUtils;  
    6. import com.xahl.data.pojo.SheetData;  
    7.   
    8. public class TestExcel2 {  
    9.       
    10.       
    11.   
    12.     public static void main(String[] args) {  
    13.           
    14.         //获取模板   
    15.         String model = "test.xlsx" ;   
    16.         File f = new File("e:/test.xlsx");  
    17.   
    18.         SheetData[] sds = new SheetData[5];  
    19.           
    20.         //创建5个数据sheet  
    21.         forint i = 0 ; i < 5 ; i++) {  
    22.             SheetData sd = new SheetData("测试" + i);  
    23.             sd.put("name""张三" + i);  
    24.             sd.put("age"13);  
    25.               
    26.             //每个sheet页加入100条测试数据  
    27.             //注意这里可以加入pojo也可以直接使用map,理论上map在这里效率更高一些  
    28.             for(int j = 0 ; j < 100 ; j++) {  
    29.                 TestData td = new TestData(j, j * -1"t" + j);  
    30.                 sd.addData(td);;  
    31.             }  
    32.                
    33.             sds[i] = sd ;  
    34.         }  
    35.            
    36.                
    37.         try {  
    38.             ExcelUtils.writeData(model, new FileOutputStream(f) ,sds);  
    39.         } catch (FileNotFoundException e) {  
    40.             // TODO Auto-generated catch block  
    41.             e.printStackTrace();  
    42.         }  
    43.            
    44.           
    45.   
    46.     }  
    47.   
    48. }  
    49.    

     

    输出文件如下:



     



     

     

      模板中单元格的样式会延续复制,包含颜色,宽度等等。有兴趣大家可以一起扩展一下。

    转载自我瓜哥:http://jjxliu306.iteye.com/blog/2383610

    你可能感兴趣的:(poi,java,poi,excel)