Coding Stube
← Alle Projekte

Lernprojekt · 21.07.2026

Metin2 Quiz

Ein Quiz für das Online MMORPG "Metin2" im Rahmen meiner Umschulung

  • Java
  • Servlets
  • HTML
  • CSS
  • Apache Tomcat
Quiz

Highlights

  • Erste größere Anwendung mit Servlets und einem Apache Tomcat Server

Im Rahmen meiner Umschulung habe ich ein webbasiertes Quizsystem entwickelt, bei dem verschiedene Eingabeformen serverseitig verarbeitet und ausgewertet werden. Ziel des Projekts war es, den Umgang mit HTML-Formularen sowie die Verarbeitung von HTTP-Anfragen mittels Java Servlets praktisch kennenzulernen.

Das Quiz besteht aus zehn Fragen unterschiedlicher Typen. Nach dem Absenden werden die Antworten automatisch ausgewertet und der Benutzer erhält eine detaillierte Übersicht seiner Ergebnisse. Neben der erreichten Punktzahl werden auch die korrekten Lösungen angezeigt, wodurch sich das Quiz beliebig oft wiederholen lässt.

Umgesetzte Funktionen

  • Entwicklung eines webbasierten Quizsystems mit zehn Fragen
  • Verarbeitung verschiedener Formularelemente wie Textfelder, Checkboxen, Auswahlfelder und Radio-Buttons
  • Serverseitige Validierung und Auswertung der Benutzereingaben
  • Automatische Berechnung der erreichten Punktzahl
  • Dynamische Generierung der Ergebnisseite mittels Java Servlets
  • Anzeige der korrekten Antworten zur direkten Lernkontrolle
  • Unterstützung unterschiedlicher Antwortmöglichkeiten und Eingabeformate
  • Erneute Durchführung des Quiz über eine Rücksprungfunktion

Der Source-Code

Auch bei diesem Projekt kann man vieles besser gestalten und schöner Lösen, aber um meine Fortschritte und den Lernprozess besser darzustellen werde ich auch für dieses Projekt den Source-Code hier zur Verfügung stellen

Quiz-Auswertung

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Metin2 - Quiz</title>
</head>
<body>
<center>
    <h1>Metin2 Quiz</h1>
    <h3>Beantworte alle Fragen nach eigenem Kentnissstand</h3>
    <form action="metin-quiz-result" method="get">
        <fieldset style="width: 800px; text-align: center">
            <legend>Was ist das ehemalige Maximal-Level aus 2014</legend>
            <label for="maxLevel"></label>
            <input type="number" name="maxLevel" id="maxLevel" placeholder="1-120" min="1" max="120" required>
        </fieldset><br><br>
        <fieldset style="width: 800px; text-align: center">
            <legend>Wie heißt das Level 30 Schwert, in welches Durchschnitsschaden geswitcht werden kann (Voller Name oder Abkürzung)</legend>
            <label for="avgSword"></label>
            <input type="text" name="avgSword" id="avgSword" placeholder="Waffenname.." required>
        </fieldset><br><br>
        <fieldset style="width: 800px; text-align: center">
            <legend>Welche der folgenden Waffen gibt es wirklich?</legend>
            <label for="weapon1"></label>
            <input type="checkbox" name="weaponsExists" id="weapon1" value="Halbmondschwert">Halbmondschwert<br>
            <label for="weapon2"></label>
            <input type="checkbox" name="weaponsExists" id="weapon2" value="Rasiermesser"> Rasiermesser<br>
            <label for="weapon3"></label>
            <input type="checkbox" name="weaponsExists" id="weapon3" value="Dämonenschwert"> Dämonenschwert<br>
            <label for="weapon4"></label>
            <input type="checkbox" name="weaponsExists" id="weapon4" value="Schwert"> Schwert<br>
            <label for="weapon5"></label>
            <input type="checkbox" name="weaponsExists" id="weapon5" value="Dolch"> Dolch<br>
        </fieldset><br><br>
        <fieldset style="width: 800px; text-align: center">
            <legend>Welche Klasse profitiert von allen 4 Statuswerten am Meisten?</legend>
            <label for="sura"></label>
            <select name="sura" id="sura" required>
                <option value="Sura">Sura</option>
                <option value="Krieger">Krieger</option>
                <option value="Ninja">Ninja</option>
                <option value="Schamane">Schamane</option>
            </select>
        </fieldset><br><br>
        <fieldset style="width: 800px; text-align: center">
            <legend>Ein Ninja benötigt das Hauptattribut Beweglichkeit. Richtig?</legend>
            <label for="ninjaTrue"></label>
            <input type="radio" name="ninjaTF" id="ninjaTrue" value="Ja" checked="checked"> Ja<br>
            <label for="ninjaFalse"></label>
            <input type="radio" name="ninjaTF" id="ninjaFalse" value="Nein"> Nein<br>
        </fieldset><br><br>
        <fieldset style="width: 800px; text-align: center">
            <legend>Der Boss "Sensenmann" ist ab welchem Level farmbar?</legend>
            <label for="reaperLevel"></label>
            <input type="number" name="reaperLevel" id="reaperLevel" placeholder="1-120" min="1" max="120" required>
        </fieldset><br><br>
        <fieldset style="width: 800px; text-align: center">
            <legend>Monster und Metinsteine droppen bis einschließlich 15 Level unter dem eigenen Level ihren Loot. Richtig?</legend>
            <label for="dropsTrue"></label>
            <input type="radio" name="dropsPossible" id="dropsTrue" value="Ja" checked="checked"> Ja<br>
            <label for="dropsFalse"></label>
            <input type="radio" name="dropsPossible" id="dropsFalse" value="Nein"> Nein<br>
        </fieldset><br><br>
        <fieldset style="width: 800px; text-align: center">
            <legend>Der Dämonenturm ist ab Level 10 betretbar. Richtig?</legend>
            <label for="dtTrue"></label>
            <input type="radio" name="demonTowerPossible" id="dtTrue" value="Ja" checked="checked"> Ja<br>
            <label for="dtFalse"></label>
            <input type="radio" name="demonTowerPossible" id="dtFalse" value="Nein"> Nein<br>
        </fieldset><br><br>
        <fieldset style="width: 800px; text-align: center">
            <legend>Wie lang ist der Respawntimer der Eishexe? (Zeit in Minuten)</legend>
            <label for="respawnTimer"></label>
            <input type="number" name="respawnTimer" id="respawnTimer" placeholder="1-120" min="1" max="120" required>
        </fieldset><br><br>
        <fieldset style="width: 800px; text-align: center">
            <legend>Wie heißt die Währung die man ab 100.000.000 Yang erhalten kann</legend>
            <label for="currencyName"></label>
            <input type="text" name="currencyName" id="currencyName" placeholder="Währung.." required>
        </fieldset><br>
        <input type="submit">
    </form>
</center>
</body>
</html>
package dev.jjk;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@WebServlet("/metin-quiz-result")
public class Quiz extends HttpServlet {

    private final List<String> weapons = new ArrayList<>(Arrays.asList("Halbmondschwert", "Schwert", "Dolch"));

    private boolean doesWeaponsExist(String[] weaponList) {
        Set<String> selectedWeapons = new HashSet<>(Arrays.asList(weaponList));
        if(selectedWeapons.size() != weapons.size()) {
            return false;
        }

        return selectedWeapons.containsAll(weapons);
    }

    @Override
    protected void doGet(
            HttpServletRequest request,
            HttpServletResponse response
    ) throws ServletException, IOException {

        int correctAnswers = 0;
        String question;
        String answer;
        String wrongAnswer = "Deine Antwort: %s<br> Richtige Antwort: %s";
        String rightAnswer = "Deine Antwort war Richtig!<br>Antwort: %s";
        String maxLevel = request.getParameter("maxLevel");
        String avgSword = request.getParameter("avgSword");
        String[] weaponsExists = request.getParameterValues("weaponsExists");
        String weaponsExistMsg;
        String sura = request.getParameter("sura");
        String ninjaTF = request.getParameter("ninjaTF");
        String reaperLevel = request.getParameter("reaperLevel");
        String dropsPossible = request.getParameter("dropsPossible");
        String demonTowerPossible = request.getParameter("demonTowerPossible");
        String respawnTimer = request.getParameter("respawnTimer");
        String currencyName = request.getParameter("currencyName");

        if(maxLevel.equalsIgnoreCase("105")) {
            correctAnswers++;
            answer = String.format(rightAnswer, maxLevel);
            question = "Was ist das ehemalige Maximal-Level aus 2014";
            maxLevel = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green; text-alignment:left">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            question = "Was ist das ehemalige Maximal-Level aus 2014";
            answer = String.format(wrongAnswer, maxLevel, "105");
            maxLevel = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        if(avgSword.equalsIgnoreCase("VMS") || avgSword.equalsIgnoreCase("Vollmondschwert")) {
            correctAnswers++;
            answer = String.format(rightAnswer, avgSword);
            question = "Wie heißt das Level 30 Schwert, in welches Durchschnitsschaden geswitcht werden kann (Voller Name oder Abkürzung)";
            avgSword = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            answer = String.format(wrongAnswer, avgSword, "VMS / Vollmondschwert");
            question = "Wie heißt das Level 30 Schwert, in welches Durchschnitsschaden geswitcht werden kann (Voller Name oder Abkürzung)";
            avgSword = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        if(weaponsExists != null && doesWeaponsExist(weaponsExists)) {
            correctAnswers++;
            StringBuilder sb = new StringBuilder();
            for(String s : weaponsExists) {
                sb.append(s).append(", ");
            }
            answer = String.format(rightAnswer, sb);
            question = "Welche der folgenden Waffen gibt es wirklich?";
            weaponsExistMsg = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            String selectedWeapons = weaponsExists == null ? "Keine Antwort" : String.join(", ", weaponsExists);
            answer = String.format(wrongAnswer, selectedWeapons, "Halbmondschwert, Schwert, Dolch");
            question = "Welche der folgenden Waffen gibt es wirklich?";
            weaponsExistMsg = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        if(sura.equalsIgnoreCase("Sura")) {
            correctAnswers++;
            answer = String.format(rightAnswer, sura);
            question = "Welche Klasse profitiert von allen 4 Statuswerten am Meisten?";
            sura = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            answer = String.format(wrongAnswer, sura, "Sura");
            question = "Welche Klasse profitiert von allen 4 Statuswerten am Meisten?";
            sura = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        if(ninjaTF.equalsIgnoreCase("Ja")) {
            correctAnswers++;
            answer = String.format(rightAnswer, ninjaTF);
            question = "Ein Ninja benötigt das Hauptattribut Beweglichkeit. Richtig?";
            ninjaTF = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            answer = String.format(wrongAnswer, ninjaTF, "Ja");
            question = "Ein Ninja benötigt das Hauptattribut Beweglichkeit. Richtig?";
            ninjaTF = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        if(reaperLevel.equalsIgnoreCase("75")) {
            correctAnswers++;
            answer = String.format(rightAnswer, reaperLevel);
            question = "Der Boss \"Sensenmann\" ist ab welchem Level farmbar?";
            reaperLevel = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            answer = String.format(wrongAnswer, reaperLevel, "75");
            question = "Der Boss \"Sensenmann\" ist ab welchem Level farmbar?";
            reaperLevel = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        if(dropsPossible.equalsIgnoreCase("Ja")) {
            correctAnswers++;
            answer = String.format(rightAnswer, dropsPossible);
            question = "Monster und Metinsteine droppen bis einschließlich 15 Level unter dem eigenen Level ihren Loot. Richtig?";
            dropsPossible = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            answer = String.format(wrongAnswer, dropsPossible, "Ja");
            question = "Monster und Metinsteine droppen bis einschließlich 15 Level unter dem eigenen Level ihren Loot. Richtig?";
            dropsPossible = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        if(demonTowerPossible.equalsIgnoreCase("Ja")) {
            correctAnswers++;
            answer = String.format(rightAnswer, demonTowerPossible);
            question = "Der Dämonenturm ist ab Level 10 betretbar. Richtig?";
            demonTowerPossible = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            answer = String.format(wrongAnswer, demonTowerPossible, "Ja");
            question = "Der Dämonenturm ist ab Level 10 betretbar. Richtig?";
            demonTowerPossible = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        if(respawnTimer.equalsIgnoreCase("60")) {
            correctAnswers++;
            answer = String.format(rightAnswer, respawnTimer);
            question = "Wie lang ist der Respawntimer der Eishexe?";
            respawnTimer = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            answer = String.format(wrongAnswer, respawnTimer, "60 Minuten");
            question = "Wie lang ist der Respawntimer der Eishexe?";
            respawnTimer = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        if(currencyName.equalsIgnoreCase("Won")) {
            correctAnswers++;
            answer = String.format(rightAnswer, currencyName);
            question = "Wie heißt die Währung die man ab 100.000.000 Yang erhalten kann?";
            currencyName = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: green">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        } else {
            answer = String.format(wrongAnswer, currencyName, "Won");
            question = "Wie heißt die Währung die man ab 100.000.000 Yang erhalten kann?";
            currencyName = """
                    <fieldset style="width: 800px">
                    <legend>%s</legend>
                    <div style="color: red">%s</div>
                    </fieldset>
                    """.formatted(question, answer);
        }

        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");

        PrintWriter out = response.getWriter();

        out.println("""
        <!doctype html>
        <html lang="de">
        <head>
            <meta charset="UTF-8">
            <title>Quiz Auswertung</title>
        </head>
        <body>
            <center>
            <h1>Auswertung deines Quizes</h1>
            <h2>Du hast %s von 10 Fragen richtig beantwortet!</h2>
            %s<br>
            %s<br>
            %s<br>
            %s<br>
            %s<br>
            %s<br>
            %s<br>
            %s<br>
            %s<br>
            %s<br>
            <a href="metin2.html">Zurück zum Quiz</a>
            </center>
        </body>
        </html>
       \s""".formatted(correctAnswers, maxLevel, avgSword, weaponsExistMsg, sura, ninjaTF, reaperLevel, dropsPossible, demonTowerPossible, respawnTimer, currencyName));
    }

}