JakartaPOI - Java meets Office
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
Seminarbericht: JakartaPOI – Java meets Office Fachhochschule Nordwestschweiz FHA University of Applied Sciences Aargau Autor: Strittmatter Reto r.strittmatter@stud.fh-aargau.ch Studiengang Informatik Vertiefung Enterprise Computing Dozent Prof. Dr. Dominik Gruntz Windisch, 7. Juli 2004
JakartaPOI Abstract Das JakartaPOI Projekt stellt mehrere freie in Java implementierte Bibliotheken zur Verfügung, mit denen Dokumente, welche in dem Microsoft proprietären „OLE-2 Compound Document“ Format gespeichert sind, gelesen und erstellt werden können. In diesem Format sind auch die MS Word und Excel Dokumente gespeichert. Dieser Seminarbericht soll einen Überblick über diese Bibliotheken geben und ihre Verwendung an einfachen Beispielen demonstrieren. Insbesondere soll der Verwendung von POI im Bereich Webservices Beachtung geschenkt werden. R. Strittmatter, FH-Aargau Seite 2/28
JakartaPOI Inhaltsverzeichnis 1 Wie kann man Office Dokumente mit Java bearbeiten..................................................... 4 2 Was ist JakartaPOI........................................................................................................... 4 3 Elemente von JakartaPOI................................................................................................. 5 3.1 POIFS – Implementation des OLE2 Compound Document Format ......................... 5 3.2 HSSF - Java API um MS Excel Dokumente anzusprechen....................................... 6 3.3 HWPF - Java API um MS Word Dokumente zu bearbeiten.......................................7 3.4 HPSF – Java API um Dokument Eigenschaften zu manipulieren..............................7 4 Einblick in das Arbeiten mit HSSF..................................................................................... 8 4.1 Elemente eines Excel Dokument............................................................................... 8 4.2 Erstellen eines einfachen Excel Dokument................................................................ 9 4.3 Lesen eines Excel Dokument................................................................................... 11 4.4 Weitere HSSF Aspekte im Detail............................................................................. 11 4.4.1 HSSF Cells....................................................................................................... 11 4.4.2 Zellen Formatierung.......................................................................................... 12 4.4.2.1 Ausrichtung Optionen.................................................................................... 13 4.4.2.2 Zellen Ränder................................................................................................ 14 4.4.2.3 Füllungen und Farben.................................................................................... 14 4.4.2.4 Arbeiten mit Schriften.................................................................................... 15 4.4.2.6 Zeichnen von Figuren.................................................................................... 17 4.4.2.7 Arbeiten mit Formeln..................................................................................... 18 5 JakartaPOI in Webanwendungen................................................................................... 19 6 Fazit................................................................................................................................. 21 A) Literaturverzeichnis und Quellenangaben..................................................................... 22 B) Servlet Quellcode.......................................................................................................... 23 C) POIFS Beispiel.............................................................................................................. 27 D) HPSF Beispiel............................................................................................................... 27 R. Strittmatter, FH-Aargau Seite 3/28
JakartaPOI Wie kann man Office Dokumente mit Java bearbeiten 1 Wie kann man Office Dokumente mit Java bearbeiten Um mit Java MS Office Dateien erzeugen und bearbeiten zu können, gibt es grundsätzlich zwei verschiedene Ansätze. Ein möglicher Ansatz wäre eine MS Office Anwendung fern zu steuern, dies geschieht mittels der COM/DCOM Schnittstelle. Jede MS Office Anwendung ist, wenn sie korrekt installiert wurde, gleichzeitig auch ein COM/DCOM Server. Während das Schreiben eines DCOM Client in Visual Basic oder C++ kein Problem darstellt, ist dies mit Java nicht ohne weiteres möglich. Der Grund weshalb das Ansprechen des DCOM Servers nicht so einfach realisierbar ist, liegt in der Plattformunabhängigkeit von Java. Als Lösung könnte man einen Client in einer nativen Programmiersprache schreiben, der dann über das Java Native Interface (JNI) in die Java Umgebung eingebunden wird. Dies ist eine komplexe Vorgehensweise mit mehreren Nachteilen. Zum einen ist das Java-Produkt dazu nicht mehr plattform- unabhängig, hat hohe Performance Einbussen, da eine Methodenaufruf über mehrere Schichten geht, und eine MS Office Anwendung wird bloss ferngesteuert, was bei einer Webapplikationsanwendung weitere Einschränkungen zur Folge hätte. Ein zweiter weit flexibler Ansatz ist die komplette Erzeugung eines MS Office Format direkt in Java. Mit anderen Worten, es wird eine MS Excel bzw. Word Dateien erzeugt, als ob diese von einer MS Office Anwendung stammen würde. Diesen Ansatz verfolgt das JakartaPOI Projekt, welches ich in diesem Seminarbericht vorstellen möchte. 2 Was ist JakartaPOI Das JakartaPOI Projekt besteht aus mehreren Java APIs, die es einer/em Entwickler/in erlauben, Dateien zu erstellen und zu bearbeiten, welche auf dem Microsoft proprietären Dateiformat „OLE-2 Compound Document Format“ beruhen. Alle MS Office Anwendungen ab der Version 95 bis XP benutzen dieses Datei Format, wenn auch in einer leicht abweichender Form. POI steht dabei für “Poor Obfuscation Implementation“ (Schlechte, verschleiernde Implementierung). Diesen abschätzigen Projektname haben die Entwickler gewählt, da sie finden, dass das Datei Format (OLE2CDF), welches die Office Komponenten benutzen, von Microsoft nicht richtig durchdacht worden ist. Diese Ansicht wiederspiegelt sich auch in der Namensgebung der einzelnen Teile des Projektes, auf die ich nun genauer eingehen möchte. R. Strittmatter, FH-Aargau Seite 4/28
JakartaPOI Elemente von JakartaPOI 3 Elemente von JakartaPOI Wie im vorherigen Kapitel bereits erwähnt, besteht das JakartaPOI Projekt aus mehreren Einzelprojekten. Diese sind unterschiedlich weit fortgeschritten in ihrer Entwicklung. Ich möchte im Folgenden auf jedes einzelne Projekt eingehen und die wichtigsten Aspekte ein wenig erläutern. 3.1 POIFS – Implementation des OLE2 Compound Document Format POIFS ist eine reine Java Implementation des „OLE 2 Compound Document Format“ (OLE2CDF). Eine Datei, die im OLE2CD Format abgespeichert ist, beinhaltet ein Dateisystem, welches aus verschachtelten Verzeichniseinträgen sowie normalen Einträgen, also Dateien besteht. Man kann sich das ganze auch gut als ein ZIP-Archive vorstellen. Mit der POIFS API können solche Dateien einfach gelesen und geschrieben werden. POIFS stellt die Grundfunktionen für das Arbeiten mit OLE2CDF Dateien zur Verfügung und wird von allen anderen POI Komponenten verwendet. Alle weiteren POI- Komponenten wie HSSF oder HWPF verstecken die POIFS API vor dem Benutzer, es wird mit ihnen auf einer abstrakteren Schicht gearbeitet. Es gibt aber Anwendungsfälle bei denen ein/e Entwickler/inn nicht darum herum kommt, direkt mit der POIFS API zu arbeiten. Darum möchte ich kurz eine grobe Übersicht über die Verwendung der POIFS API geben. Weitere Details wie man mit der POIFS API arbeitet, sind im Anhang unter „Weiterführende Links„ unter [1] zu finden. Ein OLE2CDF Datei kann mit der POIFS API auf zwei Arten gelesen werden. 1. Herkömmliches Lesen: Dabei wird die OLE2CDF Datei wie ein normales Dateisystem gelesen, man kann die Einträge in beliebiger Reihenfolge anspringen und lesen. Der grösste Nachteil dieser Methode besteht darin, dass sich alle Dateien/Einträge der Datei im Speicher befinden, egal, ob sie die Anwendung braucht oder nicht. R. Strittmatter, FH-Aargau Seite 5/28
JakartaPOI POIFS – Implementation des OLE2 Compound Document Format 2. Event gesteuertes Lesen: Diese Art zu lesen ist effizienter als das herkömmliche Lesen. Es wird das Reactor Pattern benutzt, um ein Dokument einzulesen (Vergleichbar mit einem SAX Parser bei einer XML Datei). Es reduziert den Speicherverbrauch einer Anwendung und ist schneller als das herkömmliche Lesen, da nur noch das gelesen wird, was auch wirklich gebraucht wird. Die Nachteile dieser Lesevariante liegen in der komplizierteren Handhabung, sowie der genauen Kenntnis im Vorfeld, was genau gelesen werden muss. Ausserdem hat man keine Kontrolle über die Reihenfolge wie ein Dokument eingelesen wird. Das Schreiben einer OLE2CDF Datei kann ebenfalls auf mehrere Arten geschehen. Man kann ein existierendes Dateisystem in den Speicher laden und modifizieren (Dateien hinzufügen, löschen oder umbenennen) und anschliessend abspeichern oder man kann eine neue leere OLE2CDF Datei kreieren und mit dieser weiter arbeiten. Als Beispiel für das Arbeiten mit dem POIFS möchte ich zeigen, wie man mit der POIFS API die Elemente eines OLE2CDF Filesystems auslesen kann. Der Quellcode dieses Beispiels ist im Anhang dieses Dokumentes unter C zu finden. 3.2 HSSF - Java API um MS Excel Dokumente anzusprechen HSSF ist ein API um Microsofts Excel'97 (-2002) Dateien (XLS) manipulieren zu können. Auch diese API ist in reinem Java implementiert und benutzt im Hintergrund das POIFS API. HSSF steht für „Horrible Spread Sheet Format“ was wiederum die Meinung der Entwickler über das Excel Format wiedergibt. Auf die Einzelheiten und die Verwendung der HSSF API wird im Laufe dieses Berichts näher eingegangen. R. Strittmatter, FH-Aargau Seite 6/28
JakartaPOI HWPF - Java API um MS Word Dokumente zu bearbeiten 3.3 HWPF - Java API um MS Word Dokumente zu bearbeiten HWPF ist eine Java – API, die es einer/em Entwickler/in erlaubt, MS Word Dokumente zu bearbeiten. Dieser Teil des POI Projektes steckt immer noch im frühen Anfangsstadium der Entwicklung und ist noch nicht so weit fortgeschritten, wie die des HSSF Teils. Ausser ein paar einfachen Beispielen im Entwickler-Zweig des Projektes und der JavaDoc Dokumentation der API findet man wenig Informationen wie mit HWPF gearbeitet werden soll. Dies wird sich sicherlich im Laufe der Entwicklung dieses Projektzweiges ändern und sollte deshalb von allen Interessierten mit Spannung verfolgt werden. Die frühe Entwicklungsphase des HWPF-Projektes nehme ich zum Anlass, an dieser Stelle nicht weiter darauf einzugehen. 3.4 HPSF – Java API um Dokument Eigenschaften zu manipulieren Microsoft Anwendungen ermöglichen es, dass ein Benutzer einem erstellten Dokument gewisse Eigenschaften wie Titel, Kategorie, etc. zuweisen kann. Die Anwendung selbst speichert den letzten Autor, das Erstellungsdatum und andere Informationen automatisch in der entsprechenden OLE2CDF Datei ab. Diese Eigenschaften werden in einem Eigenschaftenstream in der internen Datenstruktur der Datei abgelegt. Mit der HPSF API, (Horrible Property Set Streams API) welche als Grundlage die POIFS API benutzt, kann man auf diesen Eigenschaftstream der OLE2CDF Dateien zugreifen und diese Eigenschaften manipulieren. Dabei unterstützt HPSF OLE2 Eigenschaftstream im Allgemeinen und ist nicht limitiert auf die weiter oben beschriebenen MS Office Anwendungen. In diesem Abschnitt möchte ich aufzeigen, wie man die wichtigsten Eigenschaften eines Dokumentes lesen kann. Die Unterstützung, um die Eigenschaften schreiben zu können, ist zum Zeitpunkt der Erstellung dieses Seminarberichtes nur rudimentär vorhanden und wird daher nicht weiter verfolgt. Im Anhang D des Dokuments ist das Listing des Quellcode abgedruckt, der den SummaryInformation- Strom eines Dokumentes einliest und ein paar Eigenschafts- Informationen auf der Konsole ausgibt. Das Dokument wird mit der Event Methode eingelesen, welche im POIFS Teil schon kurz erwähnt wurde. R. Strittmatter, FH-Aargau Seite 7/28
JakartaPOI Einblick in das Arbeiten mit HSSF 4 Einblick in das Arbeiten mit HSSF Die HSSF API besteht aus den folgenden Hauptpaketen: Package Beschreibung org.apache.poi.hssf. Liefert eine abstrakte Sicht von gängigen Spreadsheet usermodel Elementen wie Workbook, Sheet, Row, Cell, Font, Cell Style, Color Palette, Data Format, etc. org.apache.poi.hssf.record Beinhaltet Klassen, welche eine binäre XLS Struktur repräsentieren. org.apache.poi.hssf.record. Beinhaltet Klassen, die es erlauben mehrere Records als aggregates einen Record zu bearbeiten. org.apache.poi.hssf.record. In diesem Paket sind die Klassen angesiedelt, welche es formula erlauben mit Formeln in einem Excel Dokument zu arbeiten. org.apache.poi.hssf. Event basierte API um HSSF Dateien zu lesen. eventusermodel org.apache.poi.hssf.dev Beinhaltet Beispiele und Werkzeuge um Excel Dateien zu erstellen und validieren. 4.1 Elemente eines Excel Dokument Aus der Sicht von HSSF ist ein Excel Dokument ein Workbook, welches ein oder mehrere Worksheets beinhaltet. Ein Worksheet besteht wiederum aus Reihen, welche mehrere Zellen beinhalten können. Zu den jeweiligen Zellen können verschiedene Anzeigeattribute und Formelfunktionen zugewiesen sein. Die folgende Graphik soll diesen Zusammenhang verdeutlichen. Workbook Worksheet 1 Worksheet ... Worksheet n Attributes Row (1...n) color width Cell (1...n) height ... R. Strittmatter, FH-Aargau Seite 8/28
JakartaPOI Erstellen eines einfachen Excel Dokument 4.2 Erstellen eines einfachen Excel Dokument Diese Schritte sind nötig, um ein einfaches Excel Dokument zu erstellen. 1. Erstellen eines HSSFWorkbook Objektes. 2. Erstellen eines HSSFWorksheet Objektes von dem HSSFWorkbook Objekt. Dies ist der einzige Weg, um eine Referenz auf ein Worksheet Objekt zu bekommen, da in Excel kein Worksheet ausserhalb eines Workbook existieren kann. 3. Analog zur Erstellung eines Woorksheets erhält man HSSFRow Objekte von einem Worksheet und HSSFCell Objekte von einem Row Objekt. 4. Um einen Header zu kreieren, muss man mehrere Zellen/Reihen zusammenfassen, dies ist möglich via dem org.apache.poi.hssf.util.Region Objektes. Die Nummerierung der Reihen und Zellen beginnt bei null. 5. Um Daten in eine Zelle einzufügen, verwendet man die HSSFCell Methode setCellValue. Zellen unterstützen alle Nativen Java Typen wie String, int, boolean, etc. Das API unterstützt zudem noch andere gängige Typen wie Date und Calendar. 6. Als letztes muss das Excel Dokument im physikalischen Dateisystem erstellt werden. Dazu wird ein OutputStream Objekt der HSSFWorkbook Methode write übergeben, welche dann das Dokument in den entsprechenden Stream schreibt. Danach muss der Stream unbedingt geschossen werden, da die HSSF API dies nicht automatisch macht. R. Strittmatter, FH-Aargau Seite 9/28
JakartaPOI Erstellen eines einfachen Excel Dokument Dieses „Hello Excel“ Beispiel soll die oben aufgeführten Schritte wiedergeben: // Schritt 1: HSSFWorkbook wb = new HSSFWorkbook(); // Schritt 2: HSSFSheet sheet = wb.createSheet("Hello"); // Schritt 3: HSSFRow headerRow = sheet.createRow(1); // Schritt 4: // Header von Reihe 2 bis 3 und Zellen 2 bis 11 // Region(RowFrom ,CellFrom ,RowTo ,CellTo ) Region reg = new Region(1 ,(short)1 , 2 ,(short)10 ); sheet.addMergedRegion(reg); HSSFCell headerCell = headerRow.createCell((short)1); // Schritt 5: headerCell.setCellValue( "Hallo Excel" ); // Schritt 6: FileOutputStream fileOut = new FileOutputStream ("HelloExcel.xls"); wb.write(fileOut); fileOut.close(); R. Strittmatter, FH-Aargau Seite 10/28
JakartaPOI Lesen eines Excel Dokument 4.3 Lesen eines Excel Dokument Das Einlesen eines Excel Dokumentes aus einer Datei ist genau so einfach wie das Erstellen. Als erstes muss ein POIFSFileSystem Objekt erzeugt werden und dieses dann als Konstruktorargument dem HSSFWorkbook Objekt mitgegeben werden. Mit Hilfe der HSSFWorbook Methode getSheetAt( int ) kann man nun auf die einzelnen Worksheet zugreifen. Die Nummerierung beginnt hier wie bei den Feldern ebenfalls bei null. POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(“wb.xls“)); HSSFWorkbook wb = new HSSFWorkbook( fs ); HSSFSheet sheet = wb.getSheetAt(0); 4.4 Weitere HSSF Aspekte im Detail Nach der kurzen Einführung wie man eine Excel Datei erstellt bzw. liest, möchte ich nun auf ein paar wichtige Aspekte von HSSF näher eingehen. Eine detailliertere Anleitung wie man mit der HSSF API arbeitet, ist im Anhang bei den Quellenangaben unter Punkt [2] zu finden. Ausserdem soll an dieser Stelle auf die JavaDoc [3] Dokumentation des Projektes verwiesen werden. 4.4.1 HSSF Cells Zellen können von einem der folgenden Typen sein: • CELL_TYPE_NUMERIC Diese Zellen dürfen nur Zahlen beinhalten. • CELL_TYPE_STRING Diese Zellen können nur Strings beinhalten keine Zahlen. • CELL_TYPE_BLANK Ein leere Zelle. • CELL_TYPE_BOOLEAN Diese Zellen können nur Ja(1)/Nein(0) beinhalten. • CELL_TYPE_ERROR • CELL_TYPE_FORMULA Diese Zellen beinhalten eine Zeichenkette, die aber als Formel interpretiert wird. (Das Gleichheitszeichen wird nicht benötigt) R. Strittmatter, FH-Aargau Seite 11/28
JakartaPOI Weitere HSSF Aspekte im Detail Der Zellentyp wird implizit gesetzt, wenn man der Zellen entsprechende Werte mittels der Methode setCellValue(...) zuweist. Bsp: cell.setCellValue( 1.1 ) weiss der Zelle automatisch den Typ „Numeric“ zu. Explizit kann man den Typ der Zelle auch mit der HSSFCell Methode setCellType ( HSSFCell.Celltype ) setzen, wobei Celltype einer der oberen Werte annehmen muss. Ist der Typ einer Zelle einmal gesetzt, kann man die Zelle mit Hilfe der entsprechenden typbezogenen Getter/Setter Methoden lesen bzw. Schreiben. cell.get/setBooleanCellValue() für Zellen vom Typ Boolean cell.get/setCellFormula() für Zellen vom Typ Formula cell.get/setErrorCellValue() für Zellen vom Typ Error cell.get/setNumericCellValue() für Zellen vom Typ Numeric cell.get/setStringCellValue() für Zellen vom Typ String Wird auf eine Zelle eine Getter/Setter Methode eines anderen Zellentyps aufgerufen, so wird eine Exception geworfen. 4.4.2 Zellen Formatierung Jeder einzelnen Zelle kann ein HSSFCellStyle Objekt zugewiesen werden. Die HSSFCellStyle Klasse legt Anzeigeattribute wie Farbe, Schrift, Höhe, Breite ,etc für die jeweilige Zelle fest. Für komplexere Attribute wie Schrift und Farbe bietet die HSSF API, die zusätzlichen Klassen HSSFFont und HSSFColor, welche die Arbeit ein wenig vereinfachen. Es ist zu beachten, dass man eine neuse HSSFCellStyle Objekt immer, von einem HSSFWorkbook Objekt mittels der Methode createCellSytle() kreieren sollte. R. Strittmatter, FH-Aargau Seite 12/28
JakartaPOI Weitere HSSF Aspekte im Detail 4.4.2.1 Ausrichtung Optionen Für die Ausrichtung des Textes bzw. Wertes einer Zelle stehen folgende Möglichkeiten zur Verfügung: HSSFCellStyle.ALIGN_CENTER HSSFCellStyle.ALIGN_CENTER_SELECTION HSSFCellStyle.ALIGN_FILL HSSFCellStyle.ALIGN_GENERAL HSSFCellStyle.ALIGN_JUSTIFY HSSFCellStyle.ALIGN_RIGHT HSSFCellStyle.ALIGN_LEFT Um einer Zelle einen Stil zuweisen zu können, muss man von einem Workbook Objekt ein Objekt von Typ HSSFCellStyle anfordern, dies geschieht mit dem Aufruf workbook.createStyle(). Das so erhaltene HSSFCellStyle Objekt kann man dann mit der Methode setAlignment( HSSFCellSytle.ALIGN_X ) einen Stil zuweisen. Hat man nun ein HSSFCellStyle Objekt nach Wunsch kreiert, kann man es mit der HSSFCell Methode setCellStyle(...) einer Zelle zuweisen. Einen Zellen-Text kann man auch vertikal ausrichten, dies ist mit der Methode setVerticalAlignment(...) eines HSSFCellSytle Objekt möglich. Auch für diese Methode sind statische Konstanten definiert, mit welchen man die Ausrichtung bestimmen kann (Bsp: HSSFCellStyle.VERTICAL_CENTER). HSSFCellStyle style = workbook.createCellStyle(); style.setAlignment(HSSFCellStyle.ALIGN_LEFT); style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); cell.setCellStyle(style); R. Strittmatter, FH-Aargau Seite 13/28
JakartaPOI Weitere HSSF Aspekte im Detail 4.4.2.2 Zellen Ränder Ähnlich wie das bei dem Ausrichtungsstil einer Zelle geschieht, können auch die Ränder einer Zelle durch ein HSSFCellStyle Objekt festgelegt werden. Dafür stellt die HSSFCellStyle Klasse die folgenden Methoden zur Verfügung. • setBorderBottom(...) • setBorderLeft(...) • setBorderRight(...) • setBorderTop(...) Auch hierfür sind in der HSSF-API Konstanten definiert, welche man als Parameter für die einzelnen Methoden setzen kann. Mit den Zuweisungs- Methoden setBorderXXXColor(...) kann man den einzelnen Rändern auch noch eine Farbe geben. 4.4.2.3 Füllungen und Farben Um einer Zelle eine Farbe zuzuweisen, müssen zwei Schritte gemacht werden, erstens muss einem HSSFCellStyle Objekt eine Farbe zugewiesen werden, dies geschieht mit setFillBackgroundColor(...) oder setFillForegroundColor(...), anschliessend muss jeweils noch ein Füllmuster mit setFillPatern(...) gesetzt werden. Die Werte der Füllmuster sind als statische Attribute in der Klasse HSSFCellStyle definiert, als Beispiel sollen hier SOLID_FOREGROUND, SPARSE_DOTS oder SQUARES dienen, weitere Attribute können aus der API Dokumentation des Projekts entnommen werden. Um die Farben zu definieren, gibt es im Paket ...hssf.util die Klasse HSSFColor, wo eine Palette von Farben schon vordefiniert ist. Die Folgenden paar Codezeilen sollen die Handhabung aufzeigen. HSSFCellStyle style = workbook.createCellStyle(); style.setFillForegroundColor( HSSFColor.RED.index ); style.setFillPatern( HSSFCellStyle.SOLID_FOREGROUND ); cell.setCellStyle( style ); R. Strittmatter, FH-Aargau Seite 14/28
JakartaPOI Weitere HSSF Aspekte im Detail 4.4.2.4 Arbeiten mit Schriften Um mit unterschiedlichen Schriften arbeiten zu können, haben die Entwickler ebenfalls eine spezielle Klasse HSSFFont zu Verfügung gestellt, welche bei der Arbeit mit den Schriften unterstützt soll. Als Beispiel soll die Schrift einer Zelle mit einer 14 Punkt Courier New Schrift mit Stil kursiv und fett versehen werden. HSSFFont font = workbook.createFont(); font.setFontHeightInPoints( (short) 14 ); font.setFontName( “Courier New“ ); font.setItalic(true); font.setBoldWight(HSSFFont.BOLDWEIGHT_BOLD ); //oder BOLDWEIGHT_NORMAL HSSFCellStyle style = workbook.createCellSytle(); style.setFont(font); cell.setText( “Font Text“ ); cell.setCellStyle(style); Einem Font kann man auch, wie wir das in dem letzten Kapitel gesehen haben, durch die Methode font.setColor(...) eine Farbe zuweisen. Allerdings muss man hier kein Füllmuster zuweisen. R. Strittmatter, FH-Aargau Seite 15/28
JakartaPOI Weitere HSSF Aspekte im Detail 4.4.2.5 Zellen verbinden Um zwei Zellen miteinander zu verbinden, wird aus dem Package ...hssf.util die Hilfsklasse Region (Achtung nicht HSSFRegion) verwendet. // Region(RowFrom, CellFrom , RowTo , CellTo ) Region reg = new Region(1 , (short) 1, 2 , (short)2 ); sheet.addMergedRegion( reg ); HSSFRow row = sheet.createRow(1); row.createCell((short)1).setCellValue( "Hallo Excel" ); // Dieser Zelltext ist von der Region verdeckt: row.createCell((short)2).setCellValue( "Hidden" ); In dem Beispiel wird von Reihe eins, Zelle eins bis Reihe zwei; Zelle zwei verbunden (die short Werte spezifizieren die Zeilennummern). Nicht zu vergessen ist hier, dass die Nummerierung der Zellen und Reihen bei null beginnt. Möchte man nun einen Wert in die definierte Region setzen, so muss dieser in die erste Zelle, welche aus der ersten Reihe, die die Region definiert, erstellt worden ist, gesetzt werden (also in die Reihe und Zelle oben links der definierten Region). Ansonsten wird der Wert von der definierten Region überdeckt. Das folgende Bild zeigt die verbundene Region welche mit dem vorhergehenden Code- Beispiel erzeugt wurde. R. Strittmatter, FH-Aargau Seite 16/28
JakartaPOI Weitere HSSF Aspekte im Detail 4.4.2.6 Zeichnen von Figuren POI unterstützt das Zeichnen von Figuren in einem Excel Dokument, die in einer hierarchischen Ordnung von Gruppen und Figuren organisiert sind. Das Element, auf dem alle Figuren gezeichnet werden, wird „Patriarch“ genannt. Der Patriarch ist nicht auf dem Excelsheet sichtbar und es kann pro Sheet nur einen Patriarchen geben. (Man kann sich den Patriarchen als Glasplatte über dem Dokument vorstellen, auf der gezeichnet wird.) Mit dem Aufruf der Methode createDrawingPatriarch() auf einem HSSFSheet Objekt wird ein neuer Patriarch erstellt. Falls schon ein anderer Patriarch vorhanden ist, werden alle Zeichnungsobjekte mit diesem gelöscht. Um Zeichnungsobjekte zu erstellen sind folgende Schritte notwendig: • Erstellen eines Patriarchen • Erstellen eines Ankers, um die Zeichnung auf dem Blatt zu positionieren • Informieren des Patriarchen, dass dieser ein Zeichnungobjekt erstellen soll. • Zuweisen eins Stils (line, oval, rectangle, etc) an das Zeichnungsobjekt • Setzen von weiteren Stil Eigenschaften für die Figur. HSSFPatriarch patriarch = sheet_mita.createDrawingPatriarch(); HSSFClientAnchor a = new HSSFClientAnchor(0, 100, 0, 100, (short)1, 5, (short)6, 5 ); HSSFSimpleShape shape = patriarch.createSimpleShape(a); shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE); Ein HSSFClientAnchor Objekt definiert ein Rechteck, in dem eine Figur platziert und verankert werden kann. Dem Konstruktor werden dabei folgende Werte übergeben. HSSFClientAnchor( x1, y1, x2, y2, col1, row1, col2, row2 ) • col1, row1 : Zelle oben links • col2, row2 : Zelle unten rechts • x1, y1 : Offset von der rechten oberen Zellenecke aus (Für die Zelle oben links) • x2, y2 : Offset von der rechten oberen Zellenecke aus (Für die Zelle unten rechts) R. Strittmatter, FH-Aargau Seite 17/28
JakartaPOI Weitere HSSF Aspekte im Detail 4.4.2.7 Arbeiten mit Formeln Das HSSF Projekt ist bestrebt, eine möglichst vollständige Formel Unterstützung nachzubilden. Bis jetzt werden folgende Features unterstützt (Auszug der wichtigsten Punkte). • Zellen Referenzen • Zeichenketten, Integer und Fliesskommazahlen Literale • Relative und absolute Referenzen • Arithmetische und logische Operationen • Formeln Rückgabewerte (Nummern oder Zeichenketten) Formeln kann man einer Zelle mit der Methode setCellFormula( “formelString“ ) zuweisen oder mit dem Pendant getCellFormula() abfragen. Die übergebene Formelzeichenkette wird von einem Parser in Token zerlegt welche nach der umgekehrt polnischen Notation gespeichert, werden. Diese Notation ist nämlich die Art, wie MS Excel die Formeln zur Weiterverarbeitung abspeichert. String formel = "SUM(E7:E10)"; cell.setCellFormula(formel); R. Strittmatter, FH-Aargau Seite 18/28
JakartaPOI JakartaPOI in Webanwendungen 5 JakartaPOI in Webanwendungen Für das Versenden von Daten an den Client von einer Webanwendung aus, werden Formate benötigt, welche die gängigsten Applikationen die in der Industrie eingesetzt werden, verarbeiten können. Zu diesen Anwendungen gehören ohne Zweifel die MS Office Produkte Word und Excel. Um eine Daten im Excel- Format an den Client zu senden, gibt es zwei verschiedenen Möglichkeiten. Man könnte dem Client lediglich eine CSV-Datei (Comma Separated Value File Format) oder eine HTML-Tabelle senden. Durch das Setzen des Dokumententyps application/vnd.ms-excel im HTTP Response Header wird der Browser vom Server beauftragt, diese Daten mit MS Excel einzulesen und zu verarbeiten. Excel ist in der Lage, das erhaltene Format zu erkennen und in sein eigenes zu konvertieren. Wird eine HTML Tabelle gesendet, übernimmt Excel sogar die Zellengrössen und Farben. Ein Nachteil dieser Variante ist, dass nicht davon ausgegangen werden kann, dass auf allen Client-Systemen MS Excel installiert ist. Darum eignet sich die zweite Variante besser, bei der auf dem Server eine Excel Datei erzeugt und diese mittels Bytestrom an den Client gesendet wird. (Der Dokumententyp im HTTP Header muss auch hier auf application/vnd.ms-excel gesetzt werden.) Denn es kann davon ausgegangen werden, dass die meisten professionellen Anwendungen auf dem Markt eine korrekt erstellten Excel Datei importieren können und somit in der Lage sind, die Daten weiter zu verarbeiten. Dies ist mit CSV-Dateien oder HTML Tabellen nicht gewährleistet. Also ein guter Grund um mit dem JakartaPOI Projekt in Java Anwendungen zu arbeiten. In meinem Servlet Beispiel (der Quellcode ist im Anhang zu finden), soll eine einfache Excel Datei eingelesen werden, die Daten sollen mittels der HSSF API neu formatiert und als neue Excel Datei an den Client gesendet werden. Dabei sollen ein paar der im HSSF Teil präsentierte Aspekte genutzt werden. Hat man das Excel Dokument mittels HSSF erstellt und wunschgemäss formatiert im Speicher, hat man aus einer Webanwendung wiederum zwei Möglichkeiten, es dem Client verfügbar zumachen. R. Strittmatter, FH-Aargau Seite 19/28
JakartaPOI JakartaPOI in Webanwendungen Man könnte das Dokument mittels einem FileOutputStream in eine temporäre Datei schreiben und einen Link an den Client schicken, unter dem er die Datei abholen kann. Dies bringt allerdings den Nachteil mit, dass nicht mehr gebrauchte Dateien von einem Dienst regelmässig gelöscht werden müssen, zudem kann dies ein Sicherheitsrisiko bedeuten, da entsprechende Lese-Rechte bei den einzelnen Dateien gesetzt sein müssen, was leider nicht so trivial ist. Die bessere Alternative ist den Outputstream des HSSFWorkbook Objektes direkt mittels dem HttpServletResponse an Client zu senden, hierzu muss folgenden Punkten Beachtung geschenkt werden. • Als Dokumenttyp im HTTP Header muss application/vnd.ms-excel gesetzt sein. • Des weiteren ist zu beachten, dass bei einem Client der zwei generierte Dokumente gleichzeitig bearbeiten möchte, die Dateinamen unterschiedlich sein müssen, da Excel zwei Dateien mit gleichem Namen nicht gleichzeitig öffnen kann. Ein eindeutiger Dateiname kann im Servlet Response Header durch die Methode setHeader("Content-Disposition", "filename=" + filename) gesetzt werden. • Wie aus den Newsgroups zum Thema POI zu erfahren ist, ist das Arbeiten mit POI auf dem Server sehr Rechen- und Speicherintensiv. Mann sollte daher versuchen, die Grösse der Dokumente, die zu generieren sind, einzuschränken. Anregungen zur Performance- Optimierung sind in [6] zu finden. R. Strittmatter, FH-Aargau Seite 20/28
JakartaPOI Fazit 6 Fazit Das Jakarta POI ist sicherlich ein sehr ambitioniertes Projekt, auf das viele Entwickler/innen in der Java Welt, welche ihre Daten auf irgend eine Weise für die Microsoft Office Tools zur Verfügung stellen wollen, gewartet haben. Dies zeigt sich ebenfalls darin, dass die POI APIs in andere Projekten wie dem Reporting Projekt JasperReports oder dem Cocoon Projekt , für das es ebenfalls HSSF Serializer gibt, verwendet werden um MS Excel Dokumente generieren zu können. Obwohl noch nicht alle Subprojekte von POI reif genug für die kommerzielle Entwicklung sind, lohnt sich ein Blick insbesondere auf HSSF trotzdem. Ebenfalls sollte man die weitere Entwicklung der andere Teile im Auge behalten, denn die Entwickler arbeiten ständig daran, ihre Projekte zu verbessern und weiter zu treiben. Besonders wird in der letzten Zeit intensiv daran gearbeitet, das Performance und Speicherverbrauch-Problem von POI zu minimieren. R. Strittmatter, FH-Aargau Seite 21/28
JakartaPOI Literaturverzeichnis und Quellenangaben A) Literaturverzeichnis und Quellenangaben [1] How To Use the POIFS APIs: http://jakarta.apache.org/poi/poifs/how-to.html Geprüft im Mai 2004 [2] Busy Developers Guide: http://jakarta.apache.org/poi/hssf/quick-guide.html Geprüft im Mai 2004 [3] JakartaPOI Project Page: http://jakarta.apache.org/poi/index.html Geprüft im Mai 2004 [4] Read and Write MS Excel Spreadsheets using Jakarta POI, von Shantosh Shanbhag: http://www.ociweb.com/jnbMar2004.html Geprüft im Mai 2004 [5] Reading and Writing Excel Files with POI von A. Sengupta, A. Oliver and R. Klute: http://www.onjava.com/pub/a/onjava/2003/04/16/poi_excel.html Geprüft im Mai 2004 [6] POI Performance Tuning Examples: http://www.codebits.com Geprüft im Mai 2004 [7] It's POI-fect von Tony Sintes: http://javaworld.com/javaga/2002-05/01-ga-0503-excel3_p.html Geprüft im Mai 2004 [8] Learn to Read and Write Microsoft Excel Documents with Jakarta's POI von Samudra Gupta http://www.devx.com/Java/Article/17301 Geprüft im Mai 2004 [9] Java Magazin Artikel - Java meets Office von Bernhard Scherm und Jürgen Stöckel R. Strittmatter, FH-Aargau Seite 22/28
JakartaPOI Servlet Quellcode B) Servlet Quellcode Dieses Servlet liest Daten aus einer Excel Datei ein und stellt diese in einem neuen, durch HSSF generiertem Excel Dokument dar. Dieses Dokument wird per Stream an den Browser gesendet. import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Collection; import java.util.LinkedList; import java.util.Iterator; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFClientAnchor; import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFPatriarch; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSimpleShape; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.Region; public class HSSFServlet extends HttpServlet { private String inputFileName = null; public void init( ServletConfig config ) throws ServletException { super.init(config); inputFileName = "Servlet_Input.xls"; } public void destroy() {} protected void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { this.processRequest(req,resp); } protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { this.processRequest(req,resp); } R. Strittmatter, FH-Aargau Seite 23/28
JakartaPOI Servlet Quellcode protected void processRequest( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { String filename = "newExcel.xls"; resp.setContentType("application/vnd.ms-excel"); resp.setHeader("Content-Disposition", "filename=" + filename); OutputStream out = resp.getOutputStream(); generateExcelFile(out); out.close(); } private void generateExcelFile( OutputStream out ) throws IOException { Collection mbCol = this.readExcelFile(); // Erstelle eine neue Arbeitsmappe mit einem Sheet: HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet_mita = workbook.createSheet("Neue Mitarbeiter Liste"); // Setze einen Titel: Region regTitel = new Region( 0, (short) 0, 1, (short) 3); sheet_mita.addMergedRegion(regTitel); HSSFCell titel = sheet_mita.createRow(0).createCell((short)0); titel.setCellValue("HSSF Generierte Mitarbeiter Liste"); HSSFCellStyle titleStyle = workbook.createCellStyle(); titleStyle.setAlignment(HSSFCellStyle.ALIGN_LEFT); titleStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); HSSFFont titleFont = workbook.createFont(); titleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); titleFont.setFontHeightInPoints((short)16); titleFont.setFontName("Times New Roman"); titleStyle.setFont(titleFont); titel.setCellStyle(titleStyle); // Setze eine Kopfzeile: HSSFFont headFont = workbook.createFont(); HSSFCellStyle headStyle = workbook.createCellStyle(); HSSFRow headRow = sheet_mita.createRow(4); headRow.setHeightInPoints(25); sheet_mita.setColumnWidth((short)1, (short)4000 ); sheet_mita.setColumnWidth((short)2, (short)4000 ); sheet_mita.setColumnWidth((short)3, (short)3500 ); headStyle.setFillForegroundColor( HSSFColor.PALE_BLUE.index ); headStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); headStyle.setBorderBottom(HSSFCellStyle.BORDER_MEDIUM); headStyle.setBorderLeft(HSSFCellStyle.BORDER_HAIR); headStyle.setBorderRight(HSSFCellStyle.BORDER_HAIR); headStyle.setBorderTop(HSSFCellStyle.BORDER_HAIR); headFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); R. Strittmatter, FH-Aargau Seite 24/28
JakartaPOI Servlet Quellcode headStyle.setFont(headFont); headRow.createCell((short)1).setCellValue("Name"); headRow.createCell((short)2).setCellValue("Vorname"); headRow.createCell((short)3).setCellValue("Geburtsdatum"); headRow.createCell((short)4).setCellValue("Gehalt"); headRow.createCell((short)5).setCellValue("Abteilung"); for(int i = 1; i < 6; i++ ) headRow.getCell((short)i).setCellStyle(headStyle); // Daten aus Bean einfügen: Iterator iter = mbCol.iterator(); int startRow = headRow.getRowNum() + 2; while( iter.hasNext() ) { MitarbeiterBean mb = (MitarbeiterBean)iter.next(); HSSFRow row = sheet_mita.createRow(startRow); row.createCell((short)1).setCellValue( mb.getName() ); row.createCell((short)2).setCellValue( mb.getVorname() ); row.createCell((short)3).setCellValue( mb.getGebDate() ); row.createCell((short)4).setCellValue( mb.getGehalt() ); row.createCell((short)5).setCellValue( mb.getAbtNr() ); startRow++; } // Zeichne eine Line: HSSFPatriarch patriarch = sheet_mita.createDrawingPatriarch(); HSSFClientAnchor a = new HSSFClientAnchor(0, 100, 0, 100, (short)1, startRow, (short)6, startRow ); HSSFSimpleShape shape = patriarch.createSimpleShape(a); shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE); // Gesamt Summe der Gehälter berechnen: sheet_mita.createRow(startRow+1).createCell((short)4).setCellValue( "Gesammt" ); String formel = "SUMME(E7:E" + (startRow) + ")"; sheet_mita.createRow(startRow+2).createCell((short)4).setCellFormula(formel); workbook.write(out); } private Collection readExcelFile() throws IOException{ Collection col = new LinkedList(); POIFSFileSystem fs = new POIFSFileSystem( new FileInputStream(this.inputFileName)); HSSFWorkbook wb = new HSSFWorkbook( fs ); HSSFSheet sheet = wb.getSheet("Mitarbeiter"); int lastRowNumber = sheet.getLastRowNum(); int headerRowNumber = sheet.getFirstRowNum(); short headerFristCellNumber = sheet.getRow(headerRowNumber).getFirstCellNum(); short headerLastCellnumber = sheet.getRow(headerRowNumber).getLastCellNum(); R. Strittmatter, FH-Aargau Seite 25/28
JakartaPOI Servlet Quellcode System.out.println( "HeaderRow :" + headerRowNumber ); System.out.println( "HeaderFirsCell :" + headerFristCellNumber ); System.out.println( "HeaderLastCell :" + headerLastCellnumber ); System.out.println( "LastRow :" + lastRowNumber ); // Lese die einzelnen Zeilen ein. (Achtung: Zellen Mapping auf Bean muss stimmen.) // Erste Zeile wird als Header betrachtet und nicht eingelesen. try { for( int i = 1; i 0 && !(sheet.getRow(i).getPhysicalNumberOfCells() < 5 )) { MitarbeiterBean mbean = new MitarbeiterBean(); mbean.setName ( sheet.getRow(i).getCell((short) 0). getStringCellValue() ); mbean.setVorname( sheet.getRow(i).getCell((short) 1). getStringCellValue() ); mbean.setGebDate( sheet.getRow(i).getCell((short) 2). getDateCellValue() ); mbean.setAbtNr ( (int) sheet.getRow(i).getCell((short) 3). getNumericCellValue() ); mbean.setGehalt ( sheet.getRow(i).getCell((short) 4). getNumericCellValue() ); col.add(mbean); } // else skip the row -> it's empty } }catch(Exception e){ System.err.println("Read-Error" + e.getMessage()); } return col; } public String getServeltInfo() { return "HSSF Servlet Example"; } } R. Strittmatter, FH-Aargau Seite 26/28
JakartaPOI POIFS Beispiel C) POIFS Beispiel Listing des Quellcodes der die Verzeichnisstruktur einer OLE2CDF Datei ausgibt und falls ein Excel Dokument übergeben wird, dessen Workbook-Stream anzeigt. import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import org.apache.poi.poifs.filesystem.DirectoryEntry; import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.DocumentInputStream; import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.poifs.filesystem.POIFSFileSystem; public class POIFSBeispiel { public void run( String filename ) throws IOException { InputStream is = new FileInputStream( filename ); POIFSFileSystem fs = new POIFSFileSystem( new BufferedInputStream( is ) ); DirectoryEntry dirRoot = fs.getRoot(); listDir( dirRoot, 0 ); System.out.println("\n\n-------------Workbook Stream--------------------"); // Versuche den Workbook-Stream auf der Konsole auszugeben: // Nur bei MS Excel Dokumenten möglich. try { DocumentEntry doc = (DocumentEntry)dirRoot.getEntry("Workbook"); DocumentInputStream dis = new DocumentInputStream( doc ); byte[] buffer = new byte[1024]; while( dis.read(buffer) > 0 ) { System.out.write(buffer); } dis.close(); }catch( FileNotFoundException e ) { System.err.println("File has no workbook entry."); } System.out.flush(); is.close(); } private void listDir( DirectoryEntry dir, int level ){ Iterator iter = dir.getEntries(); while( iter.hasNext() ) { Entry entry = (Entry) iter.next(); if( entry.isDirectoryEntry() ) { // DirectoryEntry listDir( (DirectoryEntry) entry, level + 1); } else { // DocumentEntry for( int i = 0; i < level; i++ ) System.out.print("\t"); System.out.println(entry.getName()); } } } } R. Strittmatter, FH-Aargau Seite 27/28
JakartaPOI HPSF Beispiel D)HPSF Beispiel Im Folgenden ist der Quelltext des Beispiel wiedergegeben, mit dem die SummaryInformation Eigenschaften einer OLE2CDF Datei ausgeben kann. import java.io.FileInputStream; import java.io.IOException; import org.apache.poi.hpsf.PropertySetFactory; import org.apache.poi.hpsf.SummaryInformation; import org.apache.poi.poifs.eventfilesystem.POIFSReader; import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent; import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener; public class HPSFBeispiel implements POIFSReaderListener { public void processPOIFSReaderEvent(POIFSReaderEvent event) { SummaryInformation si = null; try { si = (SummaryInformation)PropertySetFactory.create( event.getStream() ); } catch ( Exception e) { throw new RuntimeException( "Property set stream \"" + event.getPath() + event.getName() + "\": " + e ); } System.out.println("Liste der SummaryInformation:"); System.out.println("-----------------------------"); System.out.println(""); System.out.println("ApplicationName:\t" + si.getApplicationName() ); System.out.println("Author :\t" + si.getAuthor() ); System.out.println("LastAuthor :\t" + si.getLastAuthor() ); System.out.println("LastSaveDate :\t" + si.getLastSaveDateTime() ); System.out.println("PageCount :\t" + si.getPageCount() ); System.out.println("Titel :\t" + si.getTitle() ); System.out.println("LastPrinted :\t" + si.getLastPrinted() ); System.out.flush(); } public static void main(String[] args) throws IOException { String filename = args[0]; // So wird mit der Event-Methode eine Datei eingelesen // \005 im unten übergebenen String ist das Mapping // auf das Zeichen mit dem Dezimalwert von 5 POIFSReader reader = new POIFSReader(); reader.registerListener( new HPSFBeispiel(), "\005SummaryInformation" ); reader.read( new FileInputStream(filename) ); } } R. Strittmatter, FH-Aargau Seite 28/28
Sie können auch lesen