Java Web Basic – Tag 6 von 10
Von Elyndra Valen, Senior Developer bei Java Fleet Systems Consulting

🗺️ Deine Position im Kurs
| Tag | Thema | Status |
|---|---|---|
| 1 | Java EE Überblick & HTTP | ✅ Abgeschlossen |
| 2 | HTTP-Protokoll Vertiefung & Zustandslosigkeit | ✅ Abgeschlossen |
| 3 | Servlets & Servlet API | ✅ Abgeschlossen |
| 4 | Deployment Descriptor & MVC vs Model 2 | ✅ Abgeschlossen |
| 5 | JSP & Expression Languages | ✅ Abgeschlossen |
| → 6 | Java Beans, Actions, Scopes & Direktiven | 👉 DU BIST HIER! |
| 7 | Include-Action vs Include-Direktive | 📜 Kommt als nächstes |
| 8 | JSTL – Java Standard Tag Libraries | 🔒 Noch nicht freigeschaltet |
| 9 | Java Web und Datenbanken – Datasource | 🔒 Noch nicht freigeschaltet |
| 10 | Connection Pools & JDBC in Web-Umgebungen | 🔒 Noch nicht freigeschaltet |
Modul: Java Web Basic
Gesamt-Dauer: 10 Arbeitstage (je 8 Stunden)
Dein Ziel: JavaBeans verstehen, Actions nutzen und Scopes meistern
📋 Voraussetzungen für diesen Tag
Du brauchst:
- ✅ JDK 21 LTS installiert
- ✅ Apache NetBeans 22 (oder neuer)
- ✅ Payara Server 6.x konfiguriert
- ✅ Tag 1-5 abgeschlossen
- ✅ JSP & Expression Language verstanden
- ✅ MVC/Model 2 Architektur verstanden
- ✅ Implizite Objekte kennen (
${param},${requestScope}, etc.)
Tag verpasst?
Spring zurück zu Tag 5, um JSP und Expression Language zu lernen. Ohne EL wird heute schwer!
Setup-Probleme?
Schreib uns: elyndra.valen@java-developer.online
⚡ Das Wichtigste in 30 Sekunden
Heute lernst du:
- ✅ Was JavaBeans sind und warum sie wichtig sind
- ✅ JavaBeans Konventionen (getter/setter, no-arg constructor)
- ✅ JSP Standard Actions (
<jsp:useBean>,<jsp:setProperty>,<jsp:getProperty>) - ✅ Die 4 Scopes verstehen (page, request, session, application)
- ✅ JSP-Direktiven im Detail (
<%@ page %>,<%@ include %>,<%@ taglib %>) - ✅ Best Practices für saubere Views
Am Ende des Tages kannst du:
- JavaBeans in JSPs verwenden
- Actions richtig einsetzen
- Scopes gezielt nutzen für Daten-Management
- Direktiven konfigurieren
- Saubere, wartbare JSPs schreiben
Zeit-Investment: ~8 Stunden
Schwierigkeitsgrad: Mittel (Konzepte + Praxis!)
👋 Willkommen zu Tag 6!
Hi! 👋
Elyndra hier. Heute wird’s richtig praktisch!
Kurzwiederholung: Challenge von Tag 5
Gestern solltest du eine JSP erstellen, die Produktdaten anzeigt und Expression Language verwendet. Falls du es noch nicht gemacht hast, hier die Musterlösung:
Controller: ProductServlet.java
package com.example.controller;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.util.*;
@WebServlet("/products")
public class ProductServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Simuliere Produktdaten
List<Map<String, Object>> products = new ArrayList<>();
Map<String, Object> product1 = new HashMap<>();
product1.put("id", 1);
product1.put("name", "Laptop");
product1.put("price", 899.99);
products.add(product1);
Map<String, Object> product2 = new HashMap<>();
product2.put("id", 2);
product2.put("name", "Smartphone");
product2.put("price", 599.99);
products.add(product2);
// Setze im Request-Scope
request.setAttribute("products", products);
// Forward zu JSP
request.getRequestDispatcher("/WEB-INF/views/products.jsp")
.forward(request, response);
}
}
View: /WEB-INF/views/products.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Produktliste</title>
</head>
<body>
<h1>Unsere Produkte</h1>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Preis</th>
</tr>
<c:forEach var="product" items="${products}">
<tr>
<td>${product.id}</td>
<td>${product.name}</td>
<td>${product.price} €</td>
</tr>
</c:forEach>
</table>
</body>
</html>
Hast du’s selbst geschafft? Großartig! 🎉
Hattest du Schwierigkeiten? Kein Problem – vergleiche deinen Code mit der Lösung.
Und jetzt geht’s weiter mit Tag 6! 🚀
Warum JavaBeans wichtig sind:
Gestern hast du gelernt, wie man Daten mit Map<String, Object> in JSPs übergibt. Das funktioniert, aber es gibt ein Problem: Maps sind nicht typsicher, unübersichtlich bei vielen Eigenschaften und nicht wiederverwendbar.
JavaBeans lösen dieses Problem elegant. Sie sind wiederverwendbare, typsichere Datencontainer – perfekt für das Model in MVC.
Was dich heute erwartet:
Wir schauen uns an, wie du JavaBeans definierst und in JSPs verwendest. Du lernst die JSP Standard Actions kennen – spezielle Tags, die mit Beans arbeiten. Dann vertiefen wir die verschiedenen Scopes (page, request, session, application) und verstehen, wann du welchen Scope brauchst. Zum Schluss schauen wir uns JSP-Direktiven im Detail an.
Keine Sorge:
JavaBeans klingen kompliziert, sind aber eigentlich nur POJOs (Plain Old Java Objects) mit ein paar Konventionen. Und die Actions? Die machen dein Leben einfacher, nicht schwerer!
Los geht’s! 🔧
🟢 GRUNDLAGEN: JavaBeans verstehen
Was sind JavaBeans?
Definition:
Ein JavaBean ist eine wiederverwendbare Java-Klasse, die bestimmten Konventionen folgt:
- Public class – Die Klasse muss öffentlich sein
- No-arg Constructor – Ein Konstruktor ohne Parameter
- Private properties – Felder sind privat
- Public getter/setter – Zugriff über getter/setter-Methoden
- Serializable – Optional, aber empfohlen
Analogie:
Stell dir vor, ein JavaBean ist wie ein Formular mit Feldern:
- Die Felder sind privat (niemand kann direkt reinschreiben)
- Es gibt Getter (zum Lesen der Felder)
- Es gibt Setter (zum Beschreiben der Felder)
- Das Formular hat eine Standard-Version (no-arg Constructor)
Beispiel: Ein einfaches JavaBean
package com.example.model;
import java.io.Serializable;
public class Product implements Serializable {
// 1. Private properties
private int id;
private String name;
private double price;
private String category;
// 2. No-arg Constructor (PFLICHT!)
public Product() {
// Standard-Werte können hier gesetzt werden
}
// 3. Constructor mit Parametern (optional, aber praktisch)
public Product(int id, String name, double price, String category) {
this.id = id;
this.name = name;
this.price = price;
this.category = category;
}
// 4. Public Getter/Setter
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
// 5. toString() für Debugging (optional, aber hilfreich)
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
", category='" + category + '\'' +
'}';
}
}
Was passiert hier?
privateFelder: Niemand kann direkt aufproduct.pricezugreifen- No-arg Constructor:
new Product()funktioniert - Getter:
product.getPrice()liest den Preis - Setter:
product.setPrice(99.99)setzt den Preis Serializable: Das Bean kann gespeichert/übertragen werden
Warum brauchst du JavaBeans?
Vorteile gegenüber Maps:
// ❌ SCHLECHT: Mit Map
Map<String, Object> product = new HashMap<>();
product.put("name", "Laptop");
product.put("price", 899.99);
// Typen nicht sicher!
// Tippfehler möglich: "priice" statt "price"
// IDE hat keine Auto-Completion
// ✅ GUT: Mit JavaBean
Product product = new Product();
product.setName("Laptop");
product.setPrice(899.99);
// Typsicher!
// IDE gibt Fehler bei Tippfehlern
// Auto-Completion funktioniert
In der Praxis bedeutet das:
- Typsicherheit: Compiler prüft deine Typen
- Lesbarkeit:
product.getName()ist klarer alsproduct.get("name") - Refactoring: Umbenennen funktioniert in der ganzen Codebase
- Dokumentation: Klare Struktur der Daten
- Wiederverwendbarkeit: Beans können überall genutzt werden
Dein erstes JavaBean in einer JSP
Schritt 1: Bean erstellen
Erstelle die Datei src/main/java/com/example/model/User.java:
package com.example.model;
import java.io.Serializable;
public class User implements Serializable {
private String username;
private String email;
private String role;
// No-arg Constructor
public User() {}
// Constructor mit Parametern
public User(String username, String email, String role) {
this.username = username;
this.email = email;
this.role = role;
}
// Getter/Setter
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
Schritt 2: Servlet erstellt User-Bean
Erstelle src/main/java/com/example/controller/UserServlet.java:
package com.example.controller;
import com.example.model.User;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.IOException;
@WebServlet("/user")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// User-Bean erstellen
User user = new User("nova", "nova@java-developer.online", "Developer");
// Im Request-Scope speichern
request.setAttribute("currentUser", user);
// Forward zu JSP
request.getRequestDispatcher("/WEB-INF/views/user.jsp")
.forward(request, response);
}
}
Schritt 3: JSP nutzt Expression Language
Erstelle /WEB-INF/views/user.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>User Profile</title>
</head>
<body>
<h1>User Profile</h1>
<!-- Expression Language greift auf Getter zu! -->
<p>Username: ${currentUser.username}</p>
<p>Email: ${currentUser.email}</p>
<p>Role: ${currentUser.role}</p>
<!-- EL ruft automatisch getUsername(), getEmail(), getRole() auf! -->
</body>
</html>
Was passiert hier?
- Servlet: Erstellt
User-Bean, speichert es im Request-Scope - JSP: Nutzt Expression Language
${currentUser.username} - EL-Magic:
${currentUser.username}ruft automatischcurrentUser.getUsername()auf! - Kein Java-Code in JSP: Die View bleibt sauber!
Teste es:
http://localhost:8080/YourApp/user
Du siehst:
User Profile Username: nova Email: nova@java-developer.online Role: Developer
🟢 GRUNDLAGEN: JSP Standard Actions
Was sind JSP Standard Actions?
Definition:
JSP Standard Actions sind spezielle XML-Tags, die direkt in JSPs verwendet werden können. Sie beginnen mit <jsp:...> und bieten vordefinierte Funktionen für häufige Aufgaben.
Die wichtigsten Actions:
<jsp:useBean>– Bean erstellen oder finden<jsp:setProperty>– Property setzen<jsp:getProperty>– Property auslesen<jsp:include>– Andere Ressource einbinden<jsp:forward>– Zu anderer Ressource weiterleiten
Heute fokussieren wir uns auf die ersten drei – die sogenannten Bean Actions.
<jsp:useBean> – Bean erstellen oder laden
Syntax:
<jsp:useBean id="beanName"
class="package.ClassName"
scope="page|request|session|application" />
Was macht es?
- Sucht im angegebenen Scope nach einem Bean mit dem Namen
beanName - Falls gefunden: Verwendet das existierende Bean
- Falls nicht gefunden: Erstellt neues Bean mit
new ClassName()
Beispiel:
<!-- Erstellt oder findet User-Bean im Request-Scope -->
<jsp:useBean id="user" class="com.example.model.User" scope="request" />
<!-- Jetzt kannst du das Bean verwenden -->
<p>Username: ${user.username}</p>
Wichtig:
id: Name des Beans (entsprichtrequest.getAttribute("user"))class: Vollqualifizierter Klassennamescope: Wo wird das Bean gespeichert? (default:page)
<jsp:setProperty> – Properties setzen
Syntax:
<!-- Einzelne Property setzen --> <jsp:setProperty name="beanName" property="propertyName" value="value" /> <!-- Property aus Request-Parameter setzen --> <jsp:setProperty name="beanName" property="propertyName" /> <!-- ALLE Properties aus Request-Parametern setzen --> <jsp:setProperty name="beanName" property="*" />
Beispiel 1: Manuell setzen
<jsp:useBean id="user" class="com.example.model.User" scope="request" /> <jsp:setProperty name="user" property="username" value="nova" /> <jsp:setProperty name="user" property="email" value="nova@java-developer.online" /> <jsp:setProperty name="user" property="role" value="Developer" />
Beispiel 2: Aus Request-Parameter
<!-- URL: /form.jsp?username=nova&email=nova@java-developer.online --> <jsp:useBean id="user" class="com.example.model.User" scope="request" /> <!-- Setzt alle Properties automatisch aus Request-Parametern --> <jsp:setProperty name="user" property="*" /> <!-- Jetzt ist user.username = "nova", user.email = "nova@java-developer.online" -->
Was passiert bei property="*"?
JSP schaut sich ALLE Request-Parameter an und versucht, sie mit Bean-Properties zu matchen:
- Request-Parameter
username→setUsername()wird aufgerufen - Request-Parameter
email→setEmail()wird aufgerufen - Fehlende Parameter werden ignoriert
<jsp:getProperty> – Properties auslesen
Syntax:
<jsp:getProperty name="beanName" property="propertyName" />
Beispiel:
<jsp:useBean id="user" class="com.example.model.User" scope="request" /> <p>Username: <jsp:getProperty name="user" property="username" /></p> <p>Email: <jsp:getProperty name="user" property="email" /></p>
Aber:
Expression Language ist meistens besser:
<!-- ✅ BESSER: Expression Language -->
<p>Username: ${user.username}</p>
<p>Email: ${user.email}</p>
<!-- ❌ Veraltet: getProperty -->
<p>Username: <jsp:getProperty name="user" property="username" /></p>
Wann <jsp:getProperty> verwenden?
Fast nie! Expression Language ist kürzer, lesbarer und moderner. <jsp:getProperty> ist Legacy-Code aus JSP 1.x-Zeiten.
Komplettes Beispiel: Formular mit Bean Actions
Formular: form.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>User Registration</title>
</head>
<body>
<h1>Register</h1>
<form action="register.jsp" method="post">
<label>Username:</label>
<input type="text" name="username" required /><br/>
<label>Email:</label>
<input type="email" name="email" required /><br/>
<label>Role:</label>
<select name="role">
<option value="User">User</option>
<option value="Developer">Developer</option>
<option value="Admin">Admin</option>
</select><br/>
<button type="submit">Register</button>
</form>
</body>
</html>
Verarbeitung: register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Registration Successful</title>
</head>
<body>
<h1>Registration Successful!</h1>
<!-- Bean erstellen/laden -->
<jsp:useBean id="user" class="com.example.model.User" scope="session" />
<!-- ALLE Properties aus Request-Parametern setzen -->
<jsp:setProperty name="user" property="*" />
<!-- Anzeigen mit Expression Language -->
<p>Welcome, ${user.username}!</p>
<p>Your email: ${user.email}</p>
<p>Your role: ${user.role}</p>
<p><a href="profile.jsp">View Profile</a></p>
</body>
</html>
Profil: profile.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Your Profile</title>
</head>
<body>
<h1>Your Profile</h1>
<!-- Bean aus Session holen -->
<jsp:useBean id="user" class="com.example.model.User" scope="session" />
<!-- Bean existiert bereits in Session - wird wiederverwendet -->
<p>Username: ${user.username}</p>
<p>Email: ${user.email}</p>
<p>Role: ${user.role}</p>
</body>
</html>
Was passiert hier?
- form.jsp: Zeigt Formular
- User gibt Daten ein:
username=nova,email=nova@java-developer.online,role=Developer - register.jsp:
<jsp:useBean>erstellt neuesUser-Bean im Session-Scope<jsp:setProperty property="*">setzt alle Properties aus Request-Parametern- Bean wird in Session gespeichert
- profile.jsp:
<jsp:useBean>findet existierendes Bean in Session- Kein neues Bean wird erstellt!
- Daten sind noch da
🟢 GRUNDLAGEN: Die 4 Scopes verstehen
Was sind Scopes?
Definition:
Scopes definieren die Lebensdauer und Sichtbarkeit von Objekten in einer Webanwendung.
Die 4 Scopes:
| Scope | Lebensdauer | Sichtbarkeit | Use-Case |
|---|---|---|---|
| page | Nur diese JSP | Nur diese JSP | Temporäre Daten für diese Seite |
| request | Ein Request | Alle inkludierten/forwarded JSPs | Daten für einen Request (MVC!) |
| session | Eine User-Session | Alle Requests des Users | User-spezifische Daten (Login, Warenkorb) |
| application | Webapp-Lifetime | Alle User | Globale Daten (Konfiguration, Zähler) |
Page Scope
Lebensdauer: Nur diese JSP-Seite
Java-Code:
pageContext.setAttribute("message", "Hello");
JSP:
<jsp:useBean id="temp" class="com.example.model.User" scope="page" />
Expression Language:
${pageScope.message}
<!-- oder einfach -->
${message}
Wann verwenden?
- Temporäre Variablen nur für diese JSP
- Zwischenergebnisse von Berechnungen
- Loop-Variablen
Beispiel:
<%
// Nur für diese Seite
pageContext.setAttribute("greeting", "Welcome");
%>
<h1>${greeting}</h1>
<!-- Wenn User Seite neu lädt: greeting ist weg -->
Request Scope
Lebensdauer: Ein HTTP-Request (inkl. Forward)
Java-Code:
request.setAttribute("product", product);
request.getRequestDispatcher("/view.jsp").forward(request, response);
JSP:
<jsp:useBean id="product" class="com.example.model.Product" scope="request" />
Expression Language:
${requestScope.product.name}
<!-- oder einfach -->
${product.name}
Wann verwenden?
- MVC Pattern: Controller setzt Daten, View zeigt sie an
- Daten, die nur für diesen Request relevant sind
- Suchergebnisse, Formular-Validierung
Beispiel:
// Servlet
@WebServlet("/search")
public class SearchServlet extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String query = request.getParameter("q");
List<Product> results = searchProducts(query);
// Request-Scope!
request.setAttribute("results", results);
request.setAttribute("query", query);
request.getRequestDispatcher("/WEB-INF/views/results.jsp")
.forward(request, response);
}
}
<!-- results.jsp -->
<h1>Search Results for: ${query}</h1>
<c:forEach var="product" items="${results}">
<p>${product.name} - ${product.price} €</p>
</c:forEach>
<!-- Bei neuem Request: results ist weg -->
Session Scope
Lebensdauer: Eine User-Session (typisch 30 Minuten Inaktivität)
Java-Code:
HttpSession session = request.getSession();
session.setAttribute("user", user);
JSP:
<jsp:useBean id="user" class="com.example.model.User" scope="session" />
Expression Language:
${sessionScope.user.username}
<!-- oder einfach -->
${user.username}
Wann verwenden?
- Login-Daten: Eingeloggter User
- Warenkorb: Shopping Cart
- User-Einstellungen: Sprache, Theme
- Wizard-Daten: Multi-Step-Formulare
Beispiel: Login
// LoginServlet
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = authenticate(username, password);
if (user != null) {
// Session-Scope!
HttpSession session = request.getSession();
session.setAttribute("currentUser", user);
response.sendRedirect("dashboard.jsp");
} else {
response.sendRedirect("login.jsp?error=1");
}
}
}
<!-- dashboard.jsp -->
<jsp:useBean id="currentUser" class="com.example.model.User" scope="session" />
<h1>Welcome, ${currentUser.username}!</h1>
<!-- User bleibt eingeloggt über mehrere Requests -->
Logout:
// LogoutServlet
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate(); // Session löschen!
}
response.sendRedirect("login.jsp");
}
}
Application Scope
Lebensdauer: Gesamte Webapp-Laufzeit
Java-Code:
ServletContext context = request.getServletContext();
context.setAttribute("appName", "My Shop");
JSP:
<jsp:useBean id="config" class="com.example.model.AppConfig" scope="application" />
Expression Language:
${applicationScope.appName}
<!-- oder einfach -->
${appName}
Wann verwenden?
- Konfiguration: Datenbank-URLs, API-Keys (aber NICHT in Production!)
- Globale Zähler: Visitor Counter
- Shared Resources: Connection Pools (sollte aber über JNDI laufen)
- Cache: Oft verwendete Daten
Beispiel: Visitor Counter
// VisitorCounterListener
@WebListener
public class VisitorCounterListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
context.setAttribute("visitorCount", 0);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// Cleanup
}
}
// HomeServlet
@WebServlet("/home")
public class HomeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = getServletContext();
synchronized (context) {
Integer count = (Integer) context.getAttribute("visitorCount");
count++;
context.setAttribute("visitorCount", count);
}
request.getRequestDispatcher("/WEB-INF/views/home.jsp")
.forward(request, response);
}
}
<!-- home.jsp -->
<h1>Welcome!</h1>
<p>Total Visitors: ${applicationScope.visitorCount}</p>
<!-- Zähler gilt für ALLE User! -->
Scope Priority & Lookup
Wichtig:
Expression Language sucht in folgender Reihenfolge:
- Page Scope
- Request Scope
- Session Scope
- Application Scope
Beispiel:
<%
pageContext.setAttribute("data", "page");
request.setAttribute("data", "request");
session.setAttribute("data", "session");
application.setAttribute("data", "application");
%>
<!-- Was wird angezeigt? -->
<p>${data}</p>
<!-- Output: "page" (erster gefundener Wert!) -->
<!-- Explizit angeben: -->
<p>${pageScope.data}</p> <!-- "page" -->
<p>${requestScope.data}</p> <!-- "request" -->
<p>${sessionScope.data}</p> <!-- "session" -->
<p>${applicationScope.data}</p> <!-- "application" -->
Best Practice:
Immer explizit angeben, welchen Scope du meinst:
<!-- ✅ GUT: Explizit -->
<p>Username: ${sessionScope.user.username}</p>
<!-- ❌ OKAY, aber unklar: -->
<p>Username: ${user.username}</p>
🟢 GRUNDLAGEN: JSP-Direktiven im Detail
Was sind JSP-Direktiven?
Definition:
Direktiven sind Anweisungen an den JSP-Container, wie er die JSP-Seite verarbeiten soll. Sie werden zur Compile-Zeit ausgeführt, nicht zur Runtime.
Syntax:
<%@ directive attribute="value" attribute="value" ... %>
Die 3 Direktiven:
<%@ page %>– Seiten-Konfiguration<%@ include %>– Statisches Include (zur Compile-Zeit)<%@ taglib %>– Tag-Library einbinden
<%@ page %> – Seiten-Direktive
Wichtigste Attribute:
<%@ page
contentType="text/html;charset=UTF-8"
language="java"
import="java.util.*, com.example.model.*"
session="true"
errorPage="/error.jsp"
isErrorPage="false"
buffer="8kb"
autoFlush="true"
isThreadSafe="true"
info="My JSP Page"
pageEncoding="UTF-8"
%>
Wichtige Attribute im Detail:
contentType
<!-- HTML --> <%@ page contentType="text/html;charset=UTF-8" %> <!-- JSON --> <%@ page contentType="application/json;charset=UTF-8" %> <!-- XML --> <%@ page contentType="application/xml;charset=UTF-8" %> <!-- Plain Text --> <%@ page contentType="text/plain;charset=UTF-8" %>
import
<!-- Einzelne Klasse --> <%@ page import="com.example.model.User" %> <!-- Mehrere Klassen (Komma-getrennt) --> <%@ page import="java.util.List, java.util.ArrayList, com.example.model.*" %> <!-- Alternative: Mehrere page-Direktiven --> <%@ page import="java.util.List" %> <%@ page import="java.util.ArrayList" %> <%@ page import="com.example.model.User" %>
session
<!-- Session aktivieren (default: true) -->
<%@ page session="true" %>
<!-- Session deaktivieren (für statische Seiten) -->
<%@ page session="false" %>
<!-- Wenn session="false", dann ${sessionScope} nicht verfügbar! -->
errorPage & isErrorPage
Normale Seite:
<%@ page errorPage="/error.jsp" %>
<h1>My Page</h1>
<%
// Wenn hier Exception geworfen wird → automatisch zu error.jsp
int result = 10 / 0; // ArithmeticException!
%>
Error Page:
<%@ page isErrorPage="true" %>
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
</head>
<body>
<h1>Oops! Something went wrong.</h1>
<!-- Implizites "exception" Objekt nur verfügbar, wenn isErrorPage="true" -->
<p>Error: ${exception.message}</p>
<pre>${exception}</pre>
</body>
</html>
Wichtig:
errorPagedefiniert welche Seite bei Fehler aufgerufen wirdisErrorPage="true"macht die Seite zur Error-Page (gibtexceptionObjekt)
buffer & autoFlush
<!-- Buffer-Größe (default: 8kb) --> <%@ page buffer="16kb" %> <!-- Auto-Flush (default: true) --> <%@ page autoFlush="true" %> <!-- Kein Auto-Flush (Output wird gebuffert, kann zu IllegalStateException führen) --> <%@ page autoFlush="false" %>
Was bedeutet das?
- Buffer: Output wird erst gesammelt, dann gesendet
- autoFlush: Bei vollem Buffer automatisch senden
- autoFlush=“false“: Exception, wenn Buffer voll (selten gewünscht!)
<%@ include %> – Include-Direktive
Syntax:
<%@ include file="/path/to/file.jsp" %>
Was macht es?
Inkludiert die Datei zur Compile-Zeit (statisches Include). Die Datei wird in die JSP eingefügt, bevor sie zu einem Servlet kompiliert wird.
Beispiel:
header.jsp:
<header>
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/products">Products</a>
<a href="/contact">Contact</a>
</nav>
</header>
footer.jsp:
<footer>
<p>© 2025 My Website. All rights reserved.</p>
</footer>
index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
</head>
<body>
<%@ include file="/WEB-INF/includes/header.jsp" %>
<main>
<h2>Welcome to our shop!</h2>
</main>
<%@ include file="/WEB-INF/includes/footer.jsp" %>
</body>
</html>
Wichtig:
- Compile-Zeit: Datei wird eingefügt, bevor JSP kompiliert wird
- Performance: Nur einmal kompiliert
- Änderungen: Bei Änderung von
header.jspmussindex.jspneu kompiliert werden!
Morgen (Tag 7) lernst du den Unterschied zwischen:
<%@ include file="..." %>(statisches Include zur Compile-Zeit)<jsp:include page="..." />(dynamisches Include zur Runtime)
<%@ taglib %> – Tag-Library-Direktive
Syntax:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
Was macht es?
Bindet eine Tag-Library ein. Die wichtigste ist JSTL (Java Standard Tag Library).
Beispiel: JSTL Core Tags
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<title>Products</title>
</head>
<body>
<h1>Our Products</h1>
<!-- JSTL forEach -->
<c:forEach var="product" items="${products}">
<div>
<h2>${product.name}</h2>
<p>Price: ${product.price} €</p>
</div>
</c:forEach>
</body>
</html>
Wichtig:
- JSTL lernst du morgen (Tag 8) im Detail!
- Für heute reicht:
<%@ taglib %>bindet Tag-Libraries ein
🟡 PROFESSIONALS: JavaBeans in echten Projekten
Best Practices für JavaBeans
1. Immer Serializable implementieren
// ✅ GUT
public class User implements Serializable {
private static final long serialVersionUID = 1L;
// ...
}
Warum?
- Session-Serialization (bei Server-Restart)
- Clustering (Session-Replikation zwischen Servern)
- Caching
2. No-arg Constructor MUSS vorhanden sein
// ✅ GUT
public class Product {
private int id;
private String name;
// No-arg Constructor
public Product() {}
// Constructor mit Parametern
public Product(int id, String name) {
this.id = id;
this.name = name;
}
}
// ❌ FEHLER: Kein no-arg Constructor!
public class Product {
private int id;
private String name;
// Nur dieser Constructor → <jsp:useBean> schlägt fehl!
public Product(int id, String name) {
this.id = id;
this.name = name;
}
}
3. Getter/Setter-Naming-Konventionen
// ✅ GUT: Standard Bean-Konvention
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
// ❌ FALSCH: EL findet Property nicht!
private String username;
public String getUserName() { // Capital N!
return username;
}
EL-Regel:
- Property:
username - Getter:
getUsername()(lowercase u, dann camelCase) - EL-Zugriff:
${user.username}(ruftgetUsername()auf!)
4. Boolean Properties
// ✅ GUT: is-Prefix für boolean
private boolean active;
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
// EL-Zugriff:
// ${user.active} → ruft isActive() auf!
5. toString() überschreiben
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", email='" + email + '\'' +
", role='" + role + '\'' +
'}';
}
Warum?
- Debugging (Logging)
- Fehleranalyse
- Entwickler-Freundlichkeit
Bean Validation mit JSR-380
Dependency in pom.xml:
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.0.Final</version>
</dependency>
Validiertes Bean:
package com.example.model;
import jakarta.validation.constraints.*;
import java.io.Serializable;
public class User implements Serializable {
@NotBlank(message = "Username is required")
@Size(min = 3, max = 20, message = "Username must be 3-20 characters")
private String username;
@NotBlank(message = "Email is required")
@Email(message = "Invalid email format")
private String email;
@NotNull(message = "Role is required")
private String role;
@Min(value = 18, message = "You must be at least 18 years old")
private int age;
// No-arg Constructor
public User() {}
// Getter/Setter
// ...
}
Validation in Servlet:
import jakarta.validation.*;
import java.util.Set;
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
private Validator validator;
@Override
public void init() throws ServletException {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Bean aus Request-Parametern erstellen
User user = new User();
user.setUsername(request.getParameter("username"));
user.setEmail(request.getParameter("email"));
user.setRole(request.getParameter("role"));
try {
user.setAge(Integer.parseInt(request.getParameter("age")));
} catch (NumberFormatException e) {
user.setAge(0);
}
// Validieren
Set<ConstraintViolation<User>> violations = validator.validate(user);
if (violations.isEmpty()) {
// ✅ Validation passed
HttpSession session = request.getSession();
session.setAttribute("user", user);
response.sendRedirect("dashboard.jsp");
} else {
// ❌ Validation failed
request.setAttribute("user", user);
request.setAttribute("errors", violations);
request.getRequestDispatcher("/WEB-INF/views/register.jsp")
.forward(request, response);
}
}
}
JSP mit Fehleranzeige:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<title>Register</title>
<style>
.error { color: red; }
</style>
</head>
<body>
<h1>Register</h1>
<!-- Fehler anzeigen -->
<c:if test="${not empty errors}">
<div class="error">
<h3>Please fix the following errors:</h3>
<ul>
<c:forEach var="error" items="${errors}">
<li>${error.message}</li>
</c:forEach>
</ul>
</div>
</c:if>
<form action="register" method="post">
<label>Username:</label>
<input type="text" name="username" value="${user.username}" required /><br/>
<label>Email:</label>
<input type="email" name="email" value="${user.email}" required /><br/>
<label>Age:</label>
<input type="number" name="age" value="${user.age}" required /><br/>
<label>Role:</label>
<select name="role">
<option value="User" ${user.role == 'User' ? 'selected' : ''}>User</option>
<option value="Developer" ${user.role == 'Developer' ? 'selected' : ''}>Developer</option>
</select><br/>
<button type="submit">Register</button>
</form>
</body>
</html>
Scope Best Practices
1. Verwende Request-Scope für MVC
// ✅ GUT: Controller → View mit Request-Scope
@WebServlet("/products")
public class ProductServlet extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
List<Product> products = productService.findAll();
request.setAttribute("products", products); // Request-Scope!
request.getRequestDispatcher("/WEB-INF/views/products.jsp")
.forward(request, response);
}
}
// ❌ SCHLECHT: Session-Scope für einmalige Daten
session.setAttribute("products", products); // Warum Session? Macht keinen Sinn!
2. Session-Scope nur für User-State
// ✅ GUT: Login-Daten in Session
User user = authenticate(username, password);
session.setAttribute("currentUser", user);
// ✅ GUT: Warenkorb in Session
ShoppingCart cart = new ShoppingCart();
session.setAttribute("cart", cart);
// ❌ SCHLECHT: Suchergebnisse in Session (sollte Request sein!)
session.setAttribute("searchResults", results);
3. Application-Scope sparsam verwenden
// ✅ GUT: Read-Only Configuration
ServletContext context = getServletContext();
context.setAttribute("appVersion", "1.0.0");
context.setAttribute("supportEmail", "support@java-developer.online");
// ❌ SCHLECHT: User-spezifische Daten
context.setAttribute("lastUser", user); // Alle User sehen das!
// ❌ SCHLECHT: Mutable Shared State ohne Synchronization
List<String> logs = new ArrayList<>();
context.setAttribute("logs", logs); // Race Conditions!
4. Explizite Scope-Angabe in EL
<!-- ✅ GUT: Explizit -->
<p>Username: ${sessionScope.currentUser.username}</p>
<p>Products: ${requestScope.products.size()}</p>
<!-- ❌ OKAY, aber unklar: -->
<p>Username: ${currentUser.username}</p>
Häufige Probleme & Lösungen
Problem 1: Bean nicht gefunden
Fehler:
javax.el.PropertyNotFoundException: Property 'username' not found on type 'com.example.model.User'
Lösung:
// Prüfe: Ist der Getter korrekt benannt?
// ❌ FALSCH:
public String getUserName() { // Capital N!
return username;
}
// ✅ RICHTIG:
public String getUsername() {
return username;
}
Problem 2: Bean hat keine Werte
Fehler:
<!-- Zeigt nichts an -->
<p>Username: ${user.username}</p>
Lösung:
Prüfe, ob das Bean gesetzt wurde:
// Servlet
User user = new User();
user.setUsername("nova");
request.setAttribute("user", user); // Wurde das gemacht?
request.getRequestDispatcher("/view.jsp").forward(request, response);
Problem 3: <jsp:useBean> erstellt neues Bean statt existierendes zu verwenden
Fehler:
<!-- page1.jsp -->
<jsp:useBean id="user" class="com.example.model.User" scope="session" />
<jsp:setProperty name="user" property="username" value="nova" />
<!-- page2.jsp -->
<jsp:useBean id="user" class="com.example.model.User" scope="session" />
<p>Username: ${user.username}</p> <!-- Zeigt nichts an! -->
Lösung:
Prüfe, ob der gleiche id-Name und gleiche scope verwendet werden:
<!-- page1.jsp --> <jsp:useBean id="currentUser" class="com.example.model.User" scope="session" /> <!-- page2.jsp --> <jsp:useBean id="currentUser" class="com.example.model.User" scope="session" /> <!-- Jetzt klappt's! -->
Problem 4: Property-Zugriff mit . in Map-Keys
Fehler:
<!-- Map mit Key "user.name" -->
<%
Map<String, String> data = new HashMap<>();
data.put("user.name", "nova");
request.setAttribute("data", data);
%>
<!-- ❌ Funktioniert nicht: -->
<p>${data.user.name}</p> <!-- EL denkt, "data" hat Property "user" mit Sub-Property "name" -->
Lösung:
Verwende []-Notation:
<!-- ✅ Funktioniert: -->
<p>${data['user.name']}</p>
🔵 BONUS: Fortgeschrittene Bean-Techniken
Achtung: Dieser Teil ist optional! Wenn du müde bist, skip ihn und komm später zurück. Die Grundlagen + Professionals sind das Wichtigste! 👍
Custom Converter für <jsp:setProperty>
Problem:
<jsp:setProperty> kann keine komplexen Typen konvertieren:
public class Product {
private LocalDate releaseDate; // Wie aus String konvertieren?
public void setReleaseDate(LocalDate releaseDate) {
this.releaseDate = releaseDate;
}
}
Lösung 1: String-Parameter im Bean
public class Product {
private LocalDate releaseDate;
// Setter für String
public void setReleaseDateString(String dateString) {
this.releaseDate = LocalDate.parse(dateString);
}
// Getter für LocalDate
public LocalDate getReleaseDate() {
return releaseDate;
}
}
<!-- Formular sendet: releaseDate=2025-10-30 --> <jsp:setProperty name="product" property="releaseDateString" param="releaseDate" />
Lösung 2: PropertyEditor (veraltet, aber funktioniert)
Erstelle src/main/java/com/example/editor/LocalDateEditor.java:
package com.example.editor;
import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
public class LocalDateEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDate.parse(text));
}
@Override
public String getAsText() {
LocalDate date = (LocalDate) getValue();
return date != null ? date.toString() : "";
}
}
Registriere im Servlet:
import java.beans.PropertyEditorManager;
@WebServlet("/product")
public class ProductServlet extends HttpServlet {
static {
PropertyEditorManager.registerEditor(
LocalDate.class,
LocalDateEditor.class
);
}
// ...
}
Nested Beans
Problem:
Ein Bean enthält andere Beans:
public class Order {
private User user;
private Product product;
private int quantity;
// Getter/Setter
}
public class User {
private String username;
// Getter/Setter
}
public class Product {
private String name;
// Getter/Setter
}
Zugriff in JSP:
<!-- order ist im Request-Scope -->
<p>Customer: ${order.user.username}</p>
<p>Product: ${order.product.name}</p>
<p>Quantity: ${order.quantity}</p>
<!-- EL-Aufruf-Kette:
order.getUser().getUsername()
order.getProduct().getName()
order.getQuantity()
-->
Bean-Cloning für Immutability
Problem:
Beans in Session können von mehreren Threads gleichzeitig geändert werden.
Lösung: Defensive Copying
public class User implements Serializable, Cloneable {
private String username;
private String email;
@Override
public User clone() {
try {
return (User) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // Should never happen
}
}
// Getter/Setter
}
Im Servlet:
// User aus Session holen und clonen
User sessionUser = (User) session.getAttribute("user");
User editUser = sessionUser.clone(); // Clone für Bearbeitung
// editUser in Request-Scope für Formular
request.setAttribute("editUser", editUser);
Weiterführende Ressourcen
JavaBeans Spec:
JSP Actions:
Bean Validation:
Books:
- „Head First Servlets and JSP“ – Kapitel 8 (JavaBeans)
- „Pro JSP 2“ – Kapitel 4 (Standard Actions)
💬 Real Talk: Mittagspause-Gespräch
Java Fleet Büro, 13:00 Uhr. Nova, Elyndra und Kat sitzen in der Lounge, Kat hat ihr Laptop offen und debuggt einen Issue.
Nova: „Elyndra, ehrliche Frage: Warum brauchen wir überhaupt JavaBeans? Ich könnte doch einfach alles mit Maps machen?“
Elyndra: „Könnte man. Aber stell dir vor: Du hast 50 Properties in einem User-Objekt. Mit einer Map ist das ein Albtraum – kein Typ-Check, keine Auto-Completion, jeder Tippfehler fällt erst zur Runtime auf.“
Kat (zwischendurch): „Und dann refactorst du ‚email‘ zu ‚emailAddress‘ – viel Spaß, alle 200 Stellen zu finden, wo du map.get("email") geschrieben hast. Bei Beans macht die IDE das automatisch.“
Nova: „Okay, das macht Sinn. Aber was ist mit den Actions? <jsp:useBean> sieht so… oldschool aus. Niemand nutzt das doch noch?“
Elyndra: „Stimmt, in modernen Projekten mit Spring Boot siehst du das selten. Aber das Konzept ist dasselbe – Spring nutzt auch Beans, nur versteckt es die Mechanik hinter Dependency Injection.“
Nova: „Also lerne ich hier ‚Legacy-Zeug‘, das keiner mehr braucht?“
Elyndra (lacht): „Nein, du lernst die Grundlagen. Wenn du verstehst, wie JavaBeans und Scopes funktionieren, verstehst du auch, was Spring Boot unter der Haube macht. Und in Enterprise-Projekten, die seit 15 Jahren laufen? Da siehst du genau diesen Code.“
Kat: „Real talk: Ich habe letzten Monat an einem Banking-System gearbeitet – 2008 gebaut, läuft immer noch. Überall <jsp:useBean> und Session-Scopes. Ohne diese Basics hätte ich null Chance gehabt, das zu verstehen.“
Nova: „Okay, okay, ich bin überzeugt. Lowkey war ich nur genervt, weil ich dachte, ich lerne unnötigen Kram.“
Elyndra: „Das Gute ist: Morgen lernst du JSTL – das ist moderner und macht deinen View-Code viel sauberer. Actions sind die Vorstufe. Baby Steps, weißt du?“
Nova (grinst): „Alright, I’m in. Lass uns weitermachen!“
✅ Checkpoint: Hast du es verstanden?
Bevor du weitermachst, teste dich selbst:
Quiz:
Frage 1: Was sind die 4 Pflicht-Konventionen für JavaBeans?
Frage 2: Was macht <jsp:useBean id="user" class="com.example.model.User" scope="session" />?
Frage 3: Erkläre den Unterschied zwischen den 4 Scopes (page, request, session, application). Wann verwendest du welchen?
Frage 4: Was ist der Unterschied zwischen <jsp:setProperty name="user" property="username" value="nova" /> und <jsp:setProperty name="user" property="*" />?
Frage 5: Warum solltest du in JSPs besser ${user.username} statt <jsp:getProperty name="user" property="username" /> verwenden?
Mini-Challenge:
Aufgabe: Erstelle eine Shopping-Cart-Anwendung mit JavaBeans und Scopes.
Anforderungen:
- Erstelle ein
Product-Bean mit:id,name,price - Erstelle ein
CartItem-Bean mit:product,quantity - Erstelle ein
ShoppingCart-Bean mit:List<CartItem> items,getTotalPrice() - Erstelle ein Servlet
/products, das eine Produktliste anzeigt - Erstelle ein Servlet
/add-to-cart, das ein Produkt zum Warenkorb hinzufügt (Session!) - Erstelle eine JSP
/cart.jsp, die den Warenkorb anzeigt mit Gesamtpreis - Verwende Expression Language für alle Views
- Nutze Session-Scope für den Warenkorb
Bonus:
- „Remove from Cart“-Funktion
- Quantity ändern
- „Empty Cart“-Button
Hinweise:
ShoppingCartsollte eineaddItem(Product, int quantity)Methode habenShoppingCartsollte in Session gespeichert werden- Produkte kommen aus dem Request-Scope (vom Servlet)
Lösung:
Die Lösung zu dieser Challenge findest du am Anfang von Tag 7 als Kurzwiederholung! 🚀
Alternativ kannst du die Musterlösung im GitHub-Projekt checken: Java Web Basic – GitHub
Geschafft? 🎉
Dann bist du bereit für die FAQ-Sektion!
❓ Häufig gestellte Fragen
Frage 1: Warum funktioniert ${user.username} nicht, obwohl ich user.setUsername("nova") im Servlet aufgerufen habe?
Stelle sicher, dass du das Bean auch im richtigen Scope gespeichert hast:
// ❌ FALSCH: Bean nur lokal erstellt
User user = new User();
user.setUsername("nova");
// Vergessen: request.setAttribute!
// ✅ RICHTIG:
User user = new User();
user.setUsername("nova");
request.setAttribute("user", user); // Wichtig!
Und in der JSP muss der gleiche Name verwendet werden:
<!-- Servlet: request.setAttribute("user", user); -->
<p>${user.username}</p> <!-- ✅ Klappt -->
<!-- Servlet: request.setAttribute("currentUser", user); -->
<p>${user.username}</p> <!-- ❌ user ist undefined! -->
<p>${currentUser.username}</p> <!-- ✅ Klappt -->
Frage 2: Was ist der Unterschied zwischen <%@ include %> und <jsp:include>?
Kurz gesagt:
<%@ include file="..." %>: Statisches Include zur Compile-Zeit<jsp:include page="..." />: Dynamisches Include zur Runtime
Morgen (Tag 7) lernst du den Unterschied im Detail! Stay tuned! 🔥
Frage 3: Kann ich JavaBeans auch ohne Servlet direkt in JSP erstellen?
Ja, mit <jsp:useBean>:
<!-- Erstellt neues Bean, falls nicht vorhanden -->
<jsp:useBean id="user" class="com.example.model.User" scope="request" />
<!-- Properties setzen -->
<jsp:setProperty name="user" property="username" value="nova" />
<jsp:setProperty name="user" property="email" value="nova@java-developer.online" />
<!-- Anzeigen -->
<p>Username: ${user.username}</p>
Aber: Das ist schlechte Architektur! JSPs sollten nur View sein, nicht Controller. Beans sollten im Servlet erstellt und über Request/Session weitergegeben werden (MVC/Model 2).
Frage 4: Wie lösche ich ein Bean aus einem Scope?
// Request-Scope
request.removeAttribute("user");
// Session-Scope
session.removeAttribute("user");
// Application-Scope
getServletContext().removeAttribute("config");
In JSP mit JSTL (lernst du Tag 8):
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <c:remove var="user" scope="session" />
Frage 5: Warum sollte ich Serializable implementieren?
- Session-Persistenz: Bei Server-Restart kann die Session gespeichert und wiederhergestellt werden
- Clustering: In Server-Clustern werden Session-Objekte zwischen Servern repliziert
- Caching: Frameworks wie Hibernate cachen Objekte
Ohne Serializable:
public class User {
private String username;
// Kein "implements Serializable"
}
// Im Servlet:
session.setAttribute("user", user);
// → Bei Clustering: NotSerializableException!
Frage 6: Kann ich Constructor-Parameter mit <jsp:useBean> übergeben?
Nein! <jsp:useBean> ruft immer den no-arg Constructor auf.
// ❌ Geht nicht:
<jsp:useBean id="user" class="com.example.model.User">
<jsp:param name="username" value="nova" /> <!-- Nicht unterstützt! -->
</jsp:useBean>
// ✅ Mach das stattdessen:
<jsp:useBean id="user" class="com.example.model.User" scope="request" />
<jsp:setProperty name="user" property="username" value="nova" />
Oder besser: Erstelle das Bean im Servlet mit Constructor-Parametern und gib es weiter!
Frage 7: Bernd meinte mal, Session-Scope wäre „evil“ und sollte vermieden werden. Hat er recht?
Lowkey ja, aber es kommt drauf an.
Sessions sind problematisch bei:
- Horizontal Scaling (mehr Server = Session-Replikation nötig)
- Microservices (Sessions sind Stateful = Anti-Pattern)
- RESTful APIs (sollten Stateless sein)
Sessions sind sinnvoll bei:
- Traditionellen Monolithen (wie unser Java Web Basic Kurs)
- User-Login (authenticated state)
- Shopping Carts
- Wizard-Forms (Multi-Step)
Real talk: In modernen Cloud-Native Apps nutzt man oft:
- Stateless JWT-Tokens statt Sessions
- Redis/Memcached für Shared State
- Client-Side Storage (Cookies, Local Storage)
Aber für klassische Java Web Apps (wie im Bank-Beispiel von Kat) sind Sessions Standard. Don’t overthink it – learn the basics first, optimize later! 🚀
📚 Quiz-Lösungen
Hier sind die Antworten zum Quiz von oben:
Frage 1: Was sind die 4 Pflicht-Konventionen für JavaBeans?
Antwort:
- Public class – Die Klasse muss öffentlich sein (
public class User) - No-arg Constructor – Ein Konstruktor ohne Parameter muss vorhanden sein (
public User() {}) - Private properties – Alle Felder sind privat (
private String username;) - Public getter/setter – Zugriff über öffentliche getter/setter-Methoden (
public String getUsername(),public void setUsername(String username))
Optional, aber empfohlen: 5. Serializable – Implementierung von java.io.Serializable
Frage 2: Was macht <jsp:useBean id="user" class="com.example.model.User" scope="session" />?
Antwort:
Diese Action macht folgendes:
- Sucht im Session-Scope nach einem Attribut mit dem Namen
"user" - Falls gefunden: Verwendet das existierende Bean (keine neue Instanz!)
- Falls nicht gefunden:
- Erstellt neue Instanz mit
new com.example.model.User()(no-arg Constructor!) - Speichert sie im Session-Scope unter dem Namen
"user" - Macht sie als Variable
userin dieser JSP verfügbar
- Erstellt neue Instanz mit
Entspricht diesem Java-Code:
User user = (User) session.getAttribute("user");
if (user == null) {
user = new User();
session.setAttribute("user", user);
}
Frage 3: Erkläre den Unterschied zwischen den 4 Scopes (page, request, session, application). Wann verwendest du welchen?
Antwort:
| Scope | Lebensdauer | Verwendung |
|---|---|---|
| page | Nur diese JSP-Seite | Temporäre Variablen, Loop-Counter, Zwischenergebnisse nur für diese Seite |
| request | Ein HTTP-Request (inkl. Forward/Include) | MVC Pattern: Controller setzt Daten, View zeigt sie an. Suchergebnisse, Formular-Daten. Am häufigsten verwendet! |
| session | Eine User-Session (~30 Min Inaktivität) | User-Login, Warenkorb, User-Einstellungen, Multi-Step-Forms |
| application | Gesamte Webapp-Laufzeit | Konfiguration, globale Zähler, Shared Resources (aber vorsichtig – alle User sehen das!) |
Best Practice:
- Standard: Request-Scope (stateless!)
- Nur wenn nötig: Session-Scope (stateful)
- Sehr selten: Application-Scope (global shared state)
- Fast nie: Page-Scope (zu begrenzt)
Frage 4: Was ist der Unterschied zwischen <jsp:setProperty name="user" property="username" value="nova" /> und <jsp:setProperty name="user" property="*" />?
Antwort:
Mit value="nova":
<jsp:setProperty name="user" property="username" value="nova" />
- Setzt die Property
usernamemanuell auf den Wert"nova" - Entspricht:
user.setUsername("nova"); - Unabhängig von Request-Parametern
Mit property="*":
<jsp:setProperty name="user" property="*" />
- Setzt ALLE Properties automatisch aus Request-Parametern
- JSP schaut sich alle Parameter an (
?username=nova&email=...) und versucht, sie mit Bean-Properties zu matchen - Request-Parameter
username→ ruftsetUsername(...)auf - Request-Parameter
email→ ruftsetEmail(...)auf - Fehlende oder nicht-matchende Parameter werden ignoriert
- Entspricht:
if (request.getParameter("username") != null) { user.setUsername(request.getParameter("username"));}if (request.getParameter("email") != null) { user.setEmail(request.getParameter("email"));}// usw. für alle Properties
Use-Case:
value="...": Hardcoded-Werte, Default-Werteproperty="*": Formulare, Auto-Binding von Request-Parametern
Frage 5: Warum solltest du in JSPs besser ${user.username} statt <jsp:getProperty name="user" property="username" /> verwenden?
Antwort:
Expression Language (${user.username}) ist besser, weil:
- Kürzer:
- EL:
${user.username} - Action:
<jsp:getProperty name="user" property="username" />
- EL:
- Lesbarer: EL liest sich wie normaler Property-Zugriff
- Flexibler: EL kann verschachtelt werden:
${order.user.address.city}Mit Actions müsstest du mehrere Tags schachteln (unmöglich) - Null-Safe: EL zeigt nichts an, wenn Property
nullist${user.username} <!-- Zeigt nichts, wenn user oder username null -->Action würde Exception werfen! - Mehr Features: EL kann Operatoren, Funktionen, Collections:
${user.age > 18 ? 'Adult' : 'Minor'} ${products.size()} ${user.username.toUpperCase()}
Fazit:
<jsp:getProperty> ist Legacy aus JSP 1.x-Zeiten (vor 2001). Expression Language wurde in JSP 2.0 (2003) eingeführt und ist der moderne Standard.
Use-Case für <jsp:getProperty>: Keine! Nutze immer EL! 🚀
🎉 Tag 6 geschafft!
Slay! Du hast es geschafft! 🚀
Real talk: JavaBeans und Scopes sind das Fundament für saubere Java Webanwendungen. Das war kein leichter Tag – es gab viel Theorie, viele Konzepte. Aber du hast durchgezogen. Das ist huge.
Das hast du heute gerockt:
- ✅ JavaBeans verstanden und selbst erstellt
- ✅ JSP Standard Actions kennengelernt (
<jsp:useBean>,<jsp:setProperty>) - ✅ Die 4 Scopes gemeistert (page, request, session, application)
- ✅ JSP-Direktiven im Detail gelernt
- ✅ Best Practices für Production-Code
Du kannst jetzt:
- Typsichere, wiederverwendbare Datencontainer erstellen
- Beans in verschiedenen Scopes verwalten
- Saubere MVC-Architekturen mit Request/Session-Scopes bauen
- Komplexe Formulare mit Auto-Binding implementieren
Honestly? Du bist jetzt weiter als 80% der Developer, die „JSP“ nur vom Hörensagen kennen. Ngl, du hast heute die Grundlage für alles gelegt, was noch kommt. 💪
Main Character Energy: Unlocked! ✨
Wie geht’s weiter?
Morgen (Tag 7): Include-Action vs Include-Direktive
Was dich erwartet:
- Unterschied zwischen
<%@ include %>und<jsp:include>verstehen - Compile-Zeit vs. Runtime Includes
- Wann du welches Include verwendest
- Parameter an Includes übergeben
- Dynamische Content-Generierung
- Das wird dein Game-Changer für wiederverwendbare View-Komponenten! 🔥
Brauchst du eine Pause?
Mach sie! JavaBeans und Scopes sind heavy topics. Lass das heute sacken, spiel mit dem Code, bau die Challenge. Komm morgen zurück, wenn du bereit bist. 😊
Tipp für heute Abend:
Bau die Shopping-Cart-Challenge aus! Füge Features hinzu:
- Mehrere Produkte mit Kategorien
- Quantity im Cart ändern
- „Clear Cart“-Button
- Gesamtpreis mit Mehrwertsteuer
Learning by doing! 🔧
🔧 Troubleshooting
Problem: <jsp:useBean> wirft ClassNotFoundException
Lösung:
<!-- ❌ FALSCH: Relative Paketangabe --> <jsp:useBean id="user" class="User" scope="request" /> <!-- ✅ RICHTIG: Vollqualifizierter Klassenname --> <jsp:useBean id="user" class="com.example.model.User" scope="request" />
Prüfe außerdem:
- Ist die Klasse kompiliert? (Clean and Build in NetBeans)
- Liegt die
.class-Datei inWEB-INF/classes/com/example/model/User.class? - Hat die Klasse einen no-arg Constructor?
Problem: Bean hat keine Werte, obwohl ich setProperty verwendet habe
Lösung:
<!-- Reihenfolge ist wichtig! --> <!-- ❌ FALSCH: setProperty VOR useBean --> <jsp:setProperty name="user" property="username" value="nova" /> <jsp:useBean id="user" class="com.example.model.User" scope="request" /> <!-- ✅ RICHTIG: useBean VOR setProperty --> <jsp:useBean id="user" class="com.example.model.User" scope="request" /> <jsp:setProperty name="user" property="username" value="nova" />
Problem: Expression Language zeigt Bean-Property nicht an
Lösung:
Prüfe die Getter-Methode:
// ❌ FALSCH: Groß/Kleinschreibung stimmt nicht
private String userName;
public String getUserName() { // Falsches Naming!
return userName;
}
// EL: ${user.userName} funktioniert NICHT!
// ✅ RICHTIG:
private String username;
public String getUsername() {
return username;
}
// EL: ${user.username} funktioniert!
Regel: Property username braucht Getter getUsername() (lowercase u, dann camelCase!)
Problem: Session-Bean ist nach einiger Zeit weg
Grund:
Sessions haben ein Timeout (default: 30 Minuten Inaktivität).
Lösung 1: Timeout erhöhen (in web.xml)
<session-config>
<session-timeout>60</session-timeout> <!-- 60 Minuten -->
</session-config>
Lösung 2: Session-Timeout in JSP setzen
<%
session.setMaxInactiveInterval(3600); // 3600 Sekunden = 1 Stunde
%>
Lösung 3: Check, ob Session existiert
<c:choose>
<c:when test="${not empty sessionScope.user}">
<p>Welcome, ${user.username}!</p>
</c:when>
<c:otherwise>
<p>Please <a href="login.jsp">login</a>.</p>
</c:otherwise>
</c:choose>
Problem: property="*" setzt nicht alle Properties
Grund:
Request-Parameter-Namen müssen exakt mit Bean-Property-Namen übereinstimmen.
Lösung:
<!-- Formular -->
<form action="register.jsp" method="post">
<input type="text" name="username" /> <!-- ✅ -->
<input type="text" name="userName" /> <!-- ❌ Funktioniert nicht! -->
<input type="text" name="user_name" /> <!-- ❌ Funktioniert nicht! -->
</form>
// Bean
public class User {
private String username; // Muss übereinstimmen!
public void setUsername(String username) {
this.username = username;
}
}
Regel:
- Input
name="username"→ Bean-Propertyusername→ SettersetUsername() - Case-Sensitive!
username≠userName≠user_name
📚 Resources & Links
Offizielle Dokumentation:
Bean Validation:
Best Practices:
Unsere GitHub-Repos:
💬 Feedback
Wie war Tag 6 für dich?
- 📧 elyndra@java-developer.online
- 💬 Kommentare unten im Blog
- 📱 Folge uns: @java_developer_online
Was können wir verbessern? Dein Feedback hilft uns, den Kurs besser zu machen!
👋 Bis morgen!
Das war Tag 6 – ein wichtiger Schritt auf deinem Java Web-Journey!
Du hast heute gelernt, wie man Daten sauber und typsicher in Webanwendungen verwaltet. JavaBeans sind überall – selbst wenn du später Spring Boot nutzt, basiert alles auf diesen Konzepten.
Bis morgen! 👋
Elyndra
Java Web Basic – Tag 6 von 10
Teil der Java Fleet Learning-Serie
© 2025 Java Fleet Systems Consulting
Website: java-developer.online

