Day 11: JSPs

It is 10 minutes past 5 in the evening of a fine day dated 19th of June.
And we will be studying how to write Java code inside HTML pages today!
What are JSPs?
These are Java Server Pages with .jsp extension, which are just HTML pages with Java code inside them. They also have implicit objects - request, response, pageContext, out, session, application and config which we can use. Java code is written using four types of tags:
Directive → <%@ … %> : this has 3 keywords:
@page
it has attributes like language, extends, import (used to import packages & libraries), errorPage, isErrorPage@include
file = “header.jsp” used to include other jsp pages@taglib
for using external tags, has 2 params uri and prefix
Declaration → <%! %> : for initializing values and creating methods
Scriptlet → <% %> : main logic to be shown in the page (goes inside service method)
Expression → <%= variable %> : used to print values, equivalent to out.print()
These tags can be used multiple times. JSP pages are translated to servlets! Because Tomcat is a servlet container and cannot understand JSP. So always use servlets if there’s more logic and JSP for creating better UI HTML pages.
Here’s an example:
index.jsp
<%@ page contentType="text/html" %>
<html>
<head><title>Start Your Quest</title></head>
<body>
<h2>Welcome Adventurer!</h2>
<form action="adventure" method="post">
Name: <input type="text" name="hero" /><br>
Choose Your Weapon:
<select name="weapon">
<option>Sword</option>
<option>Magic Staff</option>
<option>Bow</option>
</select><br><br>
<input type="submit" value="Enter the Dark Forest">
</form>
</body>
</html>
- We mention the name of the servlet in form action. When we click on submit form all the values are submitted via request object.
AdventureServlet.java
package controller;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.IOException;
import java.util.Random;
@WebServlet("/adventure")
public class AdventureServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String hero = req.getParameter("hero");
String weapon = req.getParameter("weapon");
String[] monsters = {"Dragon", "Troll", "Goblin", "Shadow Beast"};
String monster = monsters[new Random().nextInt(monsters.length)];
boolean victory = new Random().nextBoolean();
req.setAttribute("hero", hero);
req.setAttribute("weapon", weapon);
req.setAttribute("monster", monster);
req.setAttribute("victory", victory);
RequestDispatcher dispatcher = req.getRequestDispatcher("result.jsp");
dispatcher.forward(req, res);
}
}
The annotation creates our servlet mapping to URL (/adventure) in web.xml.
We get the values from the params and forward the new values as attributes in request object to result.jsp page.
result.jsp
<%@ page import="java.util.*" contentType="text/html" %> <!-- Directive -->
<%! // Declaration: reusable method
public String getEnding(boolean victory) {
return victory ? "You emerge victorious!" : "You were defeated... but legends speak of your bravery.";
}
%>
<html>
<head><title>Adventure Outcome</title></head>
<body>
<%
// Scriptlet: get values from request
String hero = (String) request.getAttribute("hero");
String weapon = (String) request.getAttribute("weapon");
String monster = (String) request.getAttribute("monster");
boolean victory = (Boolean) request.getAttribute("victory");
%>
<h2> <%= hero %> vs. The <%= monster %> </h2>
<p>You fought valiantly using your <b><%= weapon %></b>.</p>
<h3 <%= getEnding(victory) %></h3> <!-- Expression: show ending -->
</body>
</html>
Here we observe the usage of all the four tags! This is a HTML page despite what it looks like.
We use Directive tags to import libraries and set other properties of the page like contentType.
We used Declaration tag to declare a method called getEnding() which can be used anywhere in this page.
Then we use Scriptlet tag to write the main logic. req.getAttribute always returns an object, so we need to typecast it.
In the end, Expression tags are used to print our variables!
Notice the changes in comment tags (<! - - - > for HTML and // for Java code) throughout the page.
This whole code gets converted to a servlet code, where the scriptlet code is placed inside service() method. The getEnding() method is declared outside the service() method. The import libraries statements within directive tags are placed with other import statements in the beginning. And the Expression tag values are just printed.
Notice how we are able to use request object without instantiating it, because its an implicit object which gets instantiated when our jsp files are translated to servlets by Tomcat or other web container.
MVC Architecture
Folder Structure
MonsterApp/
├── src/
│ ├── model/
│ │ └── Monster.java
│ ├── dao/
│ │ └── MonsterDAO.java
│ └── controller/
│ └── MonsterServlet.java
├── web/
│ ├── index.jsp
│ ├── monsters.jsp
│ └── WEB-INF/
│ └── web.xml (optional)
- All jsp files should be placed under web folder, only those files will be accessed by Tomcat.
Monster.java (Model)
package model;
public class Monster {
private String name;
private String type;
private int level;
public Monster(String name, String type, int level) {
this.name = name;
this.type = type;
this.level = level;
}
public String getName() { return name; }
public String getType() { return type; }
public int getLevel() { return level; }
}
- Model should be just a POJO - Plain Old Java Object. It should represent an entity.
MonsterDAO.java
package dao;
import model.Monster;
import java.sql.*;
import java.util.*;
public class MonsterDAO {
public List<Monster> getAllMonsters() {
List<Monster> monsters = new ArrayList<>();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/monsters_db", "root", "password");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM monsters");
while (rs.next()) {
monsters.add(new Monster(
rs.getString("name"),
rs.getString("type"),
rs.getInt("level")
));
}
rs.close(); stmt.close(); conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return monsters;
}
}
- MonsterDAO is a Data Access Object for Monster entity and includes all database operations associated with it.
MonsterServlet.java (Controller)
package controller;
import dao.MonsterDAO;
import model.Monster;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.IOException;
import java.util.List;
@WebServlet("/monsters")
public class MonsterServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
List<Monster> monsters = new MonsterDAO().getAllMonsters();
req.setAttribute("monsters", monsters);
RequestDispatcher dispatcher = req.getRequestDispatcher("monsters.jsp");
dispatcher.forward(req, res);
}
}
This page represents as the “controller” which means it handles requests and responses. No core business logic should be written here.
We observe that all monsters values are stored in the “monsters“ attribute of request object.
This is then forwarded to “monsters.jsp” page.
index.jsp (Homepage)
<html>
<head><title>Monster Directory</title></head>
<body>
<h2>Welcome Hero!</h2>
<form action="monsters" method="get">
<button type="submit">View Monsters</button>
</form>
</body>
</html>
- The first page which is displayed and from where the request to “/monsters” is sent. Which is then forwarded to “monsters.jsp”.
monsters.jsp (View)
<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>Monster List</title></head>
<body>
<h2>Monster List</h2>
<c:choose>
<c:when test="${not empty monsters}">
<ul>
<c:forEach var="m" items="${monsters}">
<li>
<b>${m.name}</b> — Type: ${m.type}, Level: ${m.level}
</li>
</c:forEach>
</ul>
</c:when>
<c:otherwise>
<p>No monsters found in the database!</p>
</c:otherwise>
</c:choose>
</body>
</html>
Here we observe few tags from JSTL (Java Standard Tag Library) being used.
${variable} is used to print the values. It’s known as Expression language.
We have used few tags from core taglib like forEach (looping), choose and when (conditional).
We also have SQL tags like DataSource, query which aren’t depicted here because all database logic should be moved to DAO class.
MySQL Table
CREATE DATABASE monsters_db;
USE monsters_db;
CREATE TABLE monsters (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
type VARCHAR(50),
level INT
);
INSERT INTO monsters (name, type, level) VALUES
('Fire Drake', 'dragon', 10),
('Goblin King', 'goblin', 5),
('Undead Knight', 'undead', 7);
- This is the table to be created in MySQL before we run our program.
Servlet Filter
package filters;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.*;
import java.io.IOException;
@WebFilter("/dashboard")
public class AuthFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
boolean loggedIn = (session != null && session.getAttribute("user") != null);
if (loggedIn) {
// Prevent browser cache
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
chain.doFilter(req, res); // Continue to dashboard
} else {
response.sendRedirect("login.jsp");
}
}
}
In this code snippet we observe:
When /dashboard is requested this web filter is first executed by tomcat. Web filters are the intermediaries for web servlet pages which are executed before and can control the flow, allow or block requests to the main servlets.
Here we are checking is session is already set i.e., if the user has already logged in and if yes this AuthFilter allows the user to continue to requested page dashboard via chain.doFilter.
If not we redirect the user to login.jsp to log in first. This section of code needs to be added at all pages we want to protect, i.e., we don’t want any unauthenticated party to view it.
Notice how we prevent browser cache by setting the required Headers. This doesn’t allow the user to go back to the previous page after being logged out, because that page is no longer cached by the browser.
That’s it for today!
We will meet again in our next learning, in our next adventure!
Until then remember to chain.doFilter only good thoughts!
Subscribe to my newsletter
Read articles from Nagraj Math directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
