上一节,介绍了基于Apache的POI对Excel基本读写操作.一般情况下使用我们使用CellStyle来修改样式,但是那样的话会显得等别麻烦.所有我们可以先自定义模板,然后从模板中读取样式即可.
下面是对模板操作的封装:
package gd.hz.poi.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Calendar;
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.RichTextString;
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;
/**
* 用于处理Excel写操作
* @author lfd
* 2013-11-25
*/
public class ExcelTemplate {
//开始位置
public final static String TEMPLATE_NAME = "datastart" ;
//样式,用于要标志自定义的样式的列.
public final static String STYLE = "style" ;
//默认样式
public final static String DEFALULT_STYLE = "defaultStyle" ;
//序号,确定Excel是否需要样式.
public final static String SERNUMS = "sernums" ;
private int initRowIndxe ; //初始行
private int initColIndex ; //初始列
private int curRowIndex ; //当前行
private int curColIndex ; //当前列
private int lastRowInex ; //最后一行
private float defaultHeight ; // 默认行高
private int serColIndex ; //序号行.
private Workbook workbook = null ;
private Sheet sheet = null ;
private Row curRow = null ; //当前行
//样式
private Map<Integer,CellStyle> styles = null ;
//默认样式
private CellStyle defaultStyle = null ;
//使用单例
private static ExcelTemplate excel = new ExcelTemplate() ;
private ExcelTemplate() {}
public static ExcelTemplate getInstance() {
return excel ;
}
/**
* 读取模板(从classpath中)
* @param path 模板路径
* @return ExcelTemplate
*/
public ExcelTemplate readTemplateClassPath(String calsspath) {
try {
workbook = WorkbookFactory.create(ExcelTemplate.class.getResourceAsStream(calsspath)) ;
initTemplate() ;
} catch (InvalidFormatException e) {
e.printStackTrace();
throw new RuntimeException("读取模板格式有错!请检查.") ;
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("读取模板文件不存在!请检查.") ;
}
return this ;
}
/**
* 读取模板(从指定路径)
* @param path 模板路径
* @return ExcelTemplate
*/
public ExcelTemplate readTemplatePath(String path) {
try {
workbook = WorkbookFactory.create(new File(path)) ;
initTemplate() ;
} catch (InvalidFormatException e) {
e.printStackTrace();
throw new RuntimeException("读取模板格式有错!请检查.") ;
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("读取模板文件不存在!请检查.") ;
}
return this ;
}
/**
* 创建新的一行
*/
public void creatNewRow() {
//curRowIndex != initRowIndxe : 当前行本身是存在的,所以下移多余.
if(lastRowInex > curRowIndex && curRowIndex != initRowIndxe) {
sheet.shiftRows(curRowIndex, lastRowInex, 1, true, true) ; //有的模板最后可能是日期或者姓名之类的非数据.所以要移动行.
lastRowInex ++ ;
}
curRow = sheet.createRow(curRowIndex) ;
curRow.setHeightInPoints(defaultHeight) ;
curRowIndex ++ ;
curColIndex = initColIndex ;
}
public void createNewCol(String value) {
Cell cell = curRow.createCell(curColIndex) ;
setStyle(cell) ;
cell.setCellValue(value) ;
curColIndex ++ ;
}
public void createNewCol(double value) {
Cell cell = curRow.createCell(curColIndex) ;
setStyle(cell) ;
cell.setCellValue(value) ;
curColIndex ++ ;
}
public void createNewCol(boolean value) {
Cell cell = curRow.createCell(curColIndex) ;
setStyle(cell) ;
cell.setCellValue(value) ;
curColIndex ++ ;
}
public void createNewCol(Date value) {
Cell cell = curRow.createCell(curColIndex) ;
setStyle(cell) ;
cell.setCellValue(value) ;
curColIndex ++ ;
}
public void createNewCol(Calendar value) {
Cell cell = curRow.createCell(curColIndex) ;
setStyle(cell) ;
cell.setCellValue(value) ;
curColIndex ++ ;
}
public void createNewCol(RichTextString value) {
Cell cell = curRow.createCell(curColIndex) ;
setStyle(cell) ;
cell.setCellValue(value) ;
curColIndex ++ ;
}
/**
* 根据#xxx替换模板中的其它样式.
* @param datas 要替换的数据
*/
public void replaceFind(Map<String, String> datas) {
if(datas == null) return ;
for(Row row : sheet) {
for(Cell cell : row) {
if(cell.getCellType() != Cell.CELL_TYPE_STRING) continue ;
String value = cell.getStringCellValue().trim() ;
if(value.startsWith("#")) {
if(datas.containsKey(value.substring(1))) {
cell.setCellValue(datas.get(value.substring(1))) ;
}
}
}
}
}
/**
* 插入序号
*/
public void insertSer() {
int index = 1 ;
Row row = null ;
Cell cell = null ;
for(int i = initRowIndxe; i < curRowIndex; i++) {
row = sheet.getRow(i) ;
cell = row.createCell(serColIndex) ;
setStyle(cell) ;
cell.setCellValue(index++) ;
}
}
/**
* 输出文件,根据路径
* @param path 路径
*/
public void writeToFile(String path) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(path) ;
workbook.write(fos) ;
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("找不到文件!请检查.") ;
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("文件输出异常!请检查.") ;
} finally {
try {
if(fos != null) {
fos.close() ;
fos = null ;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 输出文件,根据流输出
* @param stream OutputStream
*/
public void writeToStream(OutputStream stream) {
try {
workbook.write(stream) ;
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("文件输出异常!请检查.") ;
} finally {
try {
if(stream != null) {
stream.close() ;
stream = null ;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 初始化模板
*/
private void initTemplate() {
sheet = workbook.getSheetAt(0) ;
styles = new HashMap<Integer, CellStyle>() ;
initConfigData() ;
lastRowInex = sheet.getLastRowNum() ;
}
/**
* defaultStyles:获得默认样式(如果默认样式没有则使用开始样式)
* styles:获取自定义样式
*
*/
private void initConfigData() {
for(Row row : sheet) {
for(Cell cell : row) {
if(cell.getCellType() != Cell.CELL_TYPE_STRING) continue ;
String value = cell.getStringCellValue().trim() ;
//获取开始位置,初始化数据
if(TEMPLATE_NAME.equals(value)) {
initRowIndxe = cell.getRowIndex() ;
initColIndex = cell.getColumnIndex() ;
curRowIndex = initRowIndxe ;
curColIndex = initColIndex ;
defaultHeight = row.getHeightInPoints() ;
if(defaultStyle == null) defaultStyle = cell.getCellStyle() ;
}
//获取defaultStyles,无论如何,当有设置defaultStyles都设置为defaultStyles
if(DEFALULT_STYLE.equals(value)) defaultStyle = cell.getCellStyle() ;
//获取自定义样式的列
if(STYLE.equals(value)) {
styles.put(cell.getColumnIndex(), cell.getCellStyle()) ;
}
//获取样式所在的列
if(SERNUMS.equals(value)) serColIndex = cell.getColumnIndex() ;
}
}
}
/**
* 设置样式
* @param cell Cell
*/
private void setStyle(Cell cell) {
//当前列存在自定义样式时使用自定义样式,否则使用默认样式.
if(styles.containsKey(curColIndex)) {
cell.setCellStyle(styles.get(curColIndex)) ;
} else {
cell.setCellStyle(defaultStyle) ;
}
}
}
基本原理是获取模板样式,记录自定义样式所在列的列号和样式,然后根据列号输出样式.
样式例子:
@Test
public void testExcel() {
ExcelTemplate excel = ExcelTemplate.getInstance().readTemplatePath("D:/Project/MAVEN_ANT/Poi_Template/excel/lilys.xls") ;
excel.creatNewRow() ;
excel.createNewCol("aaa") ;
excel.createNewCol("111") ;
excel.createNewCol("111") ;
excel.createNewCol("111") ;
excel.creatNewRow() ;
excel.createNewCol("bbb") ;
excel.createNewCol("222") ;
excel.createNewCol("222") ;
excel.createNewCol("222") ;
excel.creatNewRow() ;
excel.createNewCol("ccc") ;
excel.createNewCol("333") ;
excel.createNewCol("333") ;
excel.createNewCol("333") ;
excel.creatNewRow() ;
excel.createNewCol("ddd") ;
excel.createNewCol("444") ;
excel.createNewCol("444") ;
excel.createNewCol("444") ;
excel.creatNewRow() ;
excel.createNewCol("eee") ;
excel.createNewCol("555") ;
excel.createNewCol("555") ;
excel.createNewCol("555") ;
Map<String, String> datas = new HashMap<String, String>() ;
datas.put("title", "拉斯维加斯") ;
datas.put("date", new Date().toString()) ;
datas.put("department", "百合科技人事部") ;
excel.replaceFind(datas) ;
excel.insertSer() ;
excel.writeToFile("D:/poi.xls") ;
}
下面是例子的源代码(Maven项目):