Eingangsbeispiel

Werbung
Eingangsbeispiel - Dokumentation
Table of contents
1
Dokumentation im Code und JavaDoc.............................................................................. 2
2
Persistence Layer............................................................................................................... 2
3
2.1
Lesende Operation - getStudent(long id)...................................................................... 2
2.2
Schreibende Operation - addStudent............................................................................. 3
2.3
Referenzen.....................................................................................................................4
Presentation Layer..............................................................................................................4
3.1
ExportComboModel...................................................................................................... 5
3.2
StudentenTableModel....................................................................................................6
3.3
Graphical User Interface (View)................................................................................... 6
3.4
Referenzen.....................................................................................................................9
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Eingangsbeispiel - Dokumentation
1. Dokumentation im Code und JavaDoc
Das Beispiel ist nach den Konventionen von JavaDoc dokumentiert. Für jedes Package, jede
Klasse und jede Funktion gibt es eine Beschreibung. Mit dem Ant-Task javadoc wird aus
diesen Beschreibungen eine HTML-Version erstellt. Sie befindet sich in diesem Beispiel im
Unterverzeichnis doc/api/ und kann mit jedem Browser gelesen werden.
Zusätzlich zu den Informationen für die JavaDoc enthält der SourceCode Kommentare, um
die Verständlichkeit des Codes zu erhöhen.
2. Persistence Layer
Als Persistenzebene (= Persistence layer) bezeichnet man jenen Teil des Programms, der für
die dauerhafte Speicherung der Daten zuständig ist. Bei der objektorientierten Entwicklung
werden meist ganze Objekte in die Datenbank gespeichert und wieder aus dieser gelesen.
Um von der verwendeten Datenbank möglichst unabhängig zu sein, verwendet man
sogenannte Data Access Objects (kurz DAO). Ein DAO stellt Funktionen zur Verfügung, mit
denen einzelne Objekte in die Datenbank geschrieben und aus der Datenbank gelesen werden
können. Das DAO kümmert sich dabei um den Aufbau einer Verbindung zur Datenbank, das
Senden der Befehle, empfangen der Daten usw.
Da die verbreitesten Datenbanken relationale Datenbanken sind, die mit Tabellen arbeiten,
müssen die Datenfelder der Objekte auf eine oder mehrere Tabellen und Tabellenspalten
zugeordnet werden. Diese Zuordnung nennt man Mapping. Auch das Mapping gehört zur
Aufgabe eines DAOs.
Das Basisbeispiel arbeitet mit einem sehr einfachen DAO, das fixe SQL Statements enthält,
diese befüllt und an die Datenbank sendet.
2.1. Lesende Operation - getStudent(long id)
Die Funktion getStudent(long id) liefert eine Instanz von Student, das die Daten mit
der übergebenen id enthält.
Das dazugehörende SQL Statement ist als Konstante in der DAO Klasse enthalten:
private static String QUERY_STUDENT_GET_BYID
nachname, email from studenten where id=?";
= "select id, matnr, vorname,
Mit diesem String wird ein Statement erzeugt. Danach wird der Parameter (das Fragezeichen)
des Statements gesetzt:
Page 2
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Eingangsbeispiel - Dokumentation
PreparedStatement ps =
getConnection().prepareStatement(QUERY_STUDENT_GET_BYID);
ps.setLong(1, id.longValue());
Nach der Ausführung des Statements steht ein ResultSet zur Verfügung, aus dem die
ausgewählten Daten geholt werden können:
ResultSet rs = ps.getResultSet();
Mit der Methode createStudent wird eine neue Instanz der Klasse Student angelegt und mit
den Daten aus dem ResultSet befüllt:
Student s = createStudent(rs);
Fertig - nun kann die Instanz zurückgegeben werden.
2.2. Schreibende Operation - addStudent
Die Funktion addStudent(Student) legt ein übergebenes Student Objekt in der
Datenbank an. In der Datenbank repräsentiert eine Zeile in der Tabelle studenten einen
Studenten. Jede Zeile wird über eine eindeutige, laufende ID identifiziert. Diese ID wird von
der Datenbank verwaltet und für jeden neuen Studenten automatisch erzeugt.
Unsere Funktion muss also:
• die Felder des Student Objekts den Spalten der Tabelle zuordnen (sie mappen).
• die von der Datenbank erzeugte ID holen und dem Student Objekt zurückgeben
In unserem Beispiel ist es sehr unwahrscheinlich, dass zwei Einfügen-Operationen
gleichzeitig ausgeführt werden, aber in einer großen Applikation kann dies durchaus
vorkommen. Um zu gewährleisten, dass jene ID, die sich das Programm von der Datenbank
holt, jene ID ist, die für unser Student Objekt vergeben wurde, führen wir beide Statements in
einer Transaktion durch.
Nachdem eine Datenbankverbindung geholt wurde, wird der Insert Befehl vorbereitet. Der
SQL String dazu:
private static String QUERY_STUDENT_INSERT = "INSERT INTO studenten (matnr,
vorname, nachname, email) values (?, ?, ?, ?)";
Danach wird das Statement mit Daten befüllt und das Statement ausgeführt.
psInsert.setString(1, student.getMatnr());
psInsert.setString(2, student.getVorname());
psInsert.setString(3, student.getNachname());
Page 3
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Eingangsbeispiel - Dokumentation
psInsert.setString(4, student.getEmail());
psInsert.execute();
HSQLDb hat für die neue Zeile eine ID generiert, die mit folgendem Statement ausgelesen
werden kann:
private static String QUERY_GET_LAST_ID = "CALL IDENTITY()";
Wir führen dieses Statement aus - bekommen wir von der Datenbank keine Antwort, rollen
wir die gesamte Transaktion zurück:
Statement stmtId = dbConnection.createStatement();
stmtId.execute(QUERY_GET_LAST_ID);
rsKey = stmtId.getResultSet();
if(!rsKey.next()) {
log.error("Error: Inserting student did not generate a key");
dbConnection.rollback();
return 0L;
}
Danach lesen wir den Key aus und schließen die Transaktion ab:
// "@p0" ist der Name der Spalte die hsqldb für die Id verwendet
id = new Long(rsKey.getLong("@p0"));
dbConnection.commit();
Nun setzen wir die ausgelesene ID noch im Student Objekt und geben die ID zurück.
student.setId(id);
return id;
2.3. Referenzen
Data Access Object: Beschreibung des Data Access Object Patterns auf sun.com
3. Presentation Layer
Der Presentation Layer ist jener Teil des Programms, der für die Präsentation (Anzeige) der
Daten zuständig ist. Überlicherweise greift man bei der Programmierung des Presentation
Layers auf das MVC-Modell zurück.
Page 4
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Eingangsbeispiel - Dokumentation
Beim Model-View-Controller-Modell (=MVC-Modell) handelt es sich um ein
Architekturmuster zur Trennung von Software-Systemen in die drei Einheiten Datenmodell
(engl. Model), Präsentation (engl. View) und Programmsteuerung (engl. Controller).
Das Datenmodell enthält die dauerhaften Daten der Anwendung. Das Model hat lesenden
Zugriff auf diverse Speicher wie zum Beispiel Datenbanken. Das Model kennt weder die
View noch den Controller, es weiß also gar nicht, wie, ob und wie oft es dargestellt und
verändert wird. Änderungen im Model werden allerdings über einen Update-Mechanismus
bekannt gegeben, indem ein Event ausgelöst wird.
Die Darstellungsschicht (View) präsentiert die Daten in der Regel - jedoch nicht
notwendigerweise - zwecks Anzeige. Die Programmlogik sollte aus dem View entfernt
werden. Der View kennt das Model und ist dort registriert, um sich selbständig aktualisieren
zu können.
Der Controller verwaltet die Schichten, nimmt von ihnen Benutzeraktionen entgegen, wertet
diese aus und hat schreibenden Zugriff auf das Modell. Er enthält die Intelligenz und steuert
den Ablauf (engl. Workflow) der Anwendung.
Das MVC-Muster trifft allerdings keine Aussage über die Positionierung der Geschäftslogik
innerhalb der MVC-Klassen. Diese kann je nach Anwendungsfall besser im Controller
aufgehoben sein oder besser in das Modell verlagert werden.
Das Basisprogramm besitzt 2 Models, das ExportComboModel für die Verwaltung der
verschiedenen Exportformate und das StudentenTableModel zum Lesen der Daten aus der
Datenbank mit Hilfe des DAO.
Eine getrennte Controller Schicht ist im Basisprogramm nicht vorhanden, die Verwaltung des
Ablaufs erfolgt direkt im View.
3.1. ExportComboModel
Das ExportComboModel hat die Aufgabe, alle vorhandenen Export Formate (im
Basisprogramm XML und HTML) zu verwalten, und die ComboBox des Swing Interfaces
mit den jeweiligen Auswahlmöglichkeiten zu befüllen.
Im Konstruktor wird zunächst eine Liste erzeugt, in der die Export Formate gespeichert
werden.
exportFilter = new ArrayList|Export|();
Danach werden die jeweiligen Klassen der einzelnen Exportformate hinzugefügt.
Page 5
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Eingangsbeispiel - Dokumentation
exportFilter.add(new XmlExportImport());
exportFilter.add(new HtmlExport());
Dann wird noch mit Hilfe der Funktion setExportFilter(exportFilter); ein Log
Statement ausgegeben, und das erste Objekt der Liste mit selectedItem =
exportFilter.get(0); ausgewählt.
Will man ein neues Export Format unterstützen, braucht man nur eine weitere Klasse in die
Liste einfügen, und das Swing Interface wird automatisch upgedatet und das neue Export
Format steht zur Verfügung.
3.2. StudentenTableModel
Das StudentenTableModel hat die Aufgabe, die Daten aus der Datenbank auszulesen und
diese für die Anzeige im Swing Interface aufzubereiten. Ausserdem updated es das Swing
Interface, zum Beispiel wenn die Sortierreihenfolge geändert wird.
Im Konstrukor wird zunächst das DAO mit studentDAO = new
JdbcStudentDAO(); initialisiert, danach wird die Sortierreihenfolge festgelegt mit
this.order = order; und die komplette Datenbank wird mit der Methode
readData() ausgelesen.
Die Methode reaData() benutzt das DAO um die Datenbank auszulesen:
studenten = studentDAO.getStudents(order);
Wird die Sortierreihenfolge geändert, muss die Datenbank neu ausgelesen werden, um die
Daten in der neuen Reihenfolge zu bekommen, ausserdem muss das Swing Interface mit der
Methode fireTableDataChanged(); aktualisiert werden.
public void setOrder(String order) {
log.info("Order Changed: reading data...");
this.order = order;
readData();
fireTableDataChanged();
}
Nach dem Aufruf der Methode setOrder(String order) wird die neue, richtig sortierte Liste
im Swing Interface angezeigt.
3.3. Graphical User Interface (View)
Das Graphical User Interface (=GUI) ist komplett aus Swing-Komponenten aufgebaut. In der
Klasse MainFrame befinden sich alle Swing Komponenten und die ActionListener für die
Page 6
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Eingangsbeispiel - Dokumentation
jeweiligen Elemente.
In der Klasse MessageDlg wird ein kleines Swing Dialog Fenster mit Statusinformationen
(Bestätigung, Fehleranzeige) erzeugt.
3.3.1. MainFrame Klasse
Im Konstruktor werden zunächst die beiden init Methoden für die Models und die
Komponenten aufgerufen.
initModels();
initComponents();
Ausserdem wird ein eigener Window Listener hinzugefügt, der zum Schliessen des Swing
Fensters notwendig ist.
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent arg0) {
super.windowClosing(arg0);
terminateApplication();
}
});
Die Methode initModels(); initialsiert das StudentenTableModel und das
ExportComboModel. Dabei wird für das StudentenTableModel das Default Sortierkiterium
"Matrikelnummer" festgelegt.
In der Methode initComponents(); werden alle Swing Element erzeugt und plaziert, sowie
mit Action Listenern versehen. Die Vorgehensweise ist folgende:
• Zuerst erzeugt man das MainPanel mit JPanel mainPanel = new JPanel();
• Dann platzieren wir das MainPanel mit getContentPane().add(mainPanel); und versehen
es mit einem LayoutManager mainPanel.setLayout(new BorderLayout(5,5));
Anschliessend wollen wir das MainPanel in drei Bereiche North, Center und South
unterteilen, wir erzeugen also drei weitere Panels, wofür wir JToolbars verwenden, die
ähnlich wie normale Swing Panels, nur etwas flexibler zu verwenden sind. Diese Panels
versehen wir wieder mit einem LayoutManager und fügen sie unserem MainPanel hinzu.
• JPanel centerPanel = new JPanel(); erzeugt das Panel
• centerPanel.setLayout(new BorderLayout()); und
centerPanel.setBorder(BorderFactory.createEmptyBorder(10,5,0,10)); erzeugen das
Layout
• mainPanel.add(centerPanel, BorderLayout.CENTER); fügt das Panel an der
gewünschten Stelle im MainPanel ein.
Anschliessend werden weiter Komponenten wie Labels, Drop Down Felder, Tables und
Page 7
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Eingangsbeispiel - Dokumentation
Buttons in die jeweiligen Panels eingefügt. Einige speziellere Implementationen werden jetzt
noch genauer beschrieben:
Für die Tabelle im Center Panel wird eine JTabel Komponente verwendet JTable table =
new JTable();. Auch das StudentenTableModel muss der JTable hinzugefügt werden, das
erfolgt mit table.setModel(studentenTM); Die Tabelle wird vom Model mit Daten gefüllt,
bzw. im Falle einer Datenänderung automatisch upgedatet.
Das Drop Down Feld für die Auswahl des Sortierkriteriums wird mit einem ItemListener
versehen, um auf Änderungen reagieren zu können. Der ItemListener wird gleich direkt beim
Hinzufügen implementiert, bei einer Änderung wird die Methode sortOrderChanged()
aufgerufen, der Code sieht folgendermassen aus:
selectOrderCB.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
if (ie.getStateChange() == ItemEvent.SELECTED) {
log.debug("Order Combo State Changed: " + ie.getItem());
sortOrderChanged(ie.getItem().toString());
}
}
});
Die Methode sortOrderChanged() ruft einfach die Methode studentenTM.setOrder(order);
des StudentenTableModels mit dem neuen Sortierkriterium auf, und das Model updated die
Tabelle.
Für das Drop Down Feld zum Auswählen der Export Formate wird das ExportComboModel
mit exportCB.setModel(exportComboModel); hinzugefügt und ein Tooltip mit
exportCB.setToolTipText("Exportformat auswŠhlen, danach |Export| drŸcken"); erzeugt.
Für alle Buttons wird ein ActionListener hinzugefügt, die jeweilige Implementation wird
gleich in der MainFrame Klasse vorgenommen. Daher kann man alle ActionListener mit this
implementieren, noch ein Beispiel zur Verdeutlichung: exportBtn.addActionListener(this);
Der ActionListener überprüft, welcher Button das Event ausgelöst hat, und ruft entweder die
Methode terminateApplication(); zum Beenden des Programms oder die Methode export();
für den Export Dialog auf.
Die Methode export() liest zuerst das vom Benutzer gewählte Exportformat, bzw. die zu
benutzende ExportKlasse aus. Export export =
(Export)exportComboModel.getSelectedItem(); Danach wird ein JFileChooser Dialog
angezeigt. um Pfad und Dateinamen für die Exportdatei zu erhalten. Nach einer Abfrage,
oder der Dialog erfolgreich beendet wurde if (returnVal ==
JFileChooser.APPROVE_OPTION) wird der Pfad ausgelesen String filename =
jfc.getSelectedFile().getPath(); und die Methode export.write(studentenTM.getStudenten(),
filename); der Export Klasse aufgerufen. Danach wird ein Message Dialog erzeugt, der
Page 8
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Eingangsbeispiel - Dokumentation
entweder einer Bestätigung oder eine Fehlermeldung anzeigt. MessageDlg mdlg = new
MessageDlg(this, "Daten wurden erfolgreich exportiert!");
3.3.2. MessageDlg Klasse
Diese Klasse erzeugt in kleines Dialog Fenster für die Bestätigung bzw. das Anzeigen eines
Fehlers bei Aufrufen der Export Funktion im Hauptfenster. Die Klasse für den
MessageDialog wird von der Swing Klasse JDialog abgeleitet public class MessageDlg
extends JDialog und anschliessend im Konstruktor mit normalen Swing Komponenten wie
Panels, Labels und einem Button versehen. Der Label wird mit dem übergebenen String
initialisiert, textMsg = new JLabel(message); der entweder die Bestätigungs- oder die
Fehlermeldung enthält.
Anschliessend wird noch die Methode pack(); aufgerufen, welche die Grösse des Fensters an
die aktuellen Komponenten angepasst. Dann wird noch der Action Listener für den OK
Button implementiert und die MessageDlg Klasse ist fertig.
3.4. Referenzen
•
Sun Swing/JFC
Page 9
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Herunterladen