Klausur BOPRO2

Das Ergebnis: Ergebnis Klausur BOPRO2

Die Aufgabe

Die Aufgabe ist die Erstellung einer Java Software zur Erfassung und Speicherung gefahrener Kilometer der Fahrer einer Spedition

Die zu erstellende java Software soll eine einfache Erfassung von gefahrenen Kilometern der Fahrer einer Spedition ermöglichen. Die Lösung soll dabei rein dateibasiert arbeiten. In einer Datei „kilometer.csv“ finden sich alle Fahrer, für die die gefahrenen Kilometer erfasst werden, sowie die einzelnen Fahrten der Fahrer.

Diese Datei ist zum Start der Anwendung einzulesen. Fahrer sind als Objekte einer eigenen Klasse anzulegen. Auch für einzelne Fahrten ist eine eigene Klasse zu programmieren. Die Fahrten eines Fahrers sind dann in einer Kollektion bei jedem einzelnen Fahrer zu speichern. Da die Fahrten nach Datum zu sortieren sind, sollte die Klasse für die Fahren das Standardinterface für die Umsetzung von Vergleichen im Rahmen einer Sortierung implementieren.

Erstellen Sie zur Umsetzung der Kilometerverwaltung eine Anwendung mit einer selbstentworfenen, grafischen Benutzeroberfläche, die für alle notwendigen Aufgaben Aktionsmöglichkeiten zur Verfügung stellt. Dies muss aufgrund der wenigen Funktionen kein Menü enthalten, die Benutzerführung kann rein über Pushbuttons erfolgen. Beispiele aller GUI-Ansichten sind mitzugeben. Die Benutzeroberfläche sollte in der Kopfzeile eine Combobox darstellen, in der alle vorhandenen Fahrer mit Personalnummer und Name zur Auswahl stehen, d.h. die Kombination aus Personalnummer und Name erzeugt einen einzigen Eintrag zur Auswahl in der Combobox. Es kann davon ausgegangen werden, dass die Personalnummer genau zehn Ziffern umfasst. Wird hier ein Fahrer ausgewählt, erscheinen in einer Auflistung unterhalb der Kopfzeile alle Fahrten des Fahrers nach Datum absteigend sortiert. Neben der Combobox für die Fahrerauswahl soll ein Button aufgenommen werden, über den ein Dialogfenster aufgeht, der die Erfassung eines neuen Fahrers mit Personalnummer, Vor- und Nachname ermöglicht. Nutzen Sie zum Sortieren und für Vergleiche vorhandene Standardmethoden. Unterhalb der Liste soll die Gesamtsumme aller gefahrenen Kilometer des ausgewählten Fahrers stehen. Nutzen Sie zur Berechnung der Gesamtsumme die Möglichkeiten der Streamverarbeitung von Java. Unterhalb der Auflistung der Fahrten eines Fahrers und der Gesamtkilometeranzahl sind noch drei Eingabefelder zur Erfassung einer neuen Fahrt zu platzieren. Für eine Fahrt sind dabei Datum, Startort und die gefahrene Kilometeranzahl erfassbar und über einen Button in den Bestand aufzunehmen. Diese Informationen sind auch in der Liste der Fahrten darzustellen. Ein Löschen oder Ändern erfasster Fahrten ist nicht erforderlich. Innerhalb der GUI ist noch ein Buttons zu platzieren, über den das Programm beendet werden kann. Beim Beenden des Programms sind die aktuellen Daten zu den Fahrten zu speichern.

Teilweise werden Fahrten extern erfasst. In einem eigenen Thread soll daher jede Minute geprüft werden, ob eine Datei „addfahrten.csv“ vorhanden ist. In dieser Datei findet sich in jeder Zeile eine Fahrt eines Fahrers. Eine Zeile beginnt dabei mit der Personalnummer des Fahrers gefolgt von den Fahrtdaten mit Datum, Startort und Kilometer. Die Werte sind jeweils mit einem Komma voneinander getrennt. Hier eine Beispieldatei erzeugen.

Die Ergänzungen bei den Fahrten sind beim Entdecken der Datei direkt beim vorhandenen Datenbestand der Anwendung durchzuführen, die GUI ist direkt zu aktualisieren. Beim Laden einer negativen Kilometeranzahl ist eine Ausnahme auszulösen. Nach der Verarbeitung der Dateiinhalte ist diese zu löschen. Strukturieren Sie Ihre Lösung mit passenden Klassen. Setzen Sie Packages als auch Ausnahmen sinnvoll ein. Abläufe, die durch die Aufgabenstellung nicht konkret festgelegt sind, können nach eigenem Ermessen festgelegt werden, sie sollten dabei eine sinnvolle Handhabung des Programms ermöglichen.


Der Code

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
 
public class Fahrer implements Comparable<Fahrer> {
    private String personalnummer;
    private String vorname;
    private String nachname;
    private List<Fahrt> fahrten;
 
    public Fahrer(String personalnummer, String vorname, String nachname) {
        this.personalnummer = personalnummer;
        this.vorname = vorname;
        this.nachname = nachname;
        this.fahrten = new ArrayList<>();
    }
 
    public void addFahrt(Fahrt fahrt) {
        fahrten.add(fahrt);
        fahrten.sort(null);
    }
 
    public int berechneGesamtKilometer() {
        return fahrten.stream().mapToInt(Fahrt::getKilometer).sum();
    }
 
    // Getter and Setter methods
 
    @Override
    public int compareTo(Fahrer other) {
        return other.personalnummer.compareTo(this.personalnummer);
    }
}
 
class Fahrt implements Comparable<Fahrt> {
    private LocalDate datum;
    private String startort;
    private int kilometer;
 
    public Fahrt(LocalDate datum, String startort, int kilometer) {
        this.datum = datum;
        this.startort = startort;
        this.kilometer = kilometer;
    }
 
    // Getter and Setter methods
 
    @Override
    public int compareTo(Fahrt other) {
        return other.datum.compareTo(this.datum);
    }
}

Zusammenfassung des Java-Codes

Der obere Java-Code definiert zwei Klassen: Fahrer und Fahrt. Beide Klassen implementieren das Comparable Interface, um eine Sortierung zu ermöglichen.

Klasse Fahrer

Klasse Fahrt

Interaktionen

Der Code ist darauf ausgelegt, Fahrer und ihre Fahrten zu verwalten und bietet Funktionalitäten, um Fahrten hinzuzufügen und die Gesamtkilometer zu berechnen. Die Sortierung der Fahrten und Fahrer basiert auf dem Datum der Fahrt bzw. der Personalnummer des Fahrers.


import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Vector;
 
public class KilometerVerwaltungGUI extends JFrame {
    private JComboBox<Fahrer> fahrerComboBox;
    private DefaultListModel<String> fahrtenListModel;
    private JList<String> fahrtenList;
    private JTextField datumTextField, startortTextField, kilometerTextField;
    private JLabel gesamtKilometerLabel;
    private Vector<Fahrer> fahrerVector;
 
    public KilometerVerwaltungGUI(Vector<Fahrer> fahrerVector) {
        this.fahrerVector = fahrerVector;
 
        setTitle("Kilometerverwaltung");
        setSize(400, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
 
        // Initialize GUI components
        fahrerComboBox = new JComboBox<>(fahrerVector);
        fahrtenListModel = new DefaultListModel<>();
        fahrtenList = new JList<>(fahrtenListModel);
        JScrollPane fahrtenScrollPane = new JScrollPane(fahrtenList);
 
        JPanel inputPanel = new JPanel(new GridLayout(4, 2));
        datumTextField = new JTextField();
        startortTextField = new JTextField();
        kilometerTextField = new JTextField();
        JButton addFahrtButton = new JButton("Fahrt hinzufügen");
        gesamtKilometerLabel = new JLabel("Gesamtkilometer: 0");
 
        inputPanel.add(new JLabel("Datum (dd.MM.yyyy):"));
        inputPanel.add(datumTextField);
        inputPanel.add(new JLabel("Startort:"));
        inputPanel.add(startortTextField);
        inputPanel.add(new JLabel("Kilometer:"));
        inputPanel.add(kilometerTextField);
        inputPanel.add(addFahrtButton);
        inputPanel.add(gesamtKilometerLabel);
 
        add(fahrerComboBox, BorderLayout.NORTH);
        add(fahrtenScrollPane, BorderLayout.CENTER);
        add(inputPanel, BorderLayout.SOUTH);
 
        // Event handler for adding a new Fahrt
        addFahrtButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    LocalDate datum = LocalDate.parse(datumTextField.getText(), DateTimeFormatter.ofPattern("dd.MM.yyyy"));
                    String startort = startortTextField.getText();
                    int kilometer = Integer.parseInt(kilometerTextField.getText());
                    Fahrer selectedFahrer = (Fahrer) fahrerComboBox.getSelectedItem();
                    if (selectedFahrer != null) {
                        Fahrt neueFahrt = new Fahrt(datum, startort, kilometer);
                        selectedFahrer.addFahrt(neueFahrt);
                        aktualisiereFahrtenListe(selectedFahrer);
                    }
                } catch (DateTimeParseException | NumberFormatException ex) {
                    JOptionPane.showMessageDialog(KilometerVerwaltungGUI.this,
                            "Fehler bei der Eingabe. Bitte überprüfen Sie das Format.",
                            "Eingabefehler", JOptionPane.ERROR_MESSAGE);
                }
            }
        });
 
        // Event handler for selecting a Fahrer in the ComboBox
        fahrerComboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Fahrer selectedFahrer = (Fahrer) fahrerComboBox.getSelectedItem();
                if (selectedFahrer != null) {
                    aktualisiereFahrtenListe(selectedFahrer);
                }
            }
        });
 
        setVisible(true);
    }
 
    private void aktualisiereFahrtenListe(Fahrer fahrer) {
        fahrtenListModel.clear();
        for (Fahrt fahrt : fahrer.getFahrten()) {
            fahrtenListModel.addElement(fahrt.getDatum().format(DateTimeFormatter.ofPattern("dd.MM.yyyy")) +
                    " - " + fahrt.getStartort() + " - " + fahrt.getKilometer() + " km");
        }
        gesamtKilometerLabel.setText("Gesamtkilometer: " + fahrer.berechneGesamtKilometer());
    }
}

Zusammenfassung des Java-Codes für die Kilometerverwaltung GUI

Der Java-Code beschreibt eine grafische Benutzeroberfläche (GUI) für eine Kilometerverwaltungsanwendung mit Swing. Die Hauptklasse KilometerVerwaltungGUI erweitert JFrame und stellt die Benutzeroberfläche bereit, um Fahrten für verschiedene Fahrer zu verwalten.

Hauptkomponenten der GUI

Funktionen und Interaktionen

Die GUI ermöglicht es Benutzern, Fahrten für Fahrer hinzuzufügen, anzuzeigen und die Gesamtkilometer zu berechnen. Die Interaktion zwischen den GUI-Komponenten und den Event-Handlern sorgt für eine dynamische Benutzererfahrung.


import java.io.*;
import java.nio.file.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class DateiVerarbeitung {
    private static final String KILOMETER_CSV = "kilometer.csv";
    private static final String ADD_FAHRTEN_CSV = "addfahrten.csv";
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd.MM.yyyy");
 
    public static List<Fahrer> ladeFahrerUndFahrten() throws IOException {
        List<Fahrer> fahrerListe = new ArrayList<>();
        Map<String, Fahrer> fahrerMap = new HashMap<>();
 
        Path path = Paths.get(KILOMETER_CSV);
        if (!Files.exists(path)) {
            return fahrerListe;
        }
 
        List<String> lines = Files.readAllLines(path);
        for (String line : lines) {
            String[] data = line.split(";");
            if (data[0].equals("Fahrer")) {
                String personalnummer = data[1];
                String vorname = data[2];
                String nachname = data[3];
                Fahrer fahrer = new Fahrer(personalnummer, vorname, nachname);
                fahrerListe.add(fahrer);
                fahrerMap.put(personalnummer, fahrer);
            } else if (data[0].equals("Fahrt")) {
                String personalnummer = data[1];
                LocalDate datum = LocalDate.parse(data[2], DATE_FORMAT);
                String startort = data[3];
                int kilometer = Integer.parseInt(data[4]);
                Fahrer fahrer = fahrerMap.get(personalnummer);
                if (fahrer != null) {
                    Fahrt fahrt = new Fahrt(datum, startort, kilometer);
                    fahrer.addFahrt(fahrt);
                }
            }
        }
 
        return fahrerListe;
    }
 
    public static void speichereFahrerUndFahrten(List<Fahrer> fahrerListe) throws IOException {
        Path path = Paths.get(KILOMETER_CSV);
        try (BufferedWriter writer = Files.newBufferedWriter(path)) {
            for (Fahrer fahrer : fahrerListe) {
                String line = "Fahrer;" + fahrer.getPersonalnummer() + ";" + fahrer.getVorname() + ";" + fahrer.getNachname();
                writer.write(line);
                writer.newLine();
                for (Fahrt fahrt : fahrer.getFahrten()) {
                    line = "Fahrt;" + fahrer.getPersonalnummer() + ";" +
                            fahrt.getDatum().format(DATE_FORMAT) + ";" +
                            fahrt.getStartort() + ";" +
                            fahrt.getKilometer();
                    writer.write(line);
                    writer.newLine();
                }
            }
        }
    }
 
    public static void aktualisiereFahrtenAusDatei(List<Fahrer> fahrerListe) throws IOException {
        Path path = Paths.get(ADD_FAHRTEN_CSV);
        if (!Files.exists(path)) {
            return;
        }
 
        List<String> lines = Files.readAllLines(path);
        for (String line : lines) {
            String[] data = line.split(";");
            String personalnummer = data[0];
            LocalDate datum = LocalDate.parse(data[1], DATE_FORMAT);
            String startort = data[2];
            int kilometer = Integer.parseInt(data[3]);
 
            Fahrer fahrer = fahrerListe.stream()
                    .filter(f -> f.getPersonalnummer().equals(personalnummer))
                    .findFirst()
                    .orElse(null);
 
            if (fahrer != null) {
                Fahrt fahrt = new Fahrt(datum, startort, kilometer);
                fahrer.addFahrt(fahrt);
            }
        }
 
        Files.delete(path);
    }
}
 
public class DateiUeberwachungThread extends Thread {
    private List<Fahrer> fahrerListe;
    private KilometerVerwaltungGUI gui;
 
    public DateiUeberwachungThread(List<Fahrer> fahrerListe, KilometerVerwaltungGUI gui) {
        this.fahrerListe = fahrerListe;
        this.gui = gui;
    }
 
    @Override
    public void run() {
        while (!isInterrupted()) {
            try {
                Path path = Paths.get(DateiVerarbeitung.ADD_FAHRTEN_CSV);
                if (Files.exists(path)) {
                    DateiVerarbeitung.aktualisiereFahrtenAusDatei(fahrerListe);
 
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            Fahrer selectedFahrer = (Fahrer) gui.getFahrerComboBox().getSelectedItem();
                            if (selectedFahrer != null) {
                                gui.aktualisiereFahrtenListe(selectedFahrer);
                            }
                        }
                    });
                }
 
                Thread.sleep(60000);
            } catch (InterruptedException e) {
                break;
            } catch (IOException e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        JOptionPane.showMessageDialog(gui,
                                "Fehler beim Einlesen der Datei 'addfahrten.csv'.",
                                "Fehler", JOptionPane.ERROR_MESSAGE);
                    }
                });
            }
        }
    }
}
 
public class KilometerVerwaltungApp {
    public static void main(String[] args) {
        try {
            List<Fahrer> fahrerListe = DateiVerarbeitung.ladeFahrerUndFahrten();
            Vector<Fahrer> fahrerVector = new Vector<>(fahrerListe);
 
            KilometerVerwaltungGUI gui = new KilometerVerwaltungGUI(fahrerVector);
 
            Date
 

Zusammenfassung des Java-Codes für Dateiverarbeitung und Überwachung

Der Java-Code umfasst mehrere Klassen, die für das Laden, Speichern und Aktualisieren von Fahrer- und Fahrtendaten aus CSV-Dateien sowie für die Überwachung von Dateiänderungen in Echtzeit verantwortlich sind.

Klasse DateiVerarbeitung

Klasse DateiUeberwachungThread

Klasse KilometerVerwaltungApp

Interaktionen

Der Code ermöglicht eine effiziente Verwaltung von Fahrer- und Fahrtendaten durch das Einlesen und Schreiben von CSV-Dateien und bietet eine Echtzeit-Überwachung für Aktualisierungen.


Beispieldatei kilometer.csv

Fahrer;Personalnummer;Vorname;Nachname
Fahrer;10000000001;Peter;Schmitt
Fahrer;10000000002;Paul;Müller
Fahrer;10000000003;Mary;Wagner
Fahrt;Personalnummer;Datum;Startort;Kilometer
Fahrt;10000000001;2023-01-10;Berlin;350
Fahrt;10000000002;2023-01-11;Hamburg;250
Fahrt;10000000003;2023-01-12;München;420

Neue Version

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;
 
// Klasse, die einen Fahrer repräsentiert
class Fahrer {
    private String personalnummer;
    private String vorname;
    private String nachname;
    private List<Fahrt> fahrten;
 
    public Fahrer(String personalnummer, String vorname, String nachname) {
        this.personalnummer = personalnummer;
        this.vorname = vorname;
        this.nachname = nachname;
        this.fahrten = new ArrayList<>();
    }
 
    // Getter und Setter Methoden
    // ...
 
    // Methode zum Hinzufügen einer Fahrt und Sortieren der Fahrtenliste
    public void addFahrt(Fahrt fahrt) {
        fahrten.add(fahrt);
        fahrten.sort(null);
    }
 
    // toString-Methode für die Darstellung in der ComboBox
    @Override
    public String toString() {
        return personalnummer + " - " + vorname + " " + nachname;
    }
}
 
// Klasse, die eine Fahrt repräsentiert
class Fahrt implements Comparable<Fahrt> {
    // Attribute für Personalnummer, Datum, Startort und Kilometer
    // ...
 
    // Konstruktor, Getter und Setter Methoden
    // ...
 
    // compareTo-Methode für das Sortieren nach Datum
    @Override
    public int compareTo(Fahrt other) {
        return other.datum.compareTo(this.datum);
    }
 
    // toString-Methode für die Darstellung in der Textarea
    @Override
    public String toString() {
        return String.format("%s - %s - %d km", datum.format(DateTimeFormatter.ISO_LOCAL_DATE), startort, kilometer);
    }
}
 
// Klasse zur Verwaltung der Fahrer und Fahrten
class KilometerVerwaltung {
    private static final String CSV_FILE = "kilometer.csv";
    private Map<String, Fahrer> fahrerMap = new HashMap<>();
 
    // Methode zum Einlesen der CSV-Datei und Erstellen der Fahrer- und Fahrtobjekte
    public void einlesenCsvDatei() {
        // ...
    }
 
    // Methode zum Speichern der Daten in die CSV-Datei
    public void speichernCsvDatei() {
        // ...
    }
 
    // Getter für die Fahrer-Map
    public Map<String, Fahrer> getFahrerMap() {
        return fahrerMap;
    }
}
 
// Thread-Klasse, die die addfahrten.csv Datei überwacht und Fahrten hinzufügt
class FahrtenUpdater implements Runnable {
    private KilometerVerwaltung kilometerVerwaltung;
    private static final String ADD_FAHRTEN_CSV = "addfahrten.csv";
 
    public FahrtenUpdater(KilometerVerwaltung kilometerVerwaltung) {
        this.kilometerVerwaltung = kilometerVerwaltung;
    }
 
    @Override
    public void run() {
        // Überwachungslogik für die addfahrten.csv Datei
        // ...
    }
}
 
// Hauptklasse für die GUI
public class FahrAwayGUI {
    // GUI-Komponenten und Attribute
    // ...
 
    public FahrAwayGUI(KilometerVerwaltung kilometerVerwaltung) {
        // Initialisierung der GUI-Komponenten und Event-Listener
        // ...
    }
 
    // Singleton-Getter für die GUI-Instanz
    public static FahrAwayGUI getInstance() {
        return instance;
    }
 
    // Methode zum Laden der Fahrer in die ComboBox
    private void ladeFahrerInComboBox() {
        // ...
    }
 
    // Methode zum Aktualisieren der Fahrtenanzeige
    private void aktualisiereFahrtenAnzeige() {
        // ...
    }
 
    // Methode zum Erfassen einer neuen Fahrt
    private void erfasseFahrt() {
        // ...
    }
 
    // Methode zum Aktualisieren der GUI von einem anderen Thread aus
    public void aktualisiereGUI() {
        // ...
    }
 
    // Methode zum Starten des FahrtenUpdater-Threads
    public void starteFahrtenUpdater() {
        // ...
    }
 
    // Methode zum Stoppen des FahrtenUpdater-Threads
    public void stoppeFahrtenUpdater() {
        // ...
    }
 
    // Hauptmethode zum Starten der Anwendung
    public static void main(String[] args) {
        // ...
    }
}