Projekt „Java Anwendung markdown2flashcards“ Teil 2 – Grafische Oberfläche mit JavaFX bauen

erweiterte pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.linformatik</groupId>
    <artifactId>markdown2flashcards</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>markdown2flashcards</name>
    <url>http://linformatik.de</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!--GUI für Karteikasten -->
        <!-- JavaFX Dependencies -->
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>19</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>19</version>
    </dependency>

    </dependencies>

    <build>
        <plugins>
            <!-- Maven Compiler Plugin für Java Version 21 -->
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>

  <!-- JFX Plugin für GUI-->
        <plugin>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-maven-plugin</artifactId>
            <version>0.0.5</version>
              <configuration>
                <mainClass>de.linformatik.App</mainClass> <!-- Die Klasse mit der main-Methode -->
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
          
            <!-- JAR Plugin für Manifest -->
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <!-- Hauptklasse im Manifest definieren -->
                            <mainClass>de.linformatik.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

            <!-- Maven Clean Plugin für das Bereinigen des Projekts -->
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>

            <!-- Maven Resources Plugin für das Kopieren von Ressourcen -->
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.0.2</version>
            </plugin>

            <!-- Maven Surefire Plugin für Tests -->
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.1</version>
            </plugin>

            <!-- Maven Install Plugin für das Installieren der Artefakte -->
            <plugin>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>

            <!-- Maven Deploy Plugin für das Bereitstellen der Artefakte -->
            <plugin>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
            </plugin>

            <!-- Maven Site Plugin für die Erstellung von Sites und Berichten -->
            <plugin>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.7.1</version>
            </plugin>

            <!-- Maven Project Info Reports Plugin -->
            <plugin>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>3.0.0</version>
            </plugin>

        </plugins>
    </build>
</project>

Erweiterte App.java


package de.linformatik;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;

import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

public class App extends Application {

    private int currentCardIndex = 0;
    private List<Flashcard> flashcards = new ArrayList<>();
    private Map<String, int[]> questionStatistics = new HashMap<>(); // Speichert richtige und falsche Antworten pro Frage
    private Scene flashcardScene;  // Speichern der Flashcard-Szene

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        // Flashcards laden
        String flashcardsPath = loadFlashcardsPathFromConfig();
        if (flashcardsPath != null) {
            flashcards = loadFlashcards(flashcardsPath);
        } else {
            System.out.println("Kein Flashcards-Pfad gefunden.");
        }

        // Textfelder für Frage und Antwort
        Text questionText = new Text();
        Text answerText = new Text();

        // Antwort anfangs unsichtbar
        answerText.setVisible(false);

        // Schriftgrößen für Frage, Antwort und Statistik setzen
        questionText.setStyle("-fx-font-size: 18px;");
        answerText.setStyle("-fx-font-size: 16px;");

        // Button zum Weiterblättern der Karten
        Button nextButton = new Button("Nächste Karte");
        nextButton.setStyle("-fx-font-size: 14px;");
        nextButton.setOnAction(event -> showNextCard(questionText, answerText));

        // Button zum Zurückblättern der Karten
        Button prevButton = new Button("Vorherige Karte");
        prevButton.setStyle("-fx-font-size: 14px;");
        prevButton.setOnAction(event -> showPreviousCard(questionText, answerText));

        // Button zum Anzeigen der Antwort
        Button showAnswerButton = new Button("Antwort anzeigen");
        showAnswerButton.setStyle("-fx-font-size: 14px;");
        showAnswerButton.setOnAction(event -> {
            answerText.setVisible(true);  // Antwort sichtbar machen
        });

        // Button für "Habs gewusst"
        Button correctButton = new Button("Habs gewusst");
        correctButton.setStyle("-fx-font-size: 14px;");
        correctButton.setOnAction(event -> markAnswerCorrect(questionText));

        // Button für "Habs nicht gewusst"
        Button incorrectButton = new Button("Habs nicht gewusst");
        incorrectButton.setStyle("-fx-font-size: 14px;");
        incorrectButton.setOnAction(event -> markAnswerIncorrect(questionText));

        // Buttons nebeneinander anordnen (mit HBox)
        HBox answerButtons = new HBox(10, correctButton, incorrectButton);
        answerButtons.setStyle("-fx-alignment: center;");

        // Buttons für Navigieren und Statistik nebeneinander anordnen
        HBox navButtons = new HBox(10, prevButton, nextButton, showAnswerButton);
        navButtons.setStyle("-fx-alignment: center;");

        // Button für Statistik anzeigen
        Button statsButton = new Button("Statistik anzeigen");
        statsButton.setStyle("-fx-font-size: 14px;");
        statsButton.setOnAction(event -> showStatistics(primaryStage));

        // Layout der GUI
        VBox layout = new VBox(10, questionText, navButtons, answerText, answerButtons, statsButton);
        layout.setStyle("-fx-padding: 20;");

        // Anfangswerte der ersten Karte
        updateCard(questionText, answerText);

        // Erstelle und zeige die Szene
        flashcardScene = new Scene(layout, 1400, 1000);  // Größeres Fenster
        primaryStage.setTitle("Flashcards");
        primaryStage.setScene(flashcardScene);
        primaryStage.show();
    }

    // Liest den Pfad der Flashcards aus der config.xml-Datei
    private String loadFlashcardsPathFromConfig() {
        try {
            // XML-Dokument einlesen
            File configFile = new File("config.xml");
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(configFile);

            // Den Tag <flashcardsPath> auslesen
            NodeList nodeList = document.getElementsByTagName("flashcardsPath");
            if (nodeList.getLength() > 0) {
                Node node = nodeList.item(0);
                return node.getTextContent().trim();  // Rückgabe des Pfads
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null; // Falls keine Datei oder Fehler beim Lesen
    }

    // Lädt die Flashcards aus der angegebenen Datei
    private List<Flashcard> loadFlashcards(String filename) {
        List<Flashcard> flashcards = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
            String line;
            String currentQuestion = null;
            StringBuilder currentAnswer = new StringBuilder();  // Antwort kann mehrere Zeilen haben
    
            while ((line = br.readLine()) != null) {
                line = line.trim();  // Entfernt unnötige Leerzeichen am Anfang und Ende der Zeile
    
                // Wenn eine Frage erkannt wird
                if (line.startsWith("## Frage")) {
                    // Falls bereits eine Frage und Antwort existieren, speichern wir sie
                    if (currentQuestion != null && currentAnswer.length() > 0) {
                        flashcards.add(new Flashcard(currentQuestion, currentAnswer.toString()));
                    }
    
                    // Extrahieren der Frage, nachdem "## Frage <Nummer>:" entfernt wurde
                    currentQuestion = line.substring(9).trim();
                    currentAnswer = new StringBuilder(); // Setze Antwort zurück
                }
                // Wenn eine Antwort erkannt wird
                else if (line.startsWith("**Antwort:**")) {
                    // Füge die Antwortzeile zur bestehenden Antwort hinzu
                    currentAnswer.append(line.substring(12).trim());
                    currentAnswer.append("\n");  // Antwort auf neue Zeile setzen
                }
            }
    
            // Letzte Frage und Antwort hinzufügen, wenn vorhanden
            if (currentQuestion != null && currentAnswer.length() > 0) {
                flashcards.add(new Flashcard(currentQuestion, currentAnswer.toString()));
            }
    
        } catch (IOException e) {
            e.printStackTrace();
        }
        return flashcards;
    }

    // Aktualisiert die Anzeige der aktuellen Karte
    private void updateCard(Text questionText, Text answerText) {
        if (flashcards.size() > 0) {
            Flashcard currentCard = flashcards.get(currentCardIndex);
            questionText.setText("Frage: " + currentCard.question);
            answerText.setText("Antwort: " + currentCard.answer);
            answerText.setVisible(false);  // Antwort anfangs unsichtbar
        } else {
            questionText.setText("Keine Flashcards gefunden.");
            answerText.setText("");
        }
    }

    // Zeigt die nächste Flashcard an
    private void showNextCard(Text questionText, Text answerText) {
        if (currentCardIndex < flashcards.size() - 1) {
            currentCardIndex++;
            updateCard(questionText, answerText);
        }
    }

    // Zeigt die vorherige Flashcard an
    private void showPreviousCard(Text questionText, Text answerText) {
        if (currentCardIndex > 0) {
            currentCardIndex--;
            updateCard(questionText, answerText);
        }
    }

    // Markiert eine Antwort als richtig und aktualisiert die Statistik für diese Frage
    private void markAnswerCorrect(Text questionText) {
        Flashcard currentCard = flashcards.get(currentCardIndex);
        String question = currentCard.question;
        questionStatistics.putIfAbsent(question, new int[]{0, 0});  // Wenn die Frage noch nicht existiert, initialisiere sie
        questionStatistics.get(question)[0]++;  // Richtige Antwort erhöhen
    }

    // Markiert eine Antwort als falsch und aktualisiert die Statistik für diese Frage
    private void markAnswerIncorrect(Text questionText) {
        Flashcard currentCard = flashcards.get(currentCardIndex);
        String question = currentCard.question;
        questionStatistics.putIfAbsent(question, new int[]{0, 0});  // Wenn die Frage noch nicht existiert, initialisiere sie
        questionStatistics.get(question)[1]++;  // Falsche Antwort erhöhen
    }

    // Zeigt die Statistik an
    private void showStatistics(Stage primaryStage) {
        VBox statisticsLayout = new VBox(10);
        statisticsLayout.setStyle("-fx-padding: 20;");

        // Durchlaufen der Fragen und deren Statistiken
        for (Map.Entry<String, int[]> entry : questionStatistics.entrySet()) {
            String question = entry.getKey();
            int[] stats = entry.getValue();
            Text statText = new Text(question + " - Richtige: " + stats[0] + ", Falsche: " + stats[1]);
            statisticsLayout.getChildren().add(statText);
        }

        // Button zum Zurückkehren zur Flashcard-Seite
        Button backButton = new Button("Zurück");
        backButton.setOnAction(event -> primaryStage.setScene(flashcardScene));  // Zurück zur Flashcards-Szene
        statisticsLayout.getChildren().add(backButton);

        // Erstelle und zeige die Statistik-Seite
        Scene statsScene = new Scene(statisticsLayout, 1400, 1000);
        primaryStage.setScene(statsScene);
    }
}

Flashcard.java

package de.linformatik;
public class Flashcard {
    String question;
    String answer;

    Flashcard(String question, String answer) {
        this.question = question;
        this.answer = answer;
    }

    void show() {
        System.out.println("Frage: " + this.question);
        System.out.println("Antwort: " + this.answer);
        System.out.println();
    }
}

Konfiguration für den Pfad der Markdown-Datei config.xml

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <flashcardsPath>J:\Meine Ablage\develop\markdown2flashcards\src\main\java\de\linformatik\flashcards.md</flashcardsPath>
</config>

markdown2flashcards.bat um die JAR Datei auszuführen

@echo off
echo Starte JavaFX-Anwendung...
mvn javafx:run -X > output.log 2>&1
echo Anwendung beendet.
pause

Markdowndatei mit den Fragen und Antworten

flashcards.md

## Frage: Was ist der Unterschied zwischen Ganzzahl- und Gleitkomma-Arithmetik?
**Antwort:**  Ganzzahl-Arithmetik bezieht sich auf die Berechnungen mit ganzen Zahlen, während Gleitkomma-Arithmetik für reelle Zahlen verwendet wird.

## Frage: Was ist der Modulo-Operator?
**Antwort:** Der Modulo-Operator `%` gibt den Rest einer Division zurück.

## Frage: Was ist der Unterschied zwischen Addition und Multiplikation?
**Antwort:** Addition ist das Hinzufügen von Zahlen, Multiplikation ist die wiederholte Addition.

## Frage: Was ist eine Primzahl?
**Antwort:** Eine Primzahl ist eine natürliche Zahl größer als 1, die nur durch 1 und sich selbst teilbar ist.

## Frage: Was ist eine Potenz in der Mathematik?
**Antwort:** Eine Potenz besteht aus einer Basis und einem Exponenten und beschreibt eine wiederholte Multiplikation der Basis.

## Frage: Was ist die Binärdarstellung einer Zahl?
**Antwort:** Die Binärdarstellung ist die Darstellung einer Zahl im Zahlensystem zur Basis 2, bestehend nur aus 0 und 1.

## Frage: Was ist eine Fakultät?
**Antwort:** Die Fakultät einer Zahl \( n \) (geschrieben als \( n! \)) ist das Produkt aller natürlichen Zahlen von 1 bis \( n \).

## Frage: Was ist der Unterschied zwischen einem Bruch und einer Dezimalzahl?
**Antwort:** Ein Bruch stellt ein Verhältnis zwischen zwei Zahlen dar, während eine Dezimalzahl eine Darstellung mit einer Kommastelle ist.

## Frage: Was ist die Kommutativität von Addition und Multiplikation?
**Antwort:** Kommutativität bedeutet, dass die Reihenfolge der Operanden das Ergebnis nicht verändert (z. B. \( a + b = b + a \) oder \( a \times b = b \times a \)).

## Frage: Was ist der Unterschied zwischen einer linearen und einer exponentiellen Funktion?
**Antwort:** Eine lineare Funktion wächst konstant, während eine exponentielle Funktion exponentiell wächst (z. B. Verdopplung bei jedem Schritt).

## Frage: Was ist die Basis eines Zahlensystems?
**Antwort:** Die Basis eines Zahlensystems gibt an, mit wie vielen Ziffern Zahlen dargestellt werden (z. B. Basis 10 für Dezimalsystem, Basis 2 für Binärsystem).

## Frage: Was ist eine Logarithmusfunktion?
**Antwort:** Die Logarithmusfunktion ist die Umkehrfunktion der Exponentialfunktion und gibt an, zu welchem Exponenten eine Basis potenziert werden muss, um eine Zahl zu erhalten.

## Frage: Was ist der Unterschied zwischen einem Skalar und einem Vektor?
**Antwort:** Ein Skalar ist eine einzelne Zahl (z. B. Temperatur), während ein Vektor eine Größe mit Richtung und Betrag ist (z. B. Geschwindigkeit).

Printscreen der Applikation




Projekt „Java Anwendung markdown2flashcards“ Teil 1 – Grundgerüst für Java Anwendung „markdown2flashcards“ mit VSCode, Maven und GIT einrichten, kompilieren und ausführen

Entwicklungsumgebung und Projekt-Struktur

Was ist überhaupt Maven?

Java Maven ist ein Build-Management-Tool, das vor allem in Java-Projekten verwendet wird. Es hilft bei der Verwaltung von Abhängigkeiten, dem Erstellen, Testen und Verwalten von Projekten und deren Modulen. Es vereinfacht den gesamten Entwicklungsprozess und bietet eine Reihe von nützlichen Funktionen:

  1. Projektstruktur und -management: Maven hilft, eine standardisierte Projektstruktur zu erstellen. Damit können Entwickler leichter nachvollziehen, wie ein Projekt aufgebaut ist, ohne dass jedes Teammitglied eine eigene Struktur definieren muss.
  2. Abhängigkeitsmanagement: Maven vereinfacht die Handhabung von externen Bibliotheken (z. B. Frameworks oder Tools), indem es automatisch die richtigen Versionen von Bibliotheken aus einem zentralen Repository (wie dem Maven Central Repository) herunterlädt.
  3. Automatisiertes Build: Maven übernimmt die Aufgabe, den Code zu kompilieren, Tests durchzuführen, Pakete zu erstellen und den Build zu verwalten. Es stellt sicher, dass der gesamte Build-Prozess wiederholbar und konsistent ist.
  4. Plugin-System: Maven bietet eine große Anzahl an Plugins, die verschiedene Aufgaben wie Code-Analyse, Dokumentationserstellung und das Deployment von Anwendungen ermöglichen.
  5. Pom-Datei (Project Object Model): Die zentrale Konfigurationsdatei in Maven ist die pom.xml. Sie beschreibt das Projekt, seine Abhängigkeiten, das Build-Verfahren und andere Projekt-spezifische Informationen.

Insgesamt trägt Maven dazu bei, die Komplexität von Softwareprojekten zu verringern und den Entwicklungsprozess zu optimieren und zu automatisieren.

Konfigurationsdatei pom.xml anlegen

Inhalt der pom.xml:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.linformatik</groupId>
    <artifactId>markdown2flashcards</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>markdown2flashcards</name>
    <url>http://linformatik.de</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Maven Compiler Plugin für Java Version 21 -->
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
          
            <!-- JAR Plugin für Manifest -->
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.0.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <!-- Hauptklasse im Manifest definieren -->
                            <mainClass>de.linformatik.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

            <!-- Maven Clean Plugin für das Bereinigen des Projekts -->
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>

            <!-- Maven Resources Plugin für das Kopieren von Ressourcen -->
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.0.2</version>
            </plugin>

            <!-- Maven Surefire Plugin für Tests -->
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.1</version>
            </plugin>

            <!-- Maven Install Plugin für das Installieren der Artefakte -->
            <plugin>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>

            <!-- Maven Deploy Plugin für das Bereitstellen der Artefakte -->
            <plugin>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
            </plugin>

            <!-- Maven Site Plugin für die Erstellung von Sites und Berichten -->
            <plugin>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.7.1</version>
            </plugin>

            <!-- Maven Project Info Reports Plugin -->
            <plugin>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>3.0.0</version>
            </plugin>

        </plugins>
    </build>
</project>

1. Kopfzeile und Namespaces

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  • XML-Deklaration: Gibt an, dass dies eine XML-Datei ist, die im UTF-8-Zeichensatz kodiert ist.
  • Namespace und Schema: Definiert die XML-Namensräume und die Schema-Location für Maven, damit die Datei korrekt interpretiert werden kann.

2. Projektmetadaten

xmlKopierenBearbeiten<modelVersion>4.0.0</modelVersion>
<groupId>de.linformatik</groupId>
<artifactId>markdown2flashcards</artifactId>
<version>1.0-SNAPSHOT</version>
<name>markdown2flashcards</name>
<url>http://linformatik.de</url>

  • modelVersion: Version des POM-Modells (hier immer 4.0.0).
  • groupId: Eindeutiger Bezeichner für die Gruppe oder das Unternehmen, das das Projekt verwaltet. Hier ist es de.linformatik.
  • artifactId: Der Name des Projekts oder Artefakts, in diesem Fall markdown2flashcards.
  • version: Die Version des Projekts. 1.0-SNAPSHOT deutet darauf hin, dass dies eine Entwicklungsversion ist.
  • name: Der Name des Projekts.
  • url: Eine URL, die mehr Informationen über das Projekt bereitstellt.

3. Properties

xmlKopierenBearbeiten<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
</properties>

  • project.build.sourceEncoding: Stellt sicher, dass der Quellcode mit der UTF-8-Zeichenkodierung verarbeitet wird.
  • maven.compiler.source und maven.compiler.target: Geben an, dass der Code mit Java 21 kompiliert werden soll.

4. Abhängigkeiten

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>

  • Hier wird eine Abhängigkeit von JUnit (Version 4.11) für das Testen des Projekts definiert. Das scope-Tag gibt an, dass diese Abhängigkeit nur für die Testphase benötigt wird.

5. Build-Abschnitt

Der build-Abschnitt enthält Plugins, die das Verhalten von Maven beim Erstellen des Projekts steuern. Hier sind einige wichtige Plugins, die in der Konfiguration definiert sind:

a. Maven Compiler Plugin

xmlKopierenBearbeiten<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
    <configuration>
        <source>21</source>
        <target>21</target>
    </configuration>
</plugin>

  • Dieses Plugin stellt sicher, dass der Java-Quellcode mit der Version 21 des JDK kompiliert wird.

b. Maven Jar Plugin

xmlKopierenBearbeiten<plugin>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.0.2</version>
    <configuration>
        <archive>
            <manifest>
                <mainClass>de.linformatik.App</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

  • Erzeugt eine JAR-Datei und legt die Hauptklasse (de.linformatik.App) fest, die beim Ausführen der JAR-Datei gestartet wird.

c. Maven Clean Plugin

xmlKopierenBearbeiten<plugin>
    <artifactId>maven-clean-plugin</artifactId>
    <version>3.1.0</version>
</plugin>

  • Dieses Plugin sorgt dafür, dass das Projekt bei jedem Build-Befehl sauber gemacht wird, also alle vorherigen Artefakte gelöscht werden.

d. Maven Resources Plugin

xmlKopierenBearbeiten<plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <version>3.0.2</version>
</plugin>

  • Kopiert Ressourcen (wie Konfigurationsdateien) aus dem Quellverzeichnis in das Zielverzeichnis.

e. Maven Surefire Plugin

xmlKopierenBearbeiten<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.1</version>
</plugin>

  • Dieses Plugin führt die Tests (z. B. JUnit-Tests) während des Build-Prozesses aus.

f. Maven Install Plugin

xmlKopierenBearbeiten<plugin>
    <artifactId>maven-install-plugin</artifactId>
    <version>2.5.2</version>
</plugin>

  • Dieses Plugin installiert die erzeugten Artefakte in das lokale Maven-Repository.

g. Maven Deploy Plugin

xmlKopierenBearbeiten<plugin>
    <artifactId>maven-deploy-plugin</artifactId>
    <version>2.8.2</version>
</plugin>

  • Hiermit können Artefakte in ein zentrales Repository bereitgestellt werden.

h. Maven Site Plugin

<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>

  • Erzeugt eine Website für das Projekt, die häufig Projektinformationen, Dokumentationen und Berichte enthält.

i. Maven Project Info Reports Plugin

xmlKopierenBearbeiten<plugin>
    <artifactId>maven-project-info-reports-plugin</artifactId>
    <version>3.0.0</version>
</plugin>

  • Generiert Berichte über das Projekt, wie z. B. Abhängigkeiten, Lizenzinformationen und mehr.

Fazit

Diese pom.xml-Datei definiert ein Java-Projekt mit den folgenden Kernmerkmalen:

  • Das Projekt verwendet Java 21.
  • Es enthält eine Test-Abhängigkeit (JUnit 4.11).
  • Mehrere Maven-Plugins sind konfiguriert, um das Projekt zu kompilieren, zu testen, zu bereinigen, zu erstellen und zu veröffentlichen.
  • Eine Hauptklasse (de.linformatik.App) wird in das JAR-Manifest eingebaut.

Das Ziel dieser Datei ist es, den Build-Prozess zu automatisieren und die Verwaltung des Projekts und seiner Abhängigkeiten zu vereinfachen.

Anwendung kompilieren und ausführbare JAR-Datei erstellen – Build und Tests ausführen

Um das gesamte Projekt zu bauen und alle Tests auszuführen, kannst du den folgenden Befehl verwenden:

mvn clean install

JAR-Datei ausführen

Unter markdown2flashcards\target liegt jetzt die markdown2flashcards-1.0-SNAPSHOT.jar, welche mit dem Befehl

java -jar .\markdown2flashcards-1.0-SNAPSHOT.jar

ausgeführt werden kann.

In der Ausgabe erscheint jetzt der Text „Hallo World!“, d.h. das Grundgerüst der Anwendung wurde erfolgreich ausgeführt,

die Anwendung kann jetzt Stück für Stück erweitert werden.

JAR Datei per Doppelklick ausführen

Mit der start.bat kann die Anwednung per Doppelklick ausgeführt werden:

@echo off
java -jar "J:\Meine Ablage\develop\markdown2flashcards\target\markdown2flashcards-1.0-SNAPSHOT.jar"
pause

Powershell Script für die Einrichtung des GIT-Projekts

# PowerShell-Skript zum Initialisieren eines Git-Repositories und ersten Commit durchführen

# Überprüfen, ob Git installiert ist
$gitInstalled = Get-Command git -ErrorAction SilentlyContinue
if (-not $gitInstalled) {
    Write-Host "Git ist nicht installiert. Bitte installiere Git und versuche es erneut."
    exit
}

# Benutzer nach dem Verzeichnis fragen
$projectDir = Read-Host "Gib den Pfad zum Projektverzeichnis ein"

# Überprüfen, ob das Verzeichnis existiert
if (-not (Test-Path -Path $projectDir)) {
    Write-Host "Das angegebene Verzeichnis existiert nicht. Bitte überprüfe den Pfad."
    exit
}

# Git-Nutzername und E-Mail-Adresse setzen
$name = Read-Host "Salvatore Spadaro"
$email = Read-Host "salvatore.spadaro@gmail.com"

# Git-Konfiguration für Benutzername und E-Mail setzen
git config user.name $name
git config user.email $email

# Zum Projektverzeichnis wechseln
Set-Location -Path $projectDir

# Git-Repository initialisieren
Write-Host "Initialisiere Git-Repository..."
git init

# Dateien zum Git-Repository hinzufügen
Write-Host "Füge Dateien zum Repository hinzu..."
git add .

# Ersten Commit durchführen
$commitMessage = "Initial commit"
Write-Host "Führe ersten Commit durch..."
git commit -m $commitMessage

Write-Host "Git-Repository wurde erfolgreich initialisiert und der erste Commit wurde durchgeführt."
Write-Host "Dein Name und deine E-Mail-Adresse wurden für Git konfiguriert."



Angriffe auf Layer 3: Border Gateway Protocol (BGP)

  • BGP wird zwischen Autonomen Systemen verwendet.
  • Die Longest Prefix Matching-Regel besagt, dass bei Routingentscheidungen mit mehreren passenden Netzen das Netz mit dem spezifischeren Eintrag (längerer Netzanteil) bevorzugt wird.

BGP-Schwachstellen

  • absichtliche oder unabsichtliche Announcierungen (Bekanntgabe von IT-Adressbereichen) möglich, bspw. Pakistan Youtube-Fall in 2008
  • durch Fehlkonfiguration können Routing-Probleme entstehen oder Angriffe ermöglichen
  • es gibt Vorschläge zur Absicherung von BGP bspw. per Secure-BGP oder PKI, diese wurden jedoch Stand März 2024 noch nicht implementiert



Angriff-Szenarien aus dem Internet

Typische Angriffsarten auf den Schichten 1 und 2 sind beispielsweise ARP Spoofing. Auf Schicht 3 sind typische Angriffsarten mit dem Border Gateway Protocol verbunden. Schicht 4-Angriffe umfassen Spoofed Scans, Denial-of-Service-Attacken (DoS), Distributed Denial-of-Service-Attacken (DDoS) und HTTP-bezogene Angriffe. Auf höheren Schichten, wie Schicht 5 bis 7, sind typische Angriffe wie SQL Injection, Cross-Site Scripting und DNS-Manipulation üblich. Diese Angriffe werden oft mit speziellen Angriffswerkzeugen durchgeführt.

Angriffe auf LANs per ARP-Spoofing

Eine eingehendere Untersuchung ist erforderlich, um die Angriffsmöglichkeiten auf der Sicherungsschicht zu verstehen. Hierbei ist es wichtig, zwischen verschiedenen Umgebungen zu differenzieren:

  • Lokalen Festnetzen (LANs), die in der Regel mit Ethernet realisiert werden.
  • Drahtlosen lokalen Netzen (WLANs).
  • Drahtlosen Personal Area Networks (Bluetooth, RFID).
  • Mobilfunkkommunikationsnetzen (GSM, UMTS, LTE, 5G).

Das ARP Spoofing, das im Folgenden vorgestellt wird, ist eine Angriffstechnik, die auf lokalen Festnetzen angewendet wird.

  • Angreifer gibt sich als Router aus und probiert die Kommunikation abzuhören
  • Angreifer sendet jeweils einen ARP-Replay (Antwort) an das Endgerät und den Router, obwohl kein ARP-Request angefordert wurde
  • der Router sendet die Daten an den Angreifer
  • der Angreifer leitet die Anfrage an den Nutzer weiter

Das Zielsystem erfährt eine fehlerhafte Zuordnung von IP-Adressen zu MAC-Adressen. Dabei sendet der Angreifer in einem ARP-Antwortpaket seine eigene MAC-Adresse in Verbindung mit einer anderen IP-Adresse mit.

Wie kann man sich vor dem ARP-Spoofing schützten?

  • Schutz gegen ARP-Spoofing ist aufwendig
  • Opfer kann gefälschte ARP-Replays nicht erkennen
  • ARP-Requests können nur auf dem Switch geprüft werden

Angriffe auf WLANs

Was ist der Promiscuous mode?

  • Die Netzwerkkarte zeigt nicht nur die üblichen Datenrahmen an, die für den Empfänger bestimmt sind, sondern macht alle sichtbar.

Was macht Bluetooth-Geräte gegenüber Angriffen anfällig?

  • Es ist geplant, eine PIN als zusätzlichen Parameter in das Verschlüsselungsverfahren einzubeziehen. Allerdings bieten viele Bluetooth-Geräte, wie beispielsweise Headsets, keine Möglichkeit, die PIN zu ändern. Daher bleibt die PIN standardmäßig auf den Werkseinstellungen unverändert.
  • Im Bereich von Bluetooth besteht möglicherweise die Möglichkeit, sämtliche Session Keys auszuprobieren.

Mobilfunk-Verschlüsselung

  • Die Übertragung zwischen den Endgeräten und der Basisstation wird verschlüsselt.



Was versteht man unter OSI-Schichtenmodell, Internet-Modell und Hybrides Modell?

Ein Schichtenmodell ist ein Konzept, das in der Informatik und insbesondere in der Netzwerktechnologie verwendet wird, um komplexe Systeme in überschaubare und hierarchische Schichten zu unterteilen. Diese Schichten stellen verschiedene Funktionen bereit und kommunizieren miteinander gemäß bestimmten Standards und Protokollen. Das Ziel eines Schichtenmodells ist es, die Komplexität zu reduzieren, die Interoperabilität zu verbessern und die Wartbarkeit von Systemen zu erleichtern.

Ein bekanntes Beispiel für ein Schichtenmodell ist das OSI-Modell (Open Systems Interconnection Model), das aus sieben Schichten besteht:

  1. Physikalische Schicht: Definiert die physische Verbindung zwischen den Geräten und die Übertragung von Rohdaten über verschiedene Medien.
  2. Sicherungsschicht (Data Link Layer): Verwaltet den Zugriff auf das physische Medium und stellt sicher, dass die Daten fehlerfrei übertragen werden.
  3. Vermittlungsschicht (Network Layer): Ermöglicht die Weiterleitung von Datenpaketen über verschiedene Netzwerke und Routen.
  4. Transportschicht (Transport Layer): Verantwortlich für die Zuverlässigkeit der Kommunikation und stellt sicher, dass die Daten in der richtigen Reihenfolge ankommen.
  5. Sitzungsschicht (Session Layer): Ermöglicht die Einrichtung, Aufrechterhaltung und Beendigung von Sitzungen zwischen Anwendungen.
  6. Darstellungsschicht (Presentation Layer): Kümmert sich um die Darstellung und das Format der Daten, um sicherzustellen, dass verschiedene Systeme miteinander kommunizieren können. Beinhaltet auch Datenkompression und Verschlüsselung.
  7. Anwendungsschicht: Bietet Schnittstellen für Anwendungen und Dienste, die auf die Netzwerkinfrastruktur zugreifen. Beispiele E-Mail, WWW.

Ein weiteres häufig verwendetes Schichtenmodell ist das TCP/IP-Modell, das aus vier Schichten besteht und eng mit dem Internetprotokoll (IP) verbunden ist.

Schichtenmodelle bieten eine abstrakte Darstellung der Kommunikation zwischen verschiedenen Systemen und ermöglichen es, komplexe Netzwerke in einfachere und leichter verständliche Teile zu zerlegen.

Unter einem Protokoll im Schichtenmodell versteht man in der Regel die erste Option: „eine Festlegung von Regeln der Kommunikation zwischen Implementierungen einer Schicht auf verschiedenen Systemen“.

In einem Schichtenmodell wie dem OSI-Modell oder dem TCP/IP-Modell wird die Kommunikation zwischen verschiedenen Netzwerkkomponenten in verschiedene Schichten aufgeteilt. Jede Schicht hat ihre eigenen spezifischen Funktionen und Aufgaben. Ein Protokoll definiert die Regeln und Verfahren, nach denen die Kommunikation zwischen den Implementierungen einer bestimmten Schicht auf verschiedenen Systemen erfolgt. Diese Regeln können beispielsweise das Format von Datenpaketen, die Übertragungsgeschwindigkeit, Fehlerkorrekturmechanismen und andere Aspekte der Kommunikation umfassen. Es legt also fest, wie die Daten zwischen den Systemen ausgetauscht werden, um sicherzustellen, dass die Kommunikation reibungslos verläuft und die Informationen korrekt übertragen werden.

Internet-Modell

Das OSI-Modell ist teilweise zu detailliert, deshalb wurde das Vereinfachte Internet-Modell eingeführt.

Im Internet-Modell wurden die Schichten 5 bis 7 des OSI-Modells zu einer einzigen Anwendungsschicht zusammengeführt. Im Gegensatz zum OSI-Modell legt das Internet-Modell weniger Wert auf eine ausführliche Schichtung, sondern betont vor allem die effiziente Nutzung der etablierten Protokolle wie IP und TCP/UDP, die eng mit diesem Modell verbunden sind.

Hybrides-Modell

  • Kombiniert die Modelle OSI-Schichtenmodell und Internet-Modell
  • besteht aus 5 Schichten
  • bietet guten Praxisbezug
  • Enthält die Trennung der Schichten 1 und 2
  • fasst Schichten 5-7 zusammen



Wie lasse ich mir in der bash offene Ports anzeigen?

netstat

Dieser Befehl zeigt eine Liste der offenen TCP- und UDP-Ports an, zusammen mit den zugehörigen Diensten und den Zuständen der Ports. Die Optionen haben folgende Bedeutung:

  • -t: Zeige TCP-Ports.
  • -u: Zeige UDP-Ports.
  • -l: Zeige nur lauschende Ports.
  • -n: Zeige numerische Portnummern und IP-Adressen anstelle von Dienstnamen und Hostnamen.

ss

Ähnlich wie netstat, zeigt ss die Zustände aller TCP- und UDP-Ports an. Die Optionen sind:

  • -t: Zeige nur TCP-Ports.
  • -u: Zeige nur UDP-Ports.
  • -l: Zeige nur lauschende Ports.
  • -n: Zeige numerische Portnummern und IP-Adressen.

lsof

lsof steht für „list open files“ und kann auch verwendet werden, um offene Netzwerkverbindungen und Ports anzuzeigen. Die Option -i filtert die Anzeige auf Netzwerkverbindungen.

nmap

nmap ist ein mächtiges Netzwerk-Scanning-Tool. Hier wird es verwendet, um offene Ports auf dem lokalen Rechner zu überprüfen. Du kannst auch andere IP-Adressen oder Hostnamen anstelle von localhost verwenden.

Wähle den Befehl aus, der am besten zu deinen Anforderungen passt, und führe ihn in der Bash-Shell aus. Beachte, dass einige dieser Befehle Administratorrechte erfordern, also führe sie möglicherweise mit sudo au

Quelle: https://wissen-tauschen.de/books/linux/page/wie-lasse-ich-mir-in-der-bash-offene-ports-anzeigen




Strato vServer reparieren lassen, falls man sich mit einer Firewall Konfiguration bspw. IPtables ausgesperrt hat

Welcher Admin kennt es nicht, man konfiguriert die Firewall neu, denkt nichts böses und zack, hat man sich ausgesperrt.

Bei Strato kann man den Server über das Kundenportal neu starten/initialisieren, falls man sich bspw. per SSH nicht mehr am Server einloggen kann.

Starto vServer mit RecoveryManager neu starten




WordPress mit Plesk aktualisieren

Was ist überhaupt Plesk?

Plesk ist eine kommerzielle Webanwendung, mit der sich Dienste eines Servers bspw. gemietete vServer von Strato oder anderen Providern, einfach verwalten lassen. Mit Plesk lassen sich Internet-Seiten, Anwendungen, Datenbanken, User etc. einrichten und bspw. WordPress Updates einspielen. Die Prozesse sind teils voll automatisiert, wenn bspw. eine neue Domain eingerichtet wird, wird der vHost Eintrag im Apache-Webserver und die Konfiguration automatisch erstellt.

1.) WordPress aktualisieren

Im Menü „Anwendungen“ lässt sich bspw. die WordPress Anwendung aktualisieren

2.) Automatische Updates für WordPress aktivieren

Mit einem Klick auf den WordPress Eintrag, kann man unter „Automatische Updates“, WordPress automatisch aktualisieren lassen.




Wiki mit Bookstack und Docker-Compose einrichten

Mit Docker Compose lassen sich Docker Container quasi anhand eines Bauplans automatisiert ausführen, die Docker Compose Datei wird im YAML Format gespeichert.

Bookstack ist ein Wiki System, in dem man Texte innerhalb virteller Regale und Bücher speichern und durchsuchen kann.

Los gehts:

1. Docker Compose File anlegen

nano bookstack-docker-compose.yaml


version: '3'

services:
  mariadb:
    image: mariadb
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: xxxxxxxxxxxxxxxxxx
      MYSQL_DATABASE: bookstack
      MYSQL_USER: bookstack_user
      MYSQL_PASSWORD: qcpassed
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - mariadb_data:/var/lib/mysql
      - ./mariadb-init:/docker-entrypoint-initdb.d
      - /DEVELOP/_DOCKER/mariadb-config/my.cnf:/etc/mysql/my.cnf
    ports:
      - "3307:3306"  # Port 3306 nach außen veröffentlichen

  bookstack:
    image: linuxserver/bookstack
    restart: always
    environment:
      DB_HOST: mariadb
      DB_DATABASE: bookstack
      DB_USERNAME: bookstack_user
      DB_PASSWORD: xxxxxxxxxxxxxxxxxx
      APP_URL: http://10.0.0.5:6875   # Ändere dies auf die IP-Adresse und den gewünschten Port
    ports:
      - "6875:80"  # You can change the port if needed
    depends_on:
      - mariadb

volumes:
  mariadb_data:
    driver: local

2. Verzeichnisse erstellen

mkdir mariadb-config

mkdir mariadb-data

mkdir mariadb-init

3. MariaDB Configuration für Docker kopieren

cp /etc/mysql/my.cnf /Docker_zielverzeichnis

4. SQL Script für Datenbank Erstellung speichern

nano init.sql

CREATE DATABASE IF NOT EXISTS bookstack;
GRANT ALL ON bookstack.* TO 'bookstack_user'@'%' IDENTIFIED BY 'mein password xxxxxxxxxxxx';
FLUSH PRIVILEGES;

5. URL im Reverse Proxy Nginx eintragen

nano /etc/nginx/sites-available/develop

 location /bookstack {
        proxy_pass http://10.0.0.5:6875;  # Ändere dies auf die IP-Adresse und den Port von BookStack
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

6. Docker Container erstellen lassen und ausführen

docker-compose -f bookstack-docker-compose.yaml up -d

7. Bookstack aufrufen, anmelden und Standart Zugangsdaten ändern

Auf meinem Testserver gebe ich http://10.0.0.5/bookstack im Browser ein

Mit den Standart-Zugangsdaten anmelden:

Anmeldename: admin@admin.com

Passwort: password

Unter „Mein Account“ sollte man das Passwort umgehend ändern.

Herzlichen Glückwunsch, wenn du soweit gekommen bist, wurde Bookstack korrekt eingerichtet.




Logo in Mediawiki anpassen

1.) neues Logo bspw. per SCP hochladen hochladen

In meinem Mediawiki sind die Logos unter diesem Pfad gespeichert:

/var/www/vhosts/wissen-tauschen.de/httpdocs/resources/assets

2.) Pfad (URI) des neu hochgeladenen Bildes in der LocalSettings.php anpassen

3.) in der LocalSettings.php nach „logo“ suchen, Pfad anpassen und speichern

4.) Kontrolle des neuen Logos