[作者:[email protected]]-謝絕轉載
POI VERSION 3.0.2 Final(下載地址www.apache.org)
在web開發當中,經常用pio組件實現操作excel文件的功能:創建工作薄,工作表,將數據庫表數據導出到excel文件或者從excel文件導入到當前web項目的數據庫.那麼,如何用pio方便實用地生成一個excel錄入模板呢?
b/s結構的系統要求用戶端具備上網條件.可現實環境往往導致用戶暫時不具備上網條件,這樣一來,用excel事先生成一個錄入模板就顯得尤爲重要了.
首先,用excel製作錄入模板有以下幾個好處:
1.excel環境已經相當普遍,用戶熟悉操作;
2.用excel輸入數據不需要再安裝部署其他軟件,符合瘦客戶端的設計理念;
3.移植性強.
錄入模板的製作要求:
1.生成基本的行列表格模式:
用戶在輸入數據時,模板要提供一些數據項,供其直觀地輸入.比如:姓名,性別,住址等.這些條目是靈活的,要求動態生成.
2.生成含有下拉列表框的輸入模式:
有一些含有數據字典的項目,如:民族,政治面貌等.並且這些數據項目是靈活的,系統要動態生成.
3.具體佈局樣式先暫時不考慮
在生成下拉列表框時,有兩個方案:
1)寫一個動態生成錄入界面的vba函數,存入固定的模板文件;
web服務端在生成exel文件之前,將此含有vba代碼的模板文件複製重命名.再用pio功能打開此文件,將基本輸入項目從描述系統表的結構表信息中讀出,動態寫入excel"錄入"sheet的單元格;同時將當前待錄入項目的數據字典項目寫入單獨的"代碼"sheet當中.用戶在實際使用當中,啓動此excel文件,vba自動運行並根據事先寫入單元格的數據生成錄入界面(一些文本框,下拉列表combobox等)
2)不使用vba,直接利用"數據有效性"功能實現基本的下拉列表輸入功能.
分析:第1)種方案,較複雜,並且用戶在實際使用當中可能遭遇"屏蔽宏"功能的情形出現,不易維護;
第2)種方案,較簡單,但通用性強,因爲"數據有效性"是excel的基本功能,所以不用運行宏代碼.
結論:決定先執行第2)種方案,時機成熟再試探第1)種方案!
步驟:先建立一個生成excel字節流的類,再建立一個action類.
示例代碼:
package com.mycom.server.excel;
import java.io.ByteArrayOutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.hssf.util.HSSFDataValidation;
public class ExcelCreate {
private static Logger log = Logger.getLogger(ExcelCreate.class.getName());
//數據位置參數
private final int startNameRow=7; //待錄入字段名稱開始行
private final short startTitleNameRow=4;
private final int startTagRow =5; //標誌開始行
private final int startNameCol=3; //名稱開始列(也是標誌開始列)
//工作薄名稱
private final String SHEET_DATA_NAME="錄入";
private HSSFWorkbook excel_wbook = null; //工作薄
private HSSFSheet sheet_data = null; //錄入sheet
//Excel 列名字母
private String[] englishChar ={"A","B","C","D","E","F",
"G","H","I","J","K","L",
"M","N","O","P","Q","R",
"S","T","U","V","W","X",
"Y","Z"};
private String setupColumnName="A";//表示數據有效性來源的excel行列字符名稱
private static ExcelCreate instance = null;
private ExcelCreate(){
}
public static synchronized ExcelCreate getInstance() {
if (instance == null){
instance = new ExcelCreate();
}
return instance;
}
/**
* 根據傳入的XtField列表對象,動態地建立一個可供錄入數據的excel字節輸出流
* @return
* @throws Exception
*/
public ByteArrayOutputStream ExcelMake(String strTableChineseName,List curFields,Map<String,List> mapVocabulary)throws Exception{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try{
//創建工作薄
excel_wbook = new HSSFWorkbook();
//創建工作表sheet
sheet_data = excel_wbook.createSheet(SHEET_DATA_NAME);
HSSFRow row =null; //excel一般行(普通行)對象
HSSFRow row_setup=null; //excel代碼設置行對象
HSSFDataValidation data_validation=null;//數據有效性對象
row=sheet_data.createRow((short)startNameRow-1);//先建立一個普通行
...
...
boolean isColfull=false;
short FieldColumncount=startNameCol-1; //數據項開始列
short setupColumn=(short)(startNameCol-1+curFields.size()+6); //代碼存放列開始數
short setupRow=startNameRow-1; //代碼存放行開始數
short tmpDivcol=0; //列數整除後的商數
short tmpModcol=0; //列數整除後的餘數
//開始寫標誌信息以及中文名稱
...
...
row_setup=sheet_data.createRow((short)(startTagRow-1));
cell =row_setup.createCell((short)(startNameCol-1));//寫入表標誌
createCell(cell,curTag[0]);
//開始寫字段標題
List curDMBeanList=null;//存放代碼對象列表
Iterator it=curFields.iterator();
//準備格式
HSSFFont fieldTitlefont = excel_wbook.createFont();
fieldTitlefont.setFontHeightInPoints((short) 10); //字體高度
fieldTitlefont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); //寬度
HSSFCellStyle fieldTitlecellStyle = excel_wbook.createCellStyle();
fieldTitlecellStyle.setFont(fieldTitlefont);
fieldTitlecellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //邊框
fieldTitlecellStyle.setBottomBorderColor(HSSFColor.BLACK.index);
... ...
while (it.hasNext()){
curXtField=(XtField)it.next();
cell =row.createCell((short)FieldColumncount);
createCell(cell,curXtField.getFTitle());
cell.setCellStyle(fieldTitlecellStyle);
//如果當前數據字段是代碼項
if (curXtField.getFType().equals(VOCABULARY_TAG.toString())
&&curXtField.getCName().toString()!=null){
setupRow=startNameRow-1;
curDMBeanList=mapVocabulary.get(curXtField.getCName());
if (curDMBeanList==null){
setupColumn++;
continue;
}
Iterator itV=curDMBeanList.iterator();
//寫入代碼數據
while(itV.hasNext()){
curDMObject=(DMBean)itV.next();
row_setup=sheet_data.createRow((short)setupRow);
cell_setup = row_setup.createCell((short)setupColumn);
createCell(cell_setup,curDMObject.getTitle());
//設置當前列的數據有效性,讀取列就是sheet_setup裏的對應列,起始行到末尾行
setupRow++;
}
//最大列數
if ( setupColumn>=230){
isColfull=true;
break;
}
//處理字母
...
...
//設置 數據有效性
log.info("Excel column for vocabulary: "+setupColumnName);
data_validation = SetDataValidation("$"+setupColumnName+
"$"+(startNameRow)+":$"+setupColumnName+"$"+setupRow+"",
(short)(startNameRow),(short)FieldColumncount,
(short)300,(short)FieldColumncount);
//指定第幾列默認300行,都設置爲含有下拉列表的格式
// "$B$1:$B$3"是excel公式的寫法,表示第2列第1行到第3行是下拉列表的輸入來源,
// 後面的四個short參數分別是設置該有效性格式的目標單元格.
//加入數據有效性到當前sheet對象
sheet_data.addValidationData(data_validation) ;
...
....
setupColumn++;
}// if 結束代碼數據寫入
FieldColumncount++;
}// while
//超過最大列數 230
if (isColfull){
return null;
}
excel_wbook.write(baos);
baos.close();
log.info("Excel file bytesarray ok!");
}catch(Exception re){
log.error(re.getStackTrace());
throw re;
}
return baos;
}
/**[作者:[email protected]]-謝絕轉載
* 設置待產生下拉列表框的有效 cell範圍:行,列---行,列
* @param strFormula example= "$B$1:$B$2"; 下拉框數據來源 ->從第幾列幾行到 第幾列幾行
* @param firstRow
* @param firstCol
* @param endRow
* @param endCol
* @return HSSFDataValidation對象
*/
private HSSFDataValidation SetDataValidation(String strFormula,short firstRow,short firstCol,short endRow,short endCol)
{
HSSFDataValidation data_validation = new HSSFDataValidation((short)
(firstRow),(short)firstCol,(short)(endRow),(short)endCol);
data_validation.setDataValidationType
(HSSFDataValidation.DATA_TYPE_LIST);
data_validation.setFirstFormula(strFormula);
data_validation.setSecondFormula(null);
data_validation.setExplicitListFormula(true);
data_validation.setSurppressDropDownArrow(false);
data_validation.setEmptyCellAllowed(false);
data_validation.setShowPromptBox(false);
data_validation.createErrorBox("Invalidate!", "please input again!");
data_validation.createPromptBox("Hi!", "You can select one");
return data_validation;
}
private void createCell(HSSFCell cell,String value){
if(value == null){
value = "";
}
cell.setCellValue(new HSSFRichTextString(value));
}
}
生成後的效果圖:
注意:XtField
DMBean分別是自定義對象,與本文無關
action類代碼:略