`
jjxliu306
  • 浏览: 157200 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

java通过poi模板导出excel

    博客分类:
  • java
 
阅读更多

 

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

 附上poi的maven配置:

 

 <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>3.16</version>
  </dependency>

 我使用了最新的版本。

 

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

 

/**
 * sheet页数据定制
 * @author lyf
 *
 */
public class SheetData  {

	/**
	 * sheet页中存储 #{key} 的数据
	 */
	private Map<String, Object> map = new HashMap<String, Object>();
	
	/**
	 * 列表数据存储 sheet页中替换${key} 并以列为单位向下赋值
	 */
	private List<Object>  datas = new LinkedList<Object> ();
	
	private String name ;
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	
	
	public SheetData(String name) {
		super();
		this.name = name;
	}

	public void put(String key , Object value) {
		map.put(key, value);
	}
	
	public void remove(String key) {
		map.remove(key);
	}
	
	public Object get(String key) {
		return map.get(key);
	}
	
	/**
	 * 清理map存储和数据存储
	 */
	public void clear() {
		map.clear();
		datas.clear();
	}
	
	public void addData(Object t){
		datas.add(t);
	}
	
	public void addDatas(List<? extends Object> list) {
		datas.addAll(list);
	}
	
 
	public List<Object>  getDatas() {
		return datas;
	}
	
}

 

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

/**
 * excel操作公共类-提供excel按照模板输出
 * @author lyf
 *
 */
public class ExcelUtils {
 
	
	  
	/**
	 * Sheet复制
	 * @param fromSheet
	 * @param toSheet
	 * @param copyValueFlag
	 */
	public static void copySheet(Workbook wb,Sheet fromSheet, Sheet toSheet,
			boolean copyValueFlag) {
		//合并区域处理
	 	
		mergerRegion(fromSheet, toSheet);
		int index = 0;
		for (Iterator<Row> rowIt = fromSheet.rowIterator(); rowIt.hasNext();) {
			Row tmpRow =  rowIt.next();
			Row newRow = toSheet.createRow(tmpRow.getRowNum());
			 
			CellStyle style = tmpRow.getRowStyle();
			if(style != null)
				newRow.setRowStyle(tmpRow.getRowStyle());
			
			newRow.setHeight(tmpRow.getHeight());
			
			//针对第一行设置行宽
			if(index == 0) {
				int first = tmpRow.getFirstCellNum();
				int last = tmpRow.getLastCellNum();
				for(int i = first ; i < last ; i++) {
					int w = fromSheet.getColumnWidth(i);
					toSheet.setColumnWidth(i, w + 1);
				}
				toSheet.setDefaultColumnWidth(fromSheet.getDefaultColumnWidth());
			}
			
			//行复制
			copyRow(wb,tmpRow,newRow,copyValueFlag);
			
			index++ ;
		}
	}
	/**
	 * 行复制功能
	 * @param fromRow
	 * @param toRow
	 */
	 static void copyRow(Workbook wb,Row fromRow,Row toRow,boolean copyValueFlag){
		for (Iterator<Cell> cellIt = fromRow.cellIterator(); cellIt.hasNext();) {
			Cell tmpCell = cellIt.next();
			Cell newCell = toRow.createCell(tmpCell.getColumnIndex());
			copyCell(wb,tmpCell, newCell, copyValueFlag);
		}
	}
	/**
	* 复制原有sheet的合并单元格到新创建的sheet
	* 
	* @param sheetCreat 新创建sheet
	* @param sheet      原有的sheet
	*/
	 static void mergerRegion(Sheet fromSheet, Sheet toSheet) {
	   int sheetMergerCount = fromSheet.getNumMergedRegions();
	   for (int i = 0; i < sheetMergerCount; i++) {
		   
		   CellRangeAddress cra = fromSheet.getMergedRegion(i);
	    
		   toSheet.addMergedRegion(cra);
	   }
	}
	/**
	 * 复制单元格
	 * 
	 * @param srcCell
	 * @param distCell
	 * @param copyValueFlag
	 *            true则连同cell的内容一起复制
	 */
	public static void copyCell(Workbook wb,Cell srcCell, Cell distCell,
			boolean copyValueFlag) {
		
		 
		
		CellStyle newstyle=wb.createCellStyle();
		//copyCellStyle(srcCell.getCellStyle(), newstyle);
		//distCell.setEncoding(srcCell.);
		newstyle.cloneStyleFrom(srcCell.getCellStyle());
		//样式
		distCell.setCellStyle(newstyle);
		//评论
		if (srcCell.getCellComment() != null) {
			distCell.setCellComment(srcCell.getCellComment());
		}
		// 不同数据类型处理
		CellType srcCellType = srcCell.getCellTypeEnum();
		distCell.setCellType(srcCellType);
		
		 
		if (copyValueFlag) {
			if (srcCellType == CellType.NUMERIC) {
				if (DateUtil.isCellDateFormatted(srcCell)) {
					distCell.setCellValue(srcCell.getDateCellValue());
				} else {
					distCell.setCellValue(srcCell.getNumericCellValue());
				}
			} else if (srcCellType == CellType.STRING ) {
				distCell.setCellValue(srcCell.getRichStringCellValue());
			} else if (srcCellType == CellType.BLANK ) {
				// nothing21
			} else if (srcCellType == CellType.BOOLEAN  ) {
				distCell.setCellValue(srcCell.getBooleanCellValue());
			} else if (srcCellType == CellType.ERROR ) {
				distCell.setCellErrorValue(srcCell.getErrorCellValue());
			 
			} else if (srcCellType == CellType.FORMULA  ) {
				distCell.setCellFormula(srcCell.getCellFormula());
			} else { // nothing29
			}
		}
	}
	
	
	/**
	 * 写入excel数据
	 * @param model 采用的模板 位置在 src/model/下 模板第一个sheet页必须是模板sheet
	 * @param sheetDatas 模板数据
	 */
	 
	public static void writeData(String model , OutputStream out,SheetData... sheetDatas ) {
		
		Workbook wb = null;
		try {
			
			InputStream input = ExcelUtils.class.getResourceAsStream("/model/" + model);
			
			if(input == null) {
				throw new RuntimeException("model excel file load error :/model/" + model + " , check model file is exists !");
			}
			
			if(model.endsWith(".xlsx"))
				wb = new XSSFWorkbook(input);
			else if(model.endsWith(".xls"))
				wb = new HSSFWorkbook(input);
			else
				throw new RuntimeException("model file format is not valid , this : " + model + " , eg:.xlsx or xls");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();

			throw new RuntimeException("model excel file load error :/model/" + model);
		}

		Sheet source =  wb.getSheetAt(0);
		 
		//就一个的话 直接用模板
		int size = sheetDatas.length ;
		for(int i = 0 ; i < size  ; i++) {
			
			if(i == 0) {
				wb.setSheetName(0, sheetDatas[0].getName());
				
			} else {
				Sheet toSheet = wb.createSheet(sheetDatas[i].getName());
				//复制格式
				copySheet(wb, source, toSheet, true);
			}
			 
			 
		}
		
		for(int i = 0 ; i < size  ; i++) {
			//写数据
			writeData(sheetDatas[i], wb.getSheetAt(i));
		}
		 
		try {
			wb.write(out);
			out.flush();
			wb.close();
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	
	/**
	 * 向sheet页中写入数据
	 * @param values 数据Map
	 * @param sheet sheet
	 */
	  public static void writeData(SheetData sheetData , Sheet sheet) {
		
		//从sheet中找到匹配符 #{}表示单个 , ${}表示集合,从该单元格开始向下追加
	 
		for(Iterator<Row> rowIt = sheet.rowIterator(); rowIt.hasNext();) {
			Row row = rowIt.next();
			//取cell
			for(int j = row.getFirstCellNum() ; j < row.getLastCellNum() ; j++) {
				
				Cell cell = row.getCell(j);
 
				//判断cell的内容是否包含 $ 或者#
				if(cell != null && cell.getCellTypeEnum() == CellType.STRING && cell.getStringCellValue() != null 
							&& (cell.getStringCellValue().contains("$") || cell.getStringCellValue().contains("#") )) {
					//剥离# $
					String[] winds = CommonUtils.getWildcard(cell.getStringCellValue().trim());
					
					for(String wind : winds) {
						
						writeData(sheetData, wind , cell , sheet);
					}
					
					
				}
				
			}
			
		}
	}
	
	/**
	 * 填充数据
	 * @param values
	 * @param keyWind #{name}只替换当前 or ${names} 从当前行开始向下替换
	 */
	static void writeData(SheetData sheetData , String keyWind , Cell cell , Sheet sheet) {
		String key = keyWind.substring(2 , keyWind.length() - 1);
		
		if(keyWind.startsWith("#")) {
			
			//简单替换
				
			Object value = sheetData.get(key);
			//为空则替换为空字符串
			if(value == null) 
				value = "" ;
			
			String cellValue = cell.getStringCellValue();
			cellValue = cellValue.replace(keyWind, value.toString());
			
			cell.setCellValue(cellValue);
			
		} else  if(keyWind.startsWith("$")) {
			
			//从list中每个实体开始解,行数从当前开始
			int rowindex = cell.getRowIndex();
			int columnindex = cell.getColumnIndex();
			
			List<? extends Object> listdata = sheetData.getDatas();
	  
			//不为空的时候开始填充
			if(listdata != null && !listdata.isEmpty()){
				for(Object o : listdata) {
					Object cellValue = CommonUtils.getValue(o, key);
					
					Row row = sheet.getRow(rowindex);
					if(row == null) {
						row = sheet.createRow(rowindex);
					}
					
					 
					//取出cell
					Cell c = row.getCell(columnindex);
					if(c == null) 
						c = row.createCell(columnindex);
					if(cell.getCellStyle() != null){ 
						c.setCellStyle(cell.getCellStyle());
						
					}
						 
					if(cell.getCellTypeEnum() != null) {
						c.setCellType(cell.getCellTypeEnum());
					 
					}
					 
					if(cellValue != null) {
						if(cellValue instanceof Number || CommonUtils.isNumber(cellValue) )
							c.setCellValue( Double.valueOf(cellValue.toString()));
						else if(cellValue instanceof Boolean)
							c.setCellValue((Boolean)cellValue);
						else if(cellValue instanceof Date)
							c.setCellValue((Date)cellValue);
						else
							c.setCellValue(cellValue.toString());
					} else {
						
						//数据为空 如果当前单元格已经有数据则重置为空
						if(c.getStringCellValue() != null) {
							c.setCellValue("");
						}
						
					}
					
					
					
					rowindex++ ;
				}
			} else {
				//list数据为空则将$全部替换空字符串
				String cellValue = "" ;
				 
				cell.setCellValue(cellValue);
				
			}
			
			
			
		}
		
	}
	
}

 

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

 

 

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

 /**
	   * 从实体中解析出字段数据
	   * @param data 可能为pojo或者map 从field中解析
	   * @param field 字段名称
	   * @return
	   */
	   
	  @SuppressWarnings("rawtypes")
	public static Object getValue(Object data , String field) {
		  
		  if(data instanceof Map) {
			  
			  Map map = (Map) data;
			  return map.get(field);
		  }
		  try {
			  
			  String method = "get" + field.substring(0 , 1).toUpperCase() + field.substring(1);
			  
			  Method m = data.getClass().getMethod(method, null);
			  
			  if(m != null) {
				  return m.invoke(data, null);
			  }
			  
		  } catch (Exception e) {
			  // TODO Auto-generated catch block
			 // e.printStackTrace();
			  logger.error("data invoke error , data:" + data + " , key:" + field);
			  return null;
		  } 
		  
		  
		  return null ;
		  
	  }
	  
	  /**
	   * 判断是否为数字
	   * @param v
	   * @return
	   */
	  public static boolean isNumber(Object v) {
		  
		  if(v == null) return false; 
		  
		  if(v instanceof Number) {
			  return true ;
		  } else if(v.toString().matches("^\\d+$")) {
			  return true ;
		  } else if(v.toString().matches("^-?\\d+\\.?\\d+$")) {
			  return true ;
		  } else {
			  try{
				  Double.parseDouble(v.toString());
				  return true ;
			  }catch(Exception e) {
				  return false;
			  }
			 
			  
		  }
		  
	  }

 /**
	   * 返回 #{} 或者 ${} 中包含的值
	   * @param str
	   * @param type
	   * @return eg:#{name} ${ages} 
	   */
	  public static String[] getWildcard(String str ) {
		  
		 List<String> list = new ArrayList<String>();
		 
		 int start = 0;
		 while(start < str.length() && start >= 0) {
			 
			 start = str.indexOf("{", start);
			 
			 int end = str.indexOf("}", start);
			 if(start > 0) {
				 String wc = str.substring(start - 1 , end + 1);
				 
				 list.add(wc);
			 }
			
			 if(start < 0) break ;
			 
			 start = end + 1;
			 
		 }
		 
		 return list.toArray(new String[0]);
		  
	  }

 

 

 

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



 

 

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

public class TestData {
	private int id ;
	private int p_id ;
	private String name ;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getP_id() {
		return p_id;
	}
	public void setP_id(int p_id) {
		this.p_id = p_id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public TestData(int id, int p_id, String name) {
		super();
		this.id = id;
		this.p_id = p_id;
		this.name = name;
	}
	
	
}

 

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

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

import com.xahl.data.common.ExcelUtils;
import com.xahl.data.pojo.SheetData;

public class TestExcel2 {
	
	

	public static void main(String[] args) {
		
		//获取模板 
		String model = "test.xlsx" ; 
		File f = new File("e:/test.xlsx");

		SheetData[] sds = new SheetData[5];
		
		//创建5个数据sheet
		for( int i = 0 ; i < 5 ; i++) {
			SheetData sd = new SheetData("测试" + i);
			sd.put("name", "张三" + i);
			sd.put("age", 13);
			
			//每个sheet页加入100条测试数据
			//注意这里可以加入pojo也可以直接使用map,理论上map在这里效率更高一些
			for(int j = 0 ; j < 100 ; j++) {
				TestData td = new TestData(j, j * -1, "t" + j);
				sd.addData(td);;
			}
			 
			sds[i] = sd ;
		}
		 
		 	 
		try {
			ExcelUtils.writeData(model, new FileOutputStream(f) ,sds);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		 
		

	}

}
 

 

输出文件如下:



 



 

 

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

 

 

  • 大小: 32.5 KB
  • 大小: 21.3 KB
  • 大小: 19.5 KB
1
1
分享到:
评论

相关推荐

    poi基于模板导出excel

    ### POI 基于模板导出 Excel 的实现方法 #### 概述 Apache POI 是一个用于读写 Microsoft Office 格式文件的 Java 库,其中包括对 Excel 文件的支持。在实际开发过程中,经常会遇到需要根据现有的 Excel 模板来...

    java基于poi通过excel模板导出

    以上就是基于Apache POI通过模板导出Excel的基本流程。实际开发中,你可能还需要处理更复杂的情况,如多Sheet操作、合并单元格、处理图表、嵌入图片等。同时,为了提高性能,可以考虑使用SXSSFWorkbook,它提供了一...

    poi导出根据模板导出excel和简单列表导出excel源码

    在本案例中,我们关注的是如何使用 Apache POI 库来导出 Excel 文件,特别是根据模板导出和简单列表导出。下面将详细介绍这个过程。 1. **Apache POI 概述** Apache POI 提供了 Java API 来读写 Microsoft Office ...

    java基于poi使用excel模板导出

    本篇文章将深入探讨如何使用Apache POI基于模板来导出Excel文件,以满足数据展示和报告生成的需求。 首先,我们需要理解Apache POI的工作原理。POI库允许Java程序与Microsoft Excel的文件格式进行交互,提供了对XLS...

    POI使用Excel模板文件循环输出行并导出Excel

    在这个特定的例子中,我们将讨论如何使用POI库基于一个Excel模板文件循环输出数据行,并将结果导出为新的Excel文件。 首先,我们需要理解POI库的基本概念。POI提供了HSSF(Horizontally SpreadSheet Format)和XSSF...

    poi excel 模板读取并导出带公式的excel文档

    2. **通过模板导出Excel表格**: - 在开发中,通常会预先准备好一个Excel模板文件,这个模板文件包含了固定格式和一些基本的数据结构。 - Java程序通过读取这个模板文件,然后填充数据,最后将填充后的文件导出为...

    Java POI根据模板生成Excel(xlsx)文件

    模板中的单元格、公式、样式、图表等元素都以XML的形式存在,Java POI通过解析这些XML来操作Excel内容。 在使用Java POI处理模板时,我们需要做以下步骤: 1. **读取模板**:使用`XSSFWorkbook`类打开模板文件,它...

    java基于模板导出Excel表格

    除了平时简单的数据导出需求外,我们也经常...源码案例提供了模板,单个数据写入与列表数据写入以及文件导出的代码,详细的说明请参照个人博客“Excel模板导出”,源码可以让读者更加详细的了解Excel导出的过程和原理。

    java使用 POI Excel模板导出数据

    这篇博客"java使用POI Excel模板导出数据"探讨了如何利用POI库在Java中创建Excel模板并填充数据。下面将详细介绍这个过程以及相关知识点。 首先,我们需要理解Apache POI的基本概念。POI是Apache软件基金会的一个...

    POI按照模板导出Excel

    Apache POI提供了一种高效、灵活的方式,使Java开发者能够根据模板导出Excel文件。通过熟练掌握POI API,可以实现各种定制化的Excel处理需求,提高工作效率,简化数据报告的生成流程。 以上内容涵盖了使用Apache ...

    poi 基于excel模板导出功能

    四、导出Excel文件 1. 写入输出流:创建FileOutputStream,将填充好的工作簿写入到输出流中。 ```java FileOutputStream out = new FileOutputStream("output.xlsx"); workbook.write(out); out.close(); ``` 2. ...

    java复杂模板excel导出例子

    在Java编程中,导出复杂的Excel模板是一项常见的需求,尤其在数据分析、报表生成或数据交换等场景中。本文将深入探讨如何使用Java实现这一功能,包括选用的库、步骤、以及处理复杂模板的关键技巧。 首先,Java中最...

    JAVA poi 做EXCEL导出(包含图片) 完整版

    本教程将详细介绍如何使用JAVA POI库来创建一个包含图片的完整Excel导出功能。 首先,你需要在项目中引入Apache POI依赖。如果你使用的是Maven,可以在pom.xml文件中添加以下依赖: ```xml &lt;groupId&gt;org.apache....

    poi_模板导出excel,支持百万级数据模板导出

    poi导入、导出,支持百万级数据模板导出、合并excel。项目为spring-boot-2上开发。resource里面有模板,在junit测试类中修改为本地存在路径即可导出文件,在junit测试类中修改for循环的i可以模拟百万级数据导出。注意...

    Apache POI 模板导出excel.rar

    在"Apache POI 模板导出excel.rar"这个压缩包中,我们聚焦于使用Apache POI 3.16版本来生成基于Excel模板的数据导出功能。这个过程涉及到多个关键知识点,下面将详细阐述。 1. **Apache POI库**:Apache POI是一个...

    springboot+poi导出指定格式Excel模板

    springboot+poi导出指定格式Excel模板,完整项目,导出即用。springboot+poi导出指定格式Excel模板,完整项目,导出即用。springboot+poi导出指定格式Excel模板,完整项目,导出即用。springboot+poi导出指定格式...

    poi模板导出excel文件jar包.zip

    提供的"poi模板导出excel文件jar包.zip"压缩包包含两个重要的Java档案(JAR)文件:`commons-collections4-4.1.wso2v1.jar`和`commons-math3-3.0.jar`,它们是POI项目所依赖的库。 1. **Apache Commons Collections...

    java poi导出excel含工具类以及示例

    String outputFile = "D:\\excel\\excel.xlsx"; OutputStream outputStream = new FileOutputStream(outputFile); UtilExcel utilExcel = new UtilExcel(); String titles = "所属区域,所属车间,当前处理人,描述...

    java的poi生成excel图表demo

    通过这个“java的poi生成excel图表demo”,我们可以学习如何利用POI创建动态的、数据驱动的Excel曲线图,进一步提升数据的可视性和理解性。这个压缩包中的“EexcelChart”可能是示例代码、测试数据或生成的Excel文件...

Global site tag (gtag.js) - Google Analytics