Java - Use odfdom library to create ods file

之前曾經提到利用JODconverter來進行xls檔案轉換至ods檔案,而在這邊主要是說明,如何利

odfdom library來讀取ods template file並且做基本的處理,同時也會提到style的用法,如

粗體、縮排等設定,如此一來即可建構出一基本的ods試算表。

使用的版本為:odfdom-java-0.8.7.jar

首先,載入一自訂的資料檔,如下:

資工系,男,21,小彬
經濟系,女,19,小花
建築系,男,23,小勇
國貿系,男,21,小金
中文系,女,20,小琪
歷史系,男,18,小強
財金系,女,24,小雯
畜產系,男,23,小維
哲學系,男,25,小茂
外文系,女,20,小琳

private List<Student> studentList;

public static void main(String[] args) {
  // TODO Auto-generated method stub
  new SimpleOds("menu.txt");
}
 
public SimpleOds(String file){
  loadStudentMenu(new File(file));
  OutputOdsReport();
}
 
public void loadStudentMenu(File f){
  studentList = new ArrayList<Student>();
  Random rmd = new Random();
  try (BufferedReader br = new BufferedReader(new FileReader(f))){
     String data = null;
     System.out.println("學生名單如下:");
     while((data = br.readLine()) != null){
        Student p = new Student(data);
        p.setScore(rmd.nextInt(100));
        System.out.println(p);
        studentList.add(p);
     }
  } catch (FileNotFoundException e) {
   // TODO Auto-generated catch block
   System.out.println("指定檔案不存在!!");
  } catch(IOException e){
   System.out.println("IOException");
  }
 }

這邊做的事情很單純,載入一txt檔案,並將各欄位的資料組成一Student Bean List。

緊接著,初始化讀入Ods樣板檔及相關建立ods file變數


SimpleDateFormat date_convert = new SimpleDateFormat("yyyyMMddHHmmss");
String inputFileName;
String outputFileName;
OdfSpreadsheetDocument outputDocument; //workbook
OdfContentDom contentDom; // the document object model for content.xml
OdfOfficeAutomaticStyles contentAutoStyles;
public void OutputOdsReport(){
  inputFileName = "students.ods";
  outputFileName = "student_"+date_convert.format(
             new java.sql.Date(System.currentTimeMillis()))+".ods";
  setupOutputDocument(inputFileName);
  if (outputDocument != null) {
     processInputDocument();
     saveOutputDocument();
  }   
}

public void setupOutputDocument(String inputFile) {
   try {
      //Creates an empty spreadsheet document.
      outputDocument = OdfSpreadsheetDocument.loadDocument(inputFile);
      contentDom = outputDocument.getContentDom();
      contentAutoStyles = contentDom.getOrCreateAutomaticStyles();
   } catch (Exception e) {
      System.err.println("Unable to create output file.");
      System.err.println(e.getMessage());
      outputDocument = null;
   }
}

outputDocument => 猶如Excel的workbook,可以取得特定的sheet及輸出一新的ods

contentAutoStyles => 取得當下cell的style element,此style element跟style設定有關,如

粗體、縮排、文字顏色...等,簡單來說每一個cell都會有一個style name,如果cell的style name

一樣的話,若該style name被設定也將影響到另一cell本身。

再來則是做set value to cell的動作,如下:
public void processInputDocument(){
   OdfTable sheet = outputDocument.getTableList().get(0); //取sheet1
   int startRow = 3;
   int indent = 0;
   boolean isBold = false;
   String color = null;
   for(int i = 0 ; i < studentList.size() ; i++){
      Student bean = studentList.get(i);
      indent = (bean.getSex().equals("女")) ? 2 : 1;
      isBold = (bean.getAge() > 20) ? true : false;
      color  = (bean.getScore() <= 60) ? "#FF0000" : null;
   
      setValue(bean.getUnit(), startRow, 0, sheet, 0, false, "center", "center", null);
      setValue(bean.getSex(),  startRow, 1, sheet, indent, false, "left", "center", null);
      setValue(bean.getAge(),  startRow, 2, sheet, 0, isBold, "center", "center", null);
      setValue(bean.getName(), startRow, 3, sheet, 0, false, "center", "center", null);
      setValue(bean.getScore(),startRow, 4, sheet, 0, false, "center", "center", color);
      startRow++;
   }
}

public void setValue(Object value, int row, int col, OdfTable sheet, Integer indentation, Boolean isBOLD, String va,String ha, String color) {
   row-=1;
   OdfTableCell cell = sheet.getCellByPosition(col, row);
        
   cell.setCellBackgroundColor(Color.WHITE);
        
   String styleName = cell.getStyleName();
        
   OdfStyle styleElement = contentAutoStyles.getStyle(styleName, OdfStyleFamily.TableCell);
        
   //水平排列
   if(va != null){
      cell.setHorizontalAlignment(va);
   }
   //垂直排列
   if(ha != null){
      cell.setVerticalAlignment(ha);
   }
   //粗體
   if(isBOLD != null && isBOLD.booleanValue()){
      setFontWeight(styleElement, "bold");
   }else{
      setFontWeight(styleElement, "");
   }
   //縮排
   if(indentation != null){
      setIndentation(styleElement, String.valueOf(0.353*indentation)+" cm");
   }
   //文字顏色
   if(color != null){
      setTextColor(styleElement, color);
   }else{
      setTextColor(styleElement, "#000000");
   }
   //set value     
   if(value instanceof java.lang.String || value instanceof java.lang.Integer){
      cell.setStringValue(String.valueOf(value));
   }else if(value instanceof java.lang.Double){
      cell.setDoubleValue(Double.parseDouble(""+value));
   }
        
   //System.out.println(isBOLD.booleanValue()+","+row+","+","+col+","+styleElement);
}

上面的設定值得注意的地方是,cell.setCellBackgroundColor(Color.WHITE);主要的目的

是針對各個cell產生其各自的style name(相當於ID),避免如該欄的各cell如果style name都

一樣的話,改變其一的設定會影響到其它欄,猶如牽一髮而動全身。

setValue method的各參數將指定該cell的一些設定,如下:

//粗體
void setFontWeight(OdfStyleBase style, String value) {  
    style.setProperty(OdfTextProperties.FontWeight, value);
    style.setProperty(OdfTextProperties.FontWeightAsian, value);
    style.setProperty(OdfTextProperties.FontWeightComplex, value);
}

//縮排
void setIndentation(OdfStyleBase style, String value) {  
    style.setProperty(OdfParagraphProperties.MarginLeft, value);
}

//文字顏色 
void setTextColor(OdfStyleBase style, String value) {
    style.setProperty(OdfTextProperties.Color, value);
}

最後,則是做輸出檔案的動作
public void saveOutputDocument(){
  try {
      outputDocument.save(outputFileName);
  } catch (Exception e) {
      System.err.println("Unable to save document.");
      System.err.println(e.getMessage());
  } finally{
      if(outputDocument != null)outputDocument.close();
  }
}

留言