zoukankan      html  css  js  c++  java
  • 使用POI生成Excel报表

    先把报表模板截图贴上来


    使用POI生成Excel报表


    下面是POI编写的报表生成类ExcelReport.java

    package com.jadyer.report;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.CellStyle;
    import org.apache.poi.ss.usermodel.Row;
    import org.apache.poi.ss.usermodel.Sheet;
    import org.apache.poi.ss.usermodel.Workbook;
    import org.apache.poi.ss.usermodel.WorkbookFactory;
    
    /**
     * 使用POI生成Excel报表
     * @see 它所生成的报表是根据Excel模块文件生成的
     * @see 这里要用到poi-3.9-20121203.jar和poi-ooxml-3.9-20121203.jar
     * @see 另外模板文件<<ReportTemplate.xls>>下载地址为http://download.csdn.net/detail/jadyer/5736263
     * @create Jul 5, 2013 9:54:46 PM
     * @author 玄玉<http://blog.csdn.net/jadyer>
     */
    public enum ExcelReport {
    	//实现单例模式的唯一实例
    	INSTANCE;
    	/**报表模板文件的存储位置*/
    	private static final String REPORT_TEMPLATE_FILE_PATH = "/ReportTemplate.xls";
    	/**本列开始填充序号的标识*/
    	private static final String SERIAL_NO = "serialNo";
    	/**本行开始填充数据的标识*/
    	private static final String DATA_BEGIN = "dataBegin";
    	/**表格采用同列样式的标识*/
    	private static final String USE_STYLES = "useStyles";
    	/**表格样式采用的默认样式*/
    	private static final String DEFAULT_STYLES = "defaultStyles";
    	/**初始行的下标(指的是填充数据的第一个单元格下标)*/
    	private int initRowIndex;
    	/**初始列的下标(指的是填充数据的第一个单元格下标)*/
    	private int initColIndex;
    	/**当前行的下标(指的是填充数据的当前单元格下标)*/
    	private int currRowIndex;
    	/**当前列的下标(指的是填充数据的当前单元格下标)*/
    	private int currColIndex;
    	/**最后一行的下标*/
    	private int lastRowIndex;
    	/**序号列的第一个单元格的下标*/
    	private int serialColIndex;
    	/**默认行高(指的是填充数据的第一个单元格的行高)*/
    	private float defaultRowHeight;
    	/**存放模板中所有表格样式(键为99表示表格的默认样式)*/
    	private Map<Integer, CellStyle> allCellStyle = new HashMap<Integer, CellStyle>();
    	private Row currRow;
    	private Sheet sheet;
    	private Workbook wb;
    	
    	
    	/**
    	 * 基础数据初始化
    	 */
    	private ExcelReport(){
    		try {
    			//从指定目录中读取
    			//wb = WorkbookFactory.create(new File(REPORT_TEMPLATE_FILE_PATH));
    			//从classpath中读取模板文档
    			wb = WorkbookFactory.create(ExcelReport.class.getResourceAsStream(REPORT_TEMPLATE_FILE_PATH));
    			//获取模板中的第一个Sheet
    			sheet = wb.getSheetAt(0);
    		} catch (InvalidFormatException e) {
    			throw new RuntimeException("模板文件格式无效", e);
    		} catch (IOException e) {
    			throw new RuntimeException("模板文件不存在", e);
    		}
    		for(Row row : sheet){
    			for(Cell cell : row){
    				//报表模板文件default.xls中约定序号和SERIAL_NO和DATA_BEGIN都是String类型的
    				if(Cell.CELL_TYPE_STRING != cell.getCellType()){
    					continue;
    				}
    				String str = cell.getStringCellValue().trim();
    				//收集默认的表格样式
    				if(DEFAULT_STYLES.equals(str)){
    					this.allCellStyle.put(99, cell.getCellStyle());
    				}
    				//收集除默认表格样式以外的所有表格样式
    				if(USE_STYLES.equals(str)){
    					this.allCellStyle.put(cell.getColumnIndex(), cell.getCellStyle());
    				}
    				//定位序号列的第一个单元格下标
    				if(SERIAL_NO.equals(str)){
    					this.serialColIndex = cell.getColumnIndex();
    				}
    				//定位开始填充数据的第一个单元格的下标
    				if(DATA_BEGIN.equals(str)){
    					this.initColIndex = cell.getColumnIndex();
    					this.initRowIndex = row.getRowNum();
    					this.currColIndex = this.initColIndex;
    					this.currRowIndex = this.initRowIndex;
    					this.lastRowIndex = sheet.getLastRowNum();
    					this.defaultRowHeight = row.getHeightInPoints();
    				}
    			}
    		}
    	}
    	
    	
    	/**
    	 * 创建行
    	 */
    	public void createNewRow(){
    		//下移行的条件有2个:当前行非初始行,且当前行没有超过最后一行
    		if(this.currRowIndex!=this.initRowIndex && this.lastRowIndex>this.currRowIndex){
    			//将指定的几行进行下移一行
    			sheet.shiftRows(this.currRowIndex, this.lastRowIndex, 1, true, true);
    			//既然下移了那么最后一行下标就也要增大了
    			this.lastRowIndex++;
    		}
    		//在指定的行上创建一个空行(如果此行原本有单元格和数据,那么也会被空行覆盖,且创建出来的空行是没有单元格的)
    		this.currRow = sheet.createRow(this.currRowIndex);
    		this.currRow.setHeightInPoints(this.defaultRowHeight);
    		this.currRowIndex++;
    		this.currColIndex = this.initColIndex;
    	}
    	
    	
    	/**
    	 * 构造单元格(包括创建单元格和填充数据)
    	 */
    	public void buildCell(String value){
    		Cell cell = this.currRow.createCell(this.currColIndex);
    		if(this.allCellStyle.containsKey(this.currColIndex)){
    			cell.setCellStyle(this.allCellStyle.get(this.currColIndex));
    		}else{
    			cell.setCellStyle(this.allCellStyle.get(99));
    		}
    		cell.setCellValue(value);
    		this.currColIndex++;
    	}
    
    	
    	/**
    	 * 插入序号
    	 */
    	private void insertSerialNo(){
    		int index = 1;
    		Row row = null;
    		Cell cell = null;
    		for(int i=this.initRowIndex; i<this.currRowIndex; i++){
    			row = sheet.getRow(i);
    			cell = row.createCell(this.serialColIndex);
    			cell.setCellValue(index++);
    		}
    	}
    	
    	
    	/**
    	 * 替换模板文件中的常量
    	 */
    	private void replaceConstantData(){
    		Map<String, String> constantData = new HashMap<String, String>();
    		constantData.put("title", "优秀学生名单");
    		constantData.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    		constantData.put("developer", "玄玉博客<http://blog.csdn.net/jadyer>");
    		for(Row row : sheet){
    			for(Cell cell : row){
    				if(Cell.CELL_TYPE_STRING != cell.getCellType()){
    					continue;
    				}
    				String str = cell.getStringCellValue().trim();
    				if(str.startsWith("#")){
    					if(constantData.containsKey(str.substring(1))){
    						cell.setCellValue(constantData.get(str.substring(1)));
    					}
    				}
    			}
    		}
    	}
    	
    	
    	/**
    	 * 将生成的excel文件写到输出流中
    	 * @see 适用于文件下载
    	 */
    	public void writeToStream(OutputStream os){
    		this.insertSerialNo();
    		this.replaceConstantData();
    		try {
    			wb.write(os);
    		} catch (IOException e) {
    			throw new RuntimeException("写入流失败", e);
    		}
    	}
    	
    	
    	/**
    	 * 将生成的excel文件写到指定的文件中
    	 * @see 适用于硬盘保存
    	 */
    	public void writeToFile(String filepath){
    		this.insertSerialNo();
    		this.replaceConstantData();
    		FileOutputStream fos = null;
    		try {
    			fos = new FileOutputStream(filepath);
    			wb.write(fos);
    		} catch (FileNotFoundException e) {
    			throw new RuntimeException("写入的文件[" + filepath + "]不存在", e);
    		} catch (IOException e) {
    			throw new RuntimeException("写入数据失败", e);
    		} finally {
    			if(null != fos){
    				try {
    					fos.close();
    				} catch (IOException e) {
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }


    最后是其单元测试类ExcelReportTest.java(即演示实际调用步骤)

    package com.jadyer.report;
    
    import java.io.File;
    
    import org.junit.Assert;
    import org.junit.Test;
    
    import com.jadyer.report.ExcelReport;
    
    public class ExcelReportTest {
    	@Test
    	public void testExcelReportUtil(){
    		ExcelReport eru = ExcelReport.INSTANCE;
    		eru.createNewRow();
    		eru.buildCell("aa");
    		eru.buildCell("玄玉");
    		eru.buildCell("cc");
    		eru.buildCell("dd");
    		eru.createNewRow();
    		eru.buildCell("aa");
    		eru.buildCell("http://blog.csdn.net/jadyer");
    		eru.buildCell("cc");
    		eru.buildCell("dd");
    		eru.createNewRow();
    		eru.buildCell("aa");
    		eru.buildCell("蓄机而动");
    		eru.buildCell("cc");
    		eru.buildCell("dd");
    		eru.writeToFile("D:/test.xls");
    		Assert.assertTrue(new File("D:/test.xls").exists());
    	}
    }
  • 相关阅读:
    Android WebView重定向问题的解决方案
    Android 控件背景选择图片还是drawable XML资源
    Android AlertDialog 绝对位置计算
    Android 5.0以上Material Design 沉浸式状态栏
    Android 6.0系统动态请求系统相机权限
    Android软键盘在清单文件中所有配置含义
    Android,TextView的所有属性和方法
    【转载】Android控件属性大全
    Android布局及控件的属性说明
    android带有文字的图片按钮的两种实现方式
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3184881.html
Copyright © 2011-2022 走看看