JavaServer Pages put Java inside HTML so that the view is easier to write than a servlet full of println calls. The session covers scripting elements, JSTL, JDBC from a page, action elements, implicit objects and a small combined project.
Objectives
Do not copy. Read for understanding and the viva- Complete questions 6 to 12 of the manual: jsp
- Prepare the deliverable before the lab and finish it during the session
- Be ready to explain every step in the viva
Questions Covered
Do not copy. Read for understanding and the viva| Question | Requirement | Status |
|---|---|---|
| Q6 | Write JSP Programme to print current date and time along with timestamp, implement… | Complete |
| Q7 | Create a JSP page and implement a Scripting Tag, Expression tag and Declaration tag | Complete |
| Q8 | Import JSTL library in JSP Page and use its following tags | Complete |
| Q9 | Create a JSP Page for database connectivity using JDBC and show the students details… | Complete |
| Q10 | Write a JSP application using following Action Elements | Complete |
| Q11 | Write a JSP program using the following implicit objects with an example | Complete |
| Q12 | Create a JSP Project implementing all the above (Session 1 and Session 2) concepts… | Complete |
Preparation
Do not copy. Read for understanding and the viva- Add the JSTL jars (jakarta.servlet.jsp.jstl and its API) to the project; JSTL is not part of Tomcat.
- For auto-refresh use
response.setHeader("Refresh", "5")or a meta refresh tag. - Question 12 is a mini project: plan its pages (login, list, add, edit, delete, error) before coding.
- One Maven web project
JspLabholds all seven answers, with the samepom.xmlas Session 1. JSP pages go insrc/main/webapp/, Java classes insrc/main/java/ignou/. Questions 9 and 12 need the IGNOU database from Session 1, Question 5.
Project Setup
Do not copy. Read for understanding and the viva- Create the project as in Session 1 (NetBeans: File, New Project, Java with Maven, Web Application, name, Next, server Tomcat 10.1, Finish; Eclipse: Dynamic Web Project, then Convert to Maven Project) and name it
JspLab. Copy the Session 1pom.xml, changingartifactIdandfinalName. - To add a page: right-click Web Pages (NetBeans) or
src/main/webapp(Eclipse), New, JSP, name without extension. Base URL after Run:http://localhost:8080/JspLab/.
Question 6
Problem Statement
Write in lab recordWrite JSP Programme to print current date and time along with timestamp, implement auto-refresh of a page.
Solution
Write in lab recordSteps
- New JSP
datetimeinsrc/main/webapp/; paste the listing. - Run and open
http://localhost:8080/JspLab/datetime.jsp. Leave it for 20 seconds: the seconds and the timestamp advance on their own every 5 seconds. - In the browser dev tools, Network tab, watch a new request appear every 5 seconds.
Program
<%-- Q6: src/main/webapp/datetime.jsp
Prints date, time and timestamp; the page reloads itself every 5 seconds. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.Date, java.text.SimpleDateFormat, java.sql.Timestamp" %>
<%
// HTTP Refresh header: the browser requests this URL again after 5 seconds.
response.setHeader("Refresh", "5");
long millis = System.currentTimeMillis();
Date now = new Date(millis);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<%-- Second way: meta refresh. Either one alone is enough. --%>
<meta http-equiv="refresh" content="5">
<title>Date and Time (auto refresh)</title>
</head>
<body>
<h2>Current Date and Time</h2>
<p>Date: <%= new SimpleDateFormat("dd-MM-yyyy").format(now) %></p>
<p>Time: <%= new SimpleDateFormat("HH:mm:ss").format(now) %></p>
<p>Full: <%= now %></p>
<p>Timestamp (ms since epoch): <%= millis %></p>
<p>SQL Timestamp: <%= new Timestamp(millis) %></p>
<p><i>This page refreshes every 5 seconds. Watch the seconds change.</i></p>
</body>
</html>Output
Checked by reading, not executed (no Tomcat here). The page repaints itself every five seconds; one snapshot:
Current Date and Time
Date: 26-09-2026
Time: 11:02:15
Full: Sat Sep 26 11:02:15 IST 2026
Timestamp (ms since epoch): 1790398335518
SQL Timestamp: 2026-09-26 11:02:15.518
This page refreshes every 5 seconds. Watch the seconds change.Explanation
- Tomcat compiles the JSP into a servlet on first request (
work/Catalina/localhost/JspLab/org/apache/jsp/datetime_jsp.java); HTML becomesout.writecalls, scriptlet code is copied into_jspService. response.setHeader("Refresh", "5")asks the browser to re-request the URL after 5 seconds; themeta http-equiv="refresh"tag does the same from the HTML side. One is enough; both are shown so you can explain either in the viva. Headers must be set before output is committed, so the scriptlet sits above the DOCTYPE.System.currentTimeMillis()is the timestamp;SimpleDateFormatturns it into date and time strings.
Question 7
Problem Statement
Write in lab recordCreate a JSP page and implement a Scripting Tag, Expression tag and Declaration tag.
Solution
Write in lab recordSteps
- New JSP
scriptinginsrc/main/webapp/. - Open
http://localhost:8080/JspLab/scripting.jsp, reload several times, then openscripting.jsp?name=Asha.
Program
<%-- Q7: src/main/webapp/scripting.jsp
Declaration <%! %>, scriptlet <% %> and expression <%= %> in one page. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- Declaration: becomes a field and a method of the generated servlet class.
Because it is a field, hitCount survives across requests (until redeploy). --%>
<%!
private int hitCount = 0;
private long factorial(int n) {
long f = 1;
for (int i = 2; i <= n; i++) f *= i;
return f;
}
%>
<%-- Scriptlet: plain Java inside _jspService(); runs on every request. --%>
<%
hitCount++;
String name = request.getParameter("name");
if (name == null || name.isBlank()) name = "Student";
int n = 5;
%>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>JSP Scripting Elements</title></head>
<body>
<h2>JSP Scripting Elements</h2>
<%-- Expression: value is converted to String and written into the output. --%>
<p>Hello, <%= name %>! You are visitor number <%= hitCount %>.</p>
<p>Factorial of <%= n %> is <%= factorial(n) %>.</p>
<h3>Multiplication table of 7 (scriptlet loop)</h3>
<table border="1" cellpadding="4">
<% for (int i = 1; i <= 10; i++) { %>
<tr><td>7 x <%= i %></td><td>= <%= 7 * i %></td></tr>
<% } %>
</table>
<form method="get">
<p>Your name: <input name="name" value="<%= name %>"> <button type="submit">Greet</button></p>
</form>
</body>
</html>Output
Checked by reading. Third visit with ?name=Asha:
JSP Scripting Elements
Hello, Asha! You are visitor number 3.
Factorial of 5 is 120.
Multiplication table of 7 (scriptlet loop)
7 x 1 = 7 ... 7 x 10 = 70 (ten rows)
Your name: [Asha] [Greet]Explanation
| Element | Syntax | Becomes in the generated servlet | Used here for |
|---|---|---|---|
| Declaration | <%! ... %> | Class-level field or method, outside _jspService | hitCount field, factorial() method |
| Scriptlet | <% ... %> | Statements inside _jspService, run on every request | Reading name, incrementing hitCount, the for loop |
| Expression | <%= ... %> | out.print(...) of the value | Printing name, hitCount, factorial(n), 7 * i |
hitCountkeeps counting across requests because it is a field of the one servlet instance; it resets when the page is recompiled or the application redeploys. It is also shared by all users and not thread-safe, which is why real applications keep such state in a session or a database.- An expression must not end with a semicolon; a scriptlet must.
- The loop opens in one scriptlet and closes in another; the HTML row between them is emitted on every iteration.
Question 8
Problem Statement
Write in lab recordImport JSTL library in JSP Page and use its following tags:
- out
- if
- forEach
- choice, when and otherwise
- url and redirect
Solution
Write in lab recordSteps
- Confirm the two JSTL artifacts (
jakarta.servlet.jsp.jstl-api3.0.0 and Glassfishjakarta.servlet.jsp.jstl3.0.1) are inpom.xml; without Maven, download both jars and drop them intosrc/main/webapp/WEB-INF/lib/. - New JSP
jstl-demo; keepdatetime.jspfrom Question 6 as the redirect target. - Open
http://localhost:8080/JspLab/jstl-demo.jsp, then click the two links at the bottom.
Program
<%-- Q8: src/main/webapp/jstl-demo.jsp
JSTL 3.0 core tags on Tomcat 10.1: the taglib URI is jakarta.tags.core --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%-- 5. c:redirect: /jstl-demo.jsp?go=clock sends the browser to datetime.jsp --%>
<c:if test="${param.go == 'clock'}">
<c:redirect url="/datetime.jsp" />
</c:if>
<%-- test data: a list of marks in page scope --%>
<c:set var="student" value="Asha Verma" />
<c:set var="marks" value="${[78, 92, 45, 66, 88]}" />
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>JSTL Core Tags</title></head>
<body>
<h2>JSTL Core Tag Demo</h2>
<h3>1. c:out</h3>
<%-- escapeXml is true by default, so a value like <b>x</b> is printed literally --%>
<p>Student: <c:out value="${student}" /></p>
<p>Unknown parameter with default: <c:out value="${param.city}" default="not given" /></p>
<p>Escaped: <c:out value="<b>bold?</b>" /></p>
<h3>2. c:if</h3>
<c:if test="${not empty param.name}">
<p>Hello, <c:out value="${param.name}" /></p>
</c:if>
<c:if test="${empty param.name}">
<p>Add ?name=YourName to the URL to see c:if fire.</p>
</c:if>
<h3>3. c:forEach</h3>
<table border="1" cellpadding="4">
<tr><th>#</th><th>Marks</th><th>Result</th></tr>
<c:forEach var="m" items="${marks}" varStatus="st">
<tr>
<td>${st.count}</td>
<td>${m}</td>
<td>
<%-- 4. c:choose / c:when / c:otherwise --%>
<c:choose>
<c:when test="${m >= 75}">Distinction</c:when>
<c:when test="${m >= 50}">Pass</c:when>
<c:otherwise>Fail</c:otherwise>
</c:choose>
</td>
</tr>
</c:forEach>
</table>
<p>Counting with begin/end/step:
<c:forEach var="i" begin="1" end="10" step="3">${i} </c:forEach>
</p>
<h3>5. c:url and c:redirect</h3>
<%-- c:url prefixes the context path and adds the session id if cookies are off --%>
<c:url var="selfLink" value="/jstl-demo.jsp">
<c:param name="name" value="Rahul Singh" />
<c:param name="city" value="Kolkata" />
</c:url>
<p><a href="${selfLink}">Reload with name and city (built by c:url)</a></p>
<p>Rendered link: <c:out value="${selfLink}" /></p>
<c:url var="clockLink" value="/jstl-demo.jsp"><c:param name="go" value="clock" /></c:url>
<p><a href="${clockLink}">Go to the clock page (c:redirect)</a></p>
</body>
</html>Output
Checked by reading. First visit without parameters:
JSTL Core Tag Demo
1. c:out
Student: Asha Verma
Unknown parameter with default: not given
Escaped: <b>bold?</b>
2. c:if
Add ?name=YourName to the URL to see c:if fire.
3. c:forEach
# Marks Result
1 78 Distinction
2 92 Distinction
3 45 Fail
4 66 Pass
5 88 Distinction (five rows)
Counting with begin/end/step: 1 4 7 10
5. c:url and c:redirect
Reload with name and city (built by c:url)
Rendered link: /JspLab/jstl-demo.jsp?name=Rahul+Singh&city=Kolkata
Go to the clock page (c:redirect)Clicking the first link shows Hello, Rahul Singh under c:if and Kolkata under c:out. Clicking the second sends the browser to /JspLab/datetime.jsp with an HTTP 302 and the address bar changes.
Explanation
- The taglib directive
uri="jakarta.tags.core"is the JSTL 3.0 name; the oldjava.sun.comURI belongs to JSTL 1.2 onjavaxand fails on Tomcat 10.1 with “cannot be resolved”. c:outprints an EL value and escapes XML characters by default, so<b>shows literally;defaultcovers missing values.c:ifhas no else; for branches usec:choosewithc:whenand onec:otherwise(the manual’s “choice”).c:forEachwalks any collection or array (items) or counts (begin,end,step).varStatusgivesindex,count,first,last.c:urlprepends the context path, URL-encodes nestedc:paramvalues and appends;jsessionidwhen cookies are off.c:redirectsends a 302 and stops the page; it must run before any output, which is why it sits at the top.
Question 9
Problem Statement
Write in lab recordCreate a JSP Page for database connectivity using JDBC and show the students details from the database created during exercise no 5 in session 1.
Solution
Write in lab recordSteps
- MySQL must be running with the IGNOU database from Session 1 (
schema.sql). mysql-connector-jis already inpom.xml; if not using Maven, copy the jar toWEB-INF/lib/.- New JSP
student-list; openhttp://localhost:8080/JspLab/student-list.jsp. Stop MySQL and reload once to see the error branch.
Program
<%-- Q9: src/main/webapp/student-list.jsp
Reads the Student table of the IGNOU database (Session 1, Q5) with plain JDBC. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.sql.Connection, java.sql.DriverManager, java.sql.PreparedStatement, java.sql.ResultSet, java.sql.SQLException" %>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Student List (JDBC)</title></head>
<body>
<h2>Students in IGNOU database</h2>
<%
String url = "jdbc:mysql://localhost:3306/IGNOU?useSSL=false&serverTimezone=Asia/Kolkata";
String sql = "SELECT enrolment_no, name, dob, email, mobile, programme, semester, courses "
+ "FROM Student ORDER BY enrolment_no";
int count = 0;
// try-with-resources closes ResultSet, PreparedStatement and Connection in reverse order
try (Connection con = DriverManager.getConnection(url, "ignou", "ignou123");
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
%>
<table border="1" cellpadding="4">
<tr><th>Enrolment</th><th>Name</th><th>DOB</th><th>Email</th><th>Mobile</th>
<th>Programme</th><th>Semester</th><th>Courses</th></tr>
<%
while (rs.next()) {
count++;
%>
<tr>
<td><%= rs.getString("enrolment_no") %></td>
<td><%= rs.getString("name") %></td>
<td><%= rs.getDate("dob") %></td>
<td><%= rs.getString("email") %></td>
<td><%= rs.getString("mobile") %></td>
<td><%= rs.getString("programme") %></td>
<td><%= rs.getInt("semester") %></td>
<td><%= rs.getString("courses") %></td>
</tr>
<%
}
%>
</table>
<p>Total students: <%= count %></p>
<%
} catch (SQLException e) {
%>
<p style="color:red">Database error: <%= e.getMessage() %></p>
<p>Check that MySQL is running, schema.sql was executed and mysql-connector-j is in WEB-INF/lib.</p>
<%
}
%>
</body>
</html>Output
Checked by reading. With the three seeded rows:
Students in IGNOU database
Enrolment Name DOB Email Mobile Programme Semester Courses
2451001234 Asha Verma 2001-03-14 asha.verma@example.com 9876543210 MCA 2 MCS-218,MCS-219,MCS-220,MCS-221
2451001235 Rahul Singh 2000-11-02 rahul.singh@example.com 9123456780 MCA 2 MCS-218,MCS-220,MCS-221
2451001236 Meera Nair 2002-07-25 meera.nair@example.com 9988776655 MCA 1 MCS-211,MCS-212,MCS-213
Total students: 3With MySQL stopped: Database error: Communications link failure in red, followed by the hint line.
Explanation
- The JDBC steps are the same as in the DAO of Session 1:
DriverManager.getConnection(url, user, password),prepareStatement,executeQuery, loop overResultSet. Connector/J 8 registers its driver automatically through the service loader, soClass.forName("com.mysql.cj.jdbc.Driver")is optional. - The
trywith resources declares the connection, statement and result set together; they close in reverse order whether the loop finishes or throws. - The scriptlet is split around the HTML so the header is written once and a row per
rs.next(). SQL inside a JSP is acceptable here but mixes data access with presentation; Question 12 moves it back intoStudentDao.
Question 10
Problem Statement
Write in lab recordWrite a JSP application using following Action Elements
- jsp:forward
- jsp:include
- set and getProperty
- jsp:useBean
Solution
Write in lab recordSteps
- Add class
StudentBeanin packageignou(Source Packages, New, Java Class). - Add three JSPs in
src/main/webapp/:header,action-demo,bean-view. - Open
http://localhost:8080/JspLab/action-demo.jsp. Submit with a name:bean-view.jspshows the bean. Submit with the name empty: you are forwarded back to the form with a red message while the address bar still saysbean-view.jsp.
Program
Lab record: every tab is one file of the answer. Write all of them.
package ignou;
import java.io.Serializable;
/**
* Q10: JavaBean for jsp:useBean. Rules a bean must follow: public class,
* public no-argument constructor, private fields, public getters and setters
* named after the fields. jsp:setProperty property="*" matches request
* parameter names to these setter names.
*/
public class StudentBean implements Serializable {
private String name;
private String programme;
private int semester;
public StudentBean() { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getProgramme() { return programme; }
public void setProgramme(String programme) { this.programme = programme; }
public int getSemester() { return semester; }
public void setSemester(int semester) { this.semester = semester; }
}<%-- Q10: src/main/webapp/header.jsp (pulled in with jsp:include at request time) --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div style="background:#eee;padding:8px;border-bottom:1px solid #999">
<b>IGNOU Web Technologies Lab</b> |
Page title: <%= request.getParameter("title") %> |
Served at <%= new java.util.Date() %>
</div><%-- Q10: src/main/webapp/action-demo.jsp
Entry page: jsp:include for the header, a form that posts to bean-view.jsp,
and a message slot that bean-view.jsp fills when it jsp:forwards back here. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>JSP Action Elements</title></head>
<body>
<%-- 2. jsp:include runs header.jsp now and pastes its output here --%>
<jsp:include page="header.jsp">
<jsp:param name="title" value="Action Elements" />
</jsp:include>
<h2>Student Bean Form</h2>
<% if (request.getParameter("msg") != null) { %>
<p style="color:red"><%= request.getParameter("msg") %></p>
<% } %>
<%-- field names match the StudentBean property names on purpose --%>
<form action="bean-view.jsp" method="post">
<p><label>Name: <input name="name"></label></p>
<p><label>Programme: <input name="programme" value="MCA"></label></p>
<p><label>Semester: <input name="semester" type="number" value="2" min="1" max="6"></label></p>
<p><button type="submit">Show bean</button></p>
</form>
</body>
</html><%-- Q10: src/main/webapp/bean-view.jsp
jsp:useBean creates the bean, jsp:setProperty fills it from the request,
jsp:getProperty prints it; jsp:forward sends bad input back to the form. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 1. jsp:forward: the browser URL stays bean-view.jsp, but the form page renders --%>
<% if (request.getParameter("name") == null || request.getParameter("name").isBlank()) { %>
<jsp:forward page="action-demo.jsp">
<jsp:param name="msg" value="Name is required (you were forwarded back by jsp:forward)" />
</jsp:forward>
<% } %>
<%-- 4. jsp:useBean: find a StudentBean named 'student' in request scope or create one --%>
<jsp:useBean id="student" class="ignou.StudentBean" scope="request" />
<%-- 3. jsp:setProperty with property="*" copies every matching request parameter --%>
<jsp:setProperty name="student" property="*" />
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Bean View</title></head>
<body>
<jsp:include page="header.jsp">
<jsp:param name="title" value="Bean View" />
</jsp:include>
<h2>Values read back with jsp:getProperty</h2>
<table border="1" cellpadding="4">
<tr><th>Name</th><td><jsp:getProperty name="student" property="name" /></td></tr>
<tr><th>Programme</th><td><jsp:getProperty name="student" property="programme" /></td></tr>
<tr><th>Semester</th><td><jsp:getProperty name="student" property="semester" /></td></tr>
</table>
<%-- setProperty with a fixed value, then read it through EL --%>
<jsp:setProperty name="student" property="programme" value="MCA (forced)" />
<p>After setProperty with a literal value, programme = ${student.programme}</p>
<p><a href="action-demo.jsp">Back</a></p>
</body>
</html>Output
Checked by reading. Submitting name Meera Nair, programme MCA, semester 2:
IGNOU Web Technologies Lab | Page title: Bean View | Served at Sat Sep 26 11:20:44 IST 2026
Values read back with jsp:getProperty
Name Meera Nair
Programme MCA
Semester 2
After setProperty with a literal value, programme = MCA (forced)
BackSubmitting with an empty name leaves the address bar at /JspLab/bean-view.jsp but renders the form page with the header titled Action Elements and the red line Name is required (you were forwarded back by jsp:forward).
Explanation
| Action | What it does | Where in the code |
|---|---|---|
jsp:include | Runs another resource at request time and inserts its output; jsp:param adds request parameters visible only inside it | header.jsp at the top of both pages, with title |
jsp:forward | Hands the same request to another page and discards any output so far; the browser URL does not change | Empty name in bean-view.jsp |
jsp:useBean | Looks for a bean with that id in the given scope, creates one with the no-arg constructor if absent | student in request scope |
jsp:setProperty | Calls setters; property="*" matches every request parameter to a same-named setter and converts types | Fills name, programme, semester (String to int) |
jsp:getProperty | Calls the getter and prints the value | The three table rows |
jsp:includediffers from theincludedirective: the directive pastes source at translation time, the action calls the page at request time, so the header’s date is always current. The forward happens before any output; forwarding after content was flushed throwsIllegalStateException.
Question 11
Problem Statement
Write in lab recordWrite a JSP program using the following implicit objects with an example:
- out
- request
- response
- session
- pageContext
- exception
Solution
Write in lab recordSteps
- Add JSPs
implicitanderrorinsrc/main/webapp/. - Open
http://localhost:8080/JspLab/implicit.jsp?name=Asha, reload twice, then click the divide-by-zero link. In dev tools, Network, the response headers showX-Lab: MCSL-222andSet-Cookie: lastPage=implicit.
Program
Lab record: every tab is one file of the answer. Write all of them.
<%-- Q11: src/main/webapp/implicit.jsp
out, request, response, session, pageContext; exception is shown by error.jsp.
Open /implicit.jsp?fail=1 to trigger the exception path. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %>
<%
// response: set a header and a cookie before any output is flushed
response.setHeader("X-Lab", "MCSL-222");
response.addCookie(new jakarta.servlet.http.Cookie("lastPage", "implicit"));
// session: count visits for this browser
Integer visits = (Integer) session.getAttribute("visits");
visits = visits == null ? 1 : visits + 1;
session.setAttribute("visits", visits);
// pageContext: attribute in page scope, and a shortcut to the other scopes
pageContext.setAttribute("pageNote", "only visible on this page");
pageContext.setAttribute("appNote", "visible to every page", jakarta.servlet.jsp.PageContext.APPLICATION_SCOPE);
%>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Implicit Objects</title></head>
<body>
<h2>JSP Implicit Objects</h2>
<h3>1. out</h3>
<% out.println("<p>Written with out.println(). Buffer size: " + out.getBufferSize()
+ " bytes, remaining: " + out.getRemaining() + "</p>"); %>
<h3>2. request</h3>
<p>Method: <%= request.getMethod() %>, URI: <%= request.getRequestURI() %>,
client IP: <%= request.getRemoteAddr() %>, name parameter: <%= request.getParameter("name") %></p>
<h3>3. response</h3>
<p>Content type set to <%= response.getContentType() %>; header X-Lab and cookie lastPage added (see browser dev tools).</p>
<h3>4. session</h3>
<p>Session id: <%= session.getId() %>, visits: <%= visits %>, new: <%= session.isNew() %></p>
<h3>5. pageContext</h3>
<p>page scope: <%= pageContext.getAttribute("pageNote") %></p>
<p>application scope via pageContext: <%= pageContext.findAttribute("appNote") %></p>
<p>session via pageContext: <%= pageContext.getSession().getId().equals(session.getId()) %> (same object as session)</p>
<h3>6. exception</h3>
<p><a href="implicit.jsp?fail=1">Click to divide by zero</a>; error.jsp shows the exception object.</p>
<%
if ("1".equals(request.getParameter("fail"))) {
int zero = 0;
out.println(10 / zero); // ArithmeticException goes to errorPage
}
%>
</body>
</html><%-- Q11 and Q12: src/main/webapp/error.jsp
isErrorPage="true" makes the 'exception' implicit object available.
Reached two ways: errorPage="error.jsp" in a JSP page directive, or the
error-page entries in web.xml (uncaught exception or HTTP 404). --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<%
Integer status = (Integer) request.getAttribute("jakarta.servlet.error.status_code");
String uri = (String) request.getAttribute("jakarta.servlet.error.request_uri");
%>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Error</title></head>
<body>
<h2>Something went wrong</h2>
<% if (exception != null) { %>
<p>Exception type: <b><%= exception.getClass().getName() %></b></p>
<p>Message: <%= exception.getMessage() %></p>
<p>Thrown from: <%= exception.getStackTrace().length > 0 ? exception.getStackTrace()[0] : "unknown" %></p>
<% } else { %>
<p>HTTP status <%= status %> for <%= uri %></p>
<% } %>
<p><a href="<%= request.getContextPath() %>/">Home</a></p>
</body>
</html>Output
Checked by reading. Second visit:
JSP Implicit Objects
1. out
Written with out.println(). Buffer size: 8192 bytes, remaining: 7810
2. request
Method: GET, URI: /JspLab/implicit.jsp, client IP: 0:0:0:0:0:0:0:1, name parameter: Asha
3. response
Content type set to text/html;charset=UTF-8; header X-Lab and cookie lastPage added (see browser dev tools).
4. session
Session id: 7D2C9F1A4B8E3C6D0A5F2E9B1C4D7A8E, visits: 2, new: false
5. pageContext
page scope: only visible on this page
application scope via pageContext: visible to every page
session via pageContext: true (same object as session)
6. exception
Click to divide by zero; error.jsp shows the exception object.After clicking the link (implicit.jsp?fail=1) the browser shows error.jsp: Exception type: java.lang.ArithmeticException, Message: / by zero, Thrown from: org.apache.jsp.implicit_jsp._jspService(implicit_jsp.java:142).
Explanation
| Object | Type | Example use in the page |
|---|---|---|
out | JspWriter | out.println, buffer size and remaining space |
request | HttpServletRequest | method, URI, remote address, name parameter |
response | HttpServletResponse | setHeader, addCookie, content type |
session | HttpSession | id, visit counter attribute, isNew() |
pageContext | PageContext | attributes in page and application scope, findAttribute, getSession() |
exception | Throwable | class name, message, first stack frame in error.jsp |
- The six objects are local variables that Tomcat declares at the top of
_jspService; that is why they exist without any import. exceptionexists only in a page markedisErrorPage="true". The page that can fail names its handler witherrorPage="error.jsp"; on an uncaught exception Tomcat forwards to it and sets theexceptionobject.error.jspalso serves theweb.xmlerror pages of Question 12, where it reads the status code from thejakarta.servlet.error.status_codeattribute.pageContext.findAttributesearches page, request, session then application scope in that order; it is what EL uses when it resolves a bare name.
Question 12
Problem Statement
Write in lab recordCreate a JSP Project implementing all the above (Session 1 and Session 2) concepts. Login Form, CRUD operation of Student details, Session Management with exception handling using Servlet and JSP. Make necessary assumptions required.
Solution
Write in lab recordAssumptions
- Single administrator account
admin/ignou123hard-coded inLoginServlet; a Users table with hashed passwords is left for Session 9 (Spring Security). Database,StudentandStudentDaoare those of Session 1, Question 5. - Session timeout is 10 minutes; after that any request to
/studentsreturns to the login page with a message. - All database and conversion errors surface either as a red message on the list page (expected errors such as a duplicate enrolment number) or on
error.jsp(anything unexpected, throughweb.xml).
Steps
- In
JspLabcopyStudent.javaandStudentDao.javafrom Session 1 into packageignou. - Add
LoginServlet,LogoutServlet,StudentControllerto packageignou. - Add
login.jspinsrc/main/webapp/(Question 11’serror.jspis reused as is). Create foldersrc/main/webapp/WEB-INF/views/and addstudents.jspandstudent-form.jspthere. - Replace
WEB-INF/web.xmlwith the listing below. - Run.
http://localhost:8080/JspLab/openslogin.jsp. Try a wrong password, then the correct one. Add, edit and delete a student as in Session 1. - Click Logout, then type
http://localhost:8080/JspLab/studentsdirectly: you land on the login page with “Please login first”. Open/JspLab/nothing.jspfor the 404 branch oferror.jsp; stop MySQL and open the list for the exception branch.
Program
Lab record: every tab is one file of the answer. Write all of them.
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/main/webapp/WEB-INF/web.xml for the JspLab project (Session 2).
Servlet URLs come from @WebServlet annotations; this file adds the
welcome page, the session timeout and the error pages used by Q12. -->
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<display-name>JspLab</display-name>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
<session-config>
<session-timeout>10</session-timeout> <!-- minutes of inactivity -->
<cookie-config>
<http-only>true</http-only>
</cookie-config>
</session-config>
<!-- Any exception that escapes a servlet or JSP lands on error.jsp -->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
</web-app><%-- Q12: src/main/webapp/login.jsp (welcome page of the project) --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%-- already logged in? go straight to the list --%>
<c:if test="${not empty sessionScope.user}">
<c:redirect url="/students" />
</c:if>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Login - IGNOU Student App</title></head>
<body>
<h2>IGNOU Student App - Login</h2>
<c:if test="${not empty param.error}">
<p style="color:red"><c:out value="${param.error}" /></p>
</c:if>
<c:if test="${param.out == '1'}">
<p style="color:green">You have been logged out.</p>
</c:if>
<form action="login" method="post">
<p><label>Username: <input name="username" required autofocus></label></p>
<p><label>Password: <input name="password" type="password" required></label></p>
<p><button type="submit">Login</button></p>
</form>
<p><small>Demo account: admin / ignou123</small></p>
</body>
</html>package ignou;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
/**
* Q12: checks the credentials posted by login.jsp and starts a session.
* Assumption: one fixed admin account is enough for the lab. A real system
* would look the user up in a Users table and compare a password hash.
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final String USER = "admin";
private static final String PASSWORD = "ignou123";
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.sendRedirect("login.jsp");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String user = request.getParameter("username");
String pass = request.getParameter("password");
if (USER.equals(user) && PASSWORD.equals(pass)) {
HttpSession old = request.getSession(false);
if (old != null) old.invalidate(); // fresh id on login (session fixation guard)
HttpSession session = request.getSession(true);
session.setAttribute("user", user);
session.setMaxInactiveInterval(10 * 60);
response.sendRedirect("students");
} else {
response.sendRedirect("login.jsp?error=" + java.net.URLEncoder.encode("Invalid username or password", "UTF-8"));
}
}
}package ignou;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
/** Q12: ends the session and returns to the login page. */
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession(false);
if (session != null) session.invalidate();
response.sendRedirect("login.jsp?out=1");
}
}package ignou;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
/**
* Q12: servlet controller; the JSPs under WEB-INF/views/ are the views.
* Every request first checks the session; without a logged-in user it
* redirects to login.jsp. Uses Student and StudentDao from Session 1, Q5.
* GET /students list
* GET /students?action=new empty form
* GET /students?action=edit&id= filled form
* POST /students action=insert | update | delete
*/
@WebServlet("/students")
public class StudentController extends HttpServlet {
private final StudentDao dao = new StudentDao();
private boolean loggedIn(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("user") == null) {
response.sendRedirect("login.jsp?error=" + java.net.URLEncoder.encode("Please login first", "UTF-8"));
return false;
}
return true;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (!loggedIn(request, response)) return;
String action = request.getParameter("action");
try {
if ("new".equals(action)) {
request.setAttribute("student", new Student());
request.setAttribute("editing", false);
request.getRequestDispatcher("/WEB-INF/views/student-form.jsp").forward(request, response);
} else if ("edit".equals(action)) {
Student s = dao.findById(request.getParameter("id"));
if (s == null) throw new ServletException("No student with enrolment number " + request.getParameter("id"));
request.setAttribute("student", s);
request.setAttribute("editing", true);
request.getRequestDispatcher("/WEB-INF/views/student-form.jsp").forward(request, response);
} else {
request.setAttribute("students", dao.findAll());
request.getRequestDispatcher("/WEB-INF/views/students.jsp").forward(request, response);
}
} catch (SQLException e) {
// Wrapped and rethrown: web.xml routes it to error.jsp
throw new ServletException("Database error: " + e.getMessage(), e);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (!loggedIn(request, response)) return;
request.setCharacterEncoding("UTF-8");
String action = request.getParameter("action");
String msg;
try {
switch (action == null ? "" : action) {
case "insert" -> { dao.insert(fromRequest(request)); msg = "Student added"; }
case "update" -> { dao.update(fromRequest(request)); msg = "Student updated"; }
case "delete" -> { dao.delete(request.getParameter("id")); msg = "Student deleted"; }
default -> msg = "Unknown action";
}
} catch (SQLException | NumberFormatException e) {
msg = "Could not save: " + e.getMessage(); // duplicate key, bad number, and so on
}
response.sendRedirect("students?msg=" + java.net.URLEncoder.encode(msg, "UTF-8"));
}
private static Student fromRequest(HttpServletRequest r) {
Student s = new Student();
s.setEnrolmentNo(r.getParameter("enrolmentNo").trim());
s.setName(r.getParameter("name").trim());
s.setDob(r.getParameter("dob"));
s.setGender(r.getParameter("gender"));
s.setEmail(r.getParameter("email").trim());
s.setMobile(r.getParameter("mobile").trim());
s.setAddress(r.getParameter("address"));
s.setCity(r.getParameter("city"));
s.setState(r.getParameter("state"));
s.setPincode(r.getParameter("pincode"));
s.setProgramme(r.getParameter("programme"));
s.setSemester(Integer.parseInt(r.getParameter("semester")));
s.setAdmissionYear(Integer.parseInt(r.getParameter("admissionYear")));
s.setStudyCentre(r.getParameter("studyCentre"));
String[] courses = r.getParameterValues("courses");
s.setCourses(courses == null ? "" : String.join(",", courses));
return s;
}
}<%-- Q12: src/main/webapp/WEB-INF/views/students.jsp
Under WEB-INF so it cannot be opened directly; only the controller forwards here. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fn" uri="jakarta.tags.functions" %>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Students</title></head>
<body>
<p style="float:right">Logged in as <b><c:out value="${sessionScope.user}" /></b> |
<a href="logout">Logout</a></p>
<h2>IGNOU Students (${fn:length(students)})</h2>
<c:if test="${not empty param.msg}">
<p style="color:green"><c:out value="${param.msg}" /></p>
</c:if>
<p><a href="students?action=new">Add new student</a></p>
<table border="1" cellpadding="4">
<tr><th>Enrolment</th><th>Name</th><th>DOB</th><th>Email</th><th>Mobile</th>
<th>Programme</th><th>Sem</th><th>Courses</th><th>Actions</th></tr>
<c:forEach var="s" items="${students}">
<tr>
<td><c:out value="${s.enrolmentNo}" /></td>
<td><c:out value="${s.name}" /></td>
<td>${s.dob}</td>
<td><c:out value="${s.email}" /></td>
<td><c:out value="${s.mobile}" /></td>
<td><c:out value="${s.programme}" /></td>
<td>${s.semester}</td>
<td><c:out value="${s.courses}" /></td>
<td>
<c:url var="editUrl" value="/students">
<c:param name="action" value="edit" />
<c:param name="id" value="${s.enrolmentNo}" />
</c:url>
<a href="${editUrl}">Edit</a>
<form method="post" action="students" style="display:inline"
onsubmit="return confirm('Delete ${s.enrolmentNo}?')">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<c:out value='${s.enrolmentNo}' />">
<button type="submit">Delete</button>
</form>
</td>
</tr>
</c:forEach>
<c:if test="${empty students}">
<tr><td colspan="9">No students yet. Add one.</td></tr>
</c:if>
</table>
</body>
</html><%-- Q12: src/main/webapp/WEB-INF/views/student-form.jsp
One page for both Add and Edit. The controller sets 'student' and 'editing'. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fn" uri="jakarta.tags.functions" %>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>${editing ? 'Edit' : 'Add'} Student</title></head>
<body>
<h2>${editing ? 'Edit' : 'Add'} Student</h2>
<form method="post" action="students">
<input type="hidden" name="action" value="${editing ? 'update' : 'insert'}">
<p><label>Enrolment No:
<input name="enrolmentNo" value="<c:out value='${student.enrolmentNo}' />"
pattern="[0-9]{9,12}" required ${editing ? 'readonly' : ''}></label></p>
<p><label>Name: <input name="name" value="<c:out value='${student.name}' />" required></label></p>
<p><label>Date of Birth: <input type="date" name="dob" value="${student.dob}" required></label></p>
<p>Gender:
<label><input type="radio" name="gender" value="M" ${student.gender != 'F' && student.gender != 'O' ? 'checked' : ''}> Male</label>
<label><input type="radio" name="gender" value="F" ${student.gender == 'F' ? 'checked' : ''}> Female</label>
<label><input type="radio" name="gender" value="O" ${student.gender == 'O' ? 'checked' : ''}> Other</label>
</p>
<p><label>Email: <input type="email" name="email" value="<c:out value='${student.email}' />" required></label></p>
<p><label>Mobile: <input name="mobile" value="<c:out value='${student.mobile}' />" pattern="[0-9]{10}" required></label></p>
<p><label>Address: <input name="address" value="<c:out value='${student.address}' />"></label></p>
<p><label>City: <input name="city" value="<c:out value='${student.city}' />"></label></p>
<p><label>State: <input name="state" value="<c:out value='${student.state}' />"></label></p>
<p><label>Pincode: <input name="pincode" value="<c:out value='${student.pincode}' />" pattern="[0-9]{6}"></label></p>
<p><label>Programme:
<select name="programme">
<c:forEach var="p" items="${['MCA', 'BCA', 'MSc', 'PGDCA']}">
<option ${student.programme == p ? 'selected' : ''}>${p}</option>
</c:forEach>
</select></label></p>
<p><label>Semester: <input type="number" name="semester" min="1" max="6"
value="${student.semester == 0 ? 1 : student.semester}"></label></p>
<p><label>Admission Year: <input type="number" name="admissionYear" min="2000" max="2099"
value="${student.admissionYear == 0 ? 2024 : student.admissionYear}"></label></p>
<p><label>Study Centre: <input name="studyCentre" value="<c:out value='${student.studyCentre}' />"></label></p>
<p>Courses:
<c:set var="chosen" value=",${student.courses},"/>
<c:forEach var="code" items="${['MCS-218', 'MCS-219', 'MCS-220', 'MCS-221', 'MCSL-222', 'MCSL-223']}">
<c:set var="key" value=",${code}," />
<label><input type="checkbox" name="courses" value="${code}"
${fn:contains(chosen, key) ? 'checked' : ''}> ${code}</label>
</c:forEach>
</p>
<p><button type="submit">Save</button> <a href="students">Cancel</a></p>
</form>
</body>
</html>Student.java and StudentDao.java are the Session 1, Question 5 listings, copied without change.
Output
Checked by reading, not executed. A wrong password returns to login.jsp with Invalid username or password in red above the form. After a correct login the browser is at /JspLab/students and shows Logged in as admin | Logout, the heading IGNOU Students (3), the Add new student link and the same three-row table as Session 1, Question 5, each row ending in Edit and a Delete button.
After Save on the edit form the same list reappears with Student updated in green. Visiting /students after Logout shows the login page with Please login first. With MySQL stopped, error.jsp shows Exception type: jakarta.servlet.ServletException, Message: Database error: Communications link failure. A wrong URL shows HTTP status 404 for /JspLab/nothing.jsp.
Explanation
- Flow:
login.jsp(view) posts toLoginServlet(controller), which storesuserin theHttpSessionand redirects toStudentController. The controller loads data throughStudentDao(model), puts it in request attributes and forwards to a JSP underWEB-INF/views/. That is Model-View-Controller with plain servlets and JSP, the shape Spring MVC automates in Sessions 3 to 5. - Session management:
loggedIn()runs before every action and checkssession.getAttribute("user"). Login invalidates any old session first so an attacker cannot plant a known session id (fixation).web.xmlsets a 10 minute timeout andhttp-onlyon the cookie;LogoutServletinvalidates and redirects. - Views under
WEB-INFcannot be requested by URL, so nobody can openstudents.jspwithout going through the controller and its login check. - Exception handling has two levels. Expected failures (duplicate key, bad number) are caught in
doPostand shown as a message. Anything else is wrapped inServletExceptionand left to the container, which theerror-pageentries route toerror.jsp; the same page handles 404. - The views use JSTL and EL only (
c:forEach,c:out,c:url,c:if,fn:contains), no scriptlets; every POST ends in a redirect to/students(Post-Redirect-Get).
Viva Questions
Do not copy. Read for understanding and the viva- Q: How is a JSP different from a servlet? A: A JSP is translated into a servlet by the container; it is HTML with embedded Java rather than Java with embedded HTML, so it suits the view layer.
- Q: What is the JSP life cycle? A: Translation to a
.javafile, compilation, class loading,jspInit(),_jspService()per request,jspDestroy(). - Q: Difference between the include directive and
jsp:include? A: The directive merges source at translation time; the action calls the resource at request time and can pass parameters. - Q: Why prefer JSTL and EL over scriptlets? A: Views stay readable, output is escaped by default, no Java in HTML, and designers can edit the page.
- Q: How does
errorPagediffer from theerror-pageinweb.xml? A:errorPageis per JSP;web.xmlmappings apply to the whole application and also cover servlets and HTTP status codes. - Q: Why put JSPs under
WEB-INF? A: The container never servesWEB-INFdirectly, so the pages can only be reached by a forward from a servlet that has done its checks. - Q: What is the JSTL core URI for Tomcat 10.1? A:
jakarta.tags.core(JSTL 3.0); the oldjava.sun.comURI is for thejavaxversions.
Common Mistakes
Do not copy. Read for understanding and the viva- Using the JSTL 1.2 URI or jar on Tomcat 10.1: “The absolute uri cannot be resolved” at translation time.
- Setting a header or calling
c:redirectafter HTML has been written:IllegalStateException: response already committed. - A bean without a public no-arg constructor or with a getter that does not match the property name:
jsp:useBeanorgetPropertyfails at run time. - Forgetting
isErrorPage="true": theexceptionobject is undefined and the error page itself fails to compile. - Leaving
students.jspoutsideWEB-INF, which lets anyone skip the login check by typing its URL.
Session Summary
Write in lab record- Project
JspLabon Tomcat 10.1 with JSTL 3.0 (jakarta.tags.core) andmysql-connector-j - Question 6:
datetime.jspwith date, time, timestamp and 5 second auto-refresh (Refresh header and meta tag) - Question 7:
scripting.jspwith declaration, scriptlet and expression elements - Question 8:
jstl-demo.jspusingc:out,c:if,c:forEach,c:choose/c:when/c:otherwise,c:url,c:redirect - Question 9:
student-list.jspreading the IGNOU Student table through JDBC - Question 10:
StudentBean,header.jsp,action-demo.jsp,bean-view.jspusingjsp:include,jsp:forward,jsp:useBean,jsp:setProperty,jsp:getProperty - Question 11:
implicit.jspanderror.jspcoveringout,request,response,session,pageContext,exception - Question 12: login (
login.jsp,LoginServlet,LogoutServlet),StudentControllerwith session check, viewsstudents.jspandstudent-form.jspunderWEB-INF/views,web.xmlerror pages