MVC, FacesServlet, Navigation, Converters & Web Security
How Jakarta Faces controls the entire request lifecycle — and how to guard your application from unauthorised access.
Enterprise Computing · Press → to begin · Press T for contents
2 / 20
This WeekLearning Objectives
By the end of this week you will be able to:
Explain the MVC design pattern for web applications
Describe the FacesServlet controller and its role
Interpret the various technologies of page navigation in JF
Develop custom converters and validators
Implement web security using HTTP filters
Building on Weeks 8 & 9
You can now build pages and forms. This week we go deeper — understanding exactly how JF orchestrates every request, how to enforce data rules in Java, and how to stop unauthorised users from reaching pages they shouldn't see.
3 / 20
Section 1
The MVC Design Pattern
MVC is the architectural blueprint behind Jakarta Faces. Understanding it explains why the framework is designed the way it is — and why this separation of concerns makes applications far easier to maintain.
4 / 20
Section 1.1What Problem Does MVC Solve?
Early web applications mixed everything together — database calls, business rules, and HTML all in the same file. The result was code nobody could maintain.
The "Spaghetti" Problem
Imagine a recipe written as: "While cutting onions, also pre-heat the oven, and by the way here is how to plate the dish." Nobody can follow that — and if the oven changes, you have to rewrite the whole recipe.
MVC fixes this by giving every concern its own place:
Data lives in the Model — and nowhere else
Display lives in the View — and nowhere else
Logic lives in the Controller — and nowhere else
MVC stands for
Model — View — Controller
A software design pattern that separates an application into three distinct responsibilities so each can be built, tested, and changed independently.
Real-World Analogy
A TV news broadcast: Model = the news research & facts View = the teleprompter & camera Controller = the director cueing each segment
5 / 20
Section 1.2MVC Mapped to Jakarta Faces
Model
Your Data & Business Logic
Java entity classes (e.g. Product.java)
EJB session beans
JPA — database access layer
Knows nothing about the View
↔
Controller
Request Orchestrator
FacesServlet — single entry point
Managed Beans — action methods
Manages the 6-phase lifecycle
The "traffic controller"
↔
View
What the User Sees
Facelets pages (.xhtml)
JF components (h:, f:, ui:)
Facelets templates (shared layout)
Knows nothing about the Model
The Golden Rule of MVC
The Model and View are never allowed to talk directly. All communication passes through the Controller. This is why your Facelets page never contains a SQL query, and your entity class never contains HTML.
6 / 20
Section 1.3Why MVC Matters in Practice
Without MVC
With MVC (Jakarta Faces)
Changing the page design requires editing Java code
A designer edits only the .xhtml View — no Java needed
Adding a new field means touching HTML, Java, and SQL in one file
Add the field to the Model, expose it in the Bean, reference it in the View — cleanly separated
Unit testing the business logic requires a running browser
The Model and Managed Beans are plain Java — testable without a browser
Two developers editing the same file creates conflicts
Front-end and back-end developers work in separate files simultaneously
Moving from web to mobile requires rewriting everything
Replace just the View layer — the Model and Controller stay the same
Analogy
A car has three separate systems: the engine (Model), the dashboard instruments (View), and the steering/pedals (Controller). You can redesign the dashboard without rebuilding the engine.
7 / 20
Section 2
The FacesServlet Controller
FacesServlet is the heartbeat of every Jakarta Faces application. Every single user interaction passes through it. Understanding its 6-phase lifecycle explains every behaviour you will ever see in a JF app.
8 / 20
Section 2.1FacesServlet — The Central Controller
What FacesServlet is
jakarta.faces.webapp.FacesServlet is a standard Java servlet registered in web.xml. It intercepts every *.xhtml HTTP request and takes full control of processing it.
It acts as the single front controller — one entry point for all requests. Rather than having separate servlets for every page, you have one intelligent servlet that manages everything.
What FacesServlet does for every request:
Receives the raw HTTP request from the browser
Creates a FacesContext — a central object holding everything about the current request
Runs the request through the 6-phase JSF lifecycle
Writes the HTML response back to the browser
Disposes the FacesContext when done
9 / 20
Section 2.2The 6-Phase Lifecycle — In Depth
1
Restore View
→
2
Apply Request Values
→
3
Process Validations
→
4
Update Model
→
5
Invoke Application
→
6
Render Response
Phase
Plain English
Who does the work
Short-circuits if…
1. Restore View
Rebuild the page's component tree from state
FacesServlet
— (always runs)
2. Apply Request Values
Capture submitted form data from the HTTP request
Components store raw values
Immediate=true flag set
3. Process Validations
Run all validators and converters on the captured data
f: validators + converters
Any validation fails → jump to Phase 6
4. Update Model
Write validated data into the Managed Bean properties
EL bindings (#{bean.x})
Only if Phase 3 passed
5. Invoke Application
Call your action method (e.g., save())
Your Java method
Only if Phase 4 succeeded
6. Render Response
Generate and send the HTML page back to the browser
Facelets renderer
— (always runs)
Critical insight
Your save() method is called in Phase 5 — only if Phases 2, 3, and 4 all succeeded. This is why invalid form data can never reach your business logic.
Q1: A junior developer puts a database query directly inside a Facelets .xhtml page. Which MVC principle does this violate?
MVC's core rule is separation of concerns. The View (Facelets) should only display data it receives via EL expressions. Database logic belongs in the Model (JPA entities, EJBs). Mixing them creates unmaintainable "spaghetti" code.
Q2: A user submits a form. The FacesServlet processes Phase 3 and finds that a required field is empty. What happens to Phases 4 and 5?
When Phase 3 (Process Validations) fails, FacesServlet short-circuits the lifecycle. It skips Update Model (Phase 4) and Invoke Application (Phase 5) entirely and goes straight to Render Response (Phase 6) to redisplay the form with error messages. Your business logic is never touched.
11 / 20
Section 3
Page Navigation Technologies
After an action completes, Jakarta Faces must decide which page to show next. There are several ways to control this — from fully automatic to precisely hand-crafted.
12 / 20
Section 3.1Three Navigation Approaches
Approach
How it works
When to use it
Implicit Navigation
Return the filename of the target page (without .xhtml) from the action method. JF finds the file automatically.
Simple apps, most cases — no extra config needed
Explicit Navigation (faces-config.xml)
Define navigation rules in faces-config.xml — map outcomes like "success" and "failure" to specific pages.
Complex apps with many conditional routes, or when you want navigation logic separate from Java code
h:link / h:button
Non-submitting navigation. Renders as an HTML anchor tag. No form submission, no lifecycle phases.
Section 3.2Forward vs Redirect — A Critical Distinction
Server-Side Forward (default)
Browser requests /addProduct.xhtml
↓
Action runs, forward to /products.xhtml
↓ (server-side only)
Browser displays products page…
…but URL bar still shows /addProduct.xhtml ⚠
If the user presses Refresh, the form is re-submitted. This can create duplicate records.
Redirect (best practice for POST actions)
Browser requests /addProduct.xhtml
↓
Action runs → sends HTTP 302 response
↓
Browser makes a NEW request to /products.xhtml
URL bar correctly shows /products.xhtml ✓
// Add ?faces-redirect=true to trigger redirectreturn"products?faces-redirect=true";
Post-Redirect-Get Pattern
After any form submission that modifies data (save, delete, update), always append ?faces-redirect=true. This prevents duplicate submissions when the user hits the browser's Back or Refresh button.
14 / 20
Section 4
Converters & Validators
Built-in converters and validators handle common cases. But every application has unique business rules — and Jakarta Faces lets you write your own in pure Java.
15 / 20
Section 4.1Built-in vs Custom — When Do You Need Each?
Built-in converters (f:)
Handle common data type conversions automatically:
Custom Converter: when the data type is unique — e.g., your application has a special "ProductCode" format (PRD-####)
Custom Validator: when the rule cannot be expressed as a range — e.g., "the username must not already exist in the database"
Analogy
Built-in validators are like standard plug sockets — they handle 90% of cases. A custom validator is an adaptor you build yourself for the special appliance nothing else fits.
16 / 20
Section 4.2Building a Custom Converter
What a Converter does
A Converter translates a raw String (from the browser) into a Java object your code understands — and vice versa. You implement the jakarta.faces.convert.Converter interface.
@FacesConverter("productCodeConverter")
public classProductCodeConverterimplementsConverter<String> {
/**
* Called during Phase 2-3:
* Browser sends "prd-0042" →
* we return clean "PRD-0042"
*/@Overridepublic String getAsObject(
FacesContext ctx,
UIComponent comp,
String value) {
if (value == null || value.isEmpty())
returnnull;
// Uppercase and validate format
String upper = value.toUpperCase().trim();
if (!upper.matches("PRD-\\d{4}")) {
throw new ConverterException(
new FacesMessage(
"Format must be PRD-####"));
}
return upper;
}
/**
* Called during Phase 6:
* Java → display string for browser
*/@Overridepublic String getAsString(
FacesContext ctx,
UIComponent comp,
String value) {
return (value != null) ? value : "";
}
}
getAsObject: String → Java (happens during form submission, Phase 2–3)
getAsString: Java → String (happens when rendering the page, Phase 6)
Both directions must be implemented even if one just returns the value unchanged.
17 / 20
Section 4.3Building a Custom Validator
What a Validator does
A Validator checks a converted value against a business rule. It runs in Phase 3. If the rule fails, it throws a ValidatorException with a user-friendly message. Your bean method is never called.
Transforms the data type ("prd-0042" → "PRD-0042")
Validator
Checks a rule; does not change the value
Order
Conversion happens first, then validation
Failure
Both throw a FacesMessage to display to the user
18 / 20
Section 5
Web Security Using HTTP Filters
Validation protects your data. Security protects your application. HTTP Filters are the Jakarta EE mechanism for intercepting every request and enforcing access rules before any page or servlet can run.
19 / 20
Section 5.1HTTP Filters — The Security Gatekeeper
What an HTTP Filter is
A Jakarta EE Filter is a class annotated with @WebFilter that intercepts HTTP requests before they reach FacesServlet. It can inspect, modify, allow, or reject each request.
Think of it as a security checkpoint at the airport. Before you can board (reach the page), you must pass through the gate (the filter). The filter can:
Check whether the user is logged in (session check)
Redirect unauthenticated users to the login page
Log all incoming requests for auditing
Block access to admin pages for non-admin users
Why not put security logic in every Managed Bean?
If you check login status in 20 different beans, you have to maintain the check in 20 places. A filter is one class that guards all pages automatically — or all pages matching a pattern like /admin/*.
Request arrives
Browser: GET /admin/users.xhtml
Filter runs
AuthFilter: Is user logged in?
If NO
→ Redirect to login.xhtml
If YES
→ chain.doFilter() — allow request through
FacesServlet
Processes the request normally
Page rendered
Response returned to browser ✓
20 / 20
Knowledge Check — FinalSections 3, 4 & 5
Q1: After a user successfully submits an "Add Order" form, your action method returns "orders" (without ?faces-redirect=true). The user presses the browser's Refresh button. What is the risk?
Without a redirect, the browser's current URL still points to the POST action. Pressing Refresh re-submits the same POST request, calling your action method again and potentially adding a duplicate record. Always use ?faces-redirect=true after any data-modifying action (the Post-Redirect-Get pattern).
Q2: You want to prevent any unauthenticated user from accessing any page under /dashboard/. Where is the most maintainable place to implement this check?
A single HTTP Filter with the URL pattern "/dashboard/*" intercepts all requests matching that path before they reach any FacesServlet or bean. If the session check fails, the filter redirects to the login page. One class, one responsibility — far more maintainable than repeating the check in every bean.