File 26: Attendance Management Backend (attendance.jsp)

File 26: Attendance Management Backend (attendance.jsp)

Folder: OnlineClassAttendance/admin/attendance.jsp

1. Purpose

This JSP file connects the attendance management page with Oracle Database. It uses JDBC to load students, save attendance, and retrieve attendance records.

2. Complete JSP Source Code

<%@ page import="java.sql.*" %>
<%@ page import="org.json.*" %>
<%@ page contentType="application/json; charset=UTF-8" pageEncoding="UTF-8" %>

<%
    // Check administrator session
    Integer userId = (Integer) session.getAttribute("userId");
    String role = (String) session.getAttribute("role");

    if (userId == null || !"ADMIN".equals(role)) {
        response.setStatus(401);
        out.print("{\"success\":false,\"message\":\"Unauthorized access\"}");
        return;
    }

    String action = request.getParameter("action");
    String sessionText = request.getParameter("sessionId");

    String dbURL = "jdbc:oracle:thin:@localhost:1521/XEPDB1";
    String dbUser = "YOUR_DB_USERNAME";
    String dbPassword = "YOUR_DB_PASSWORD";

    try {

        Class.forName("oracle.jdbc.OracleDriver");

        try (Connection con = DriverManager.getConnection(
                dbURL, dbUser, dbPassword)) {

            // Validate session ID
            int sessionId;

            try {
                sessionId = Integer.parseInt(sessionText);

                if (sessionId <= 0) {
                    throw new NumberFormatException();
                }

            } catch (Exception ex) {
                response.setStatus(400);
                out.print("{\"success\":false,\"message\":\"Valid session ID is required\"}");
                return;
            }

            // Check whether session exists
            String checkSessionSQL =
                "SELECT COUNT(*) FROM SESSIONS WHERE SESSION_ID = ?";

            try (PreparedStatement ps =
                    con.prepareStatement(checkSessionSQL)) {

                ps.setInt(1, sessionId);

                try (ResultSet rs = ps.executeQuery()) {

                    rs.next();

                    if (rs.getInt(1) == 0) {
                        response.setStatus(404);
                        out.print("{\"success\":false,\"message\":\"Class session not found\"}");
                        return;
                    }
                }
            }

            // =====================================
            // SAVE ATTENDANCE
            // =====================================

            if ("save".equalsIgnoreCase(action)) {

                String attendanceData =
                    request.getParameter("attendanceData");

                if (attendanceData == null ||
                    attendanceData.trim().isEmpty()) {

                    response.setStatus(400);
                    out.print("{\"success\":false,\"message\":\"Attendance data is required\"}");
                    return;
                }

                JSONArray attendanceArray;

                try {
                    attendanceArray = new JSONArray(attendanceData);
                } catch (JSONException ex) {
                    response.setStatus(400);
                    out.print("{\"success\":false,\"message\":\"Invalid attendance data\"}");
                    return;
                }

                if (attendanceArray.length() == 0) {
                    response.setStatus(400);
                    out.print("{\"success\":false,\"message\":\"No attendance records supplied\"}");
                    return;
                }

                // Get enrolled students for this session
                String enrolledSQL =
                    "SELECT E.STUDENT_ID " +
                    "FROM ENROLLMENTS E " +
                    "JOIN SESSIONS S ON E.OFFERING_ID = S.OFFERING_ID " +
                    "WHERE S.SESSION_ID = ?";

                java.util.Set<Integer> enrolledStudents =
                    new java.util.HashSet<Integer>();

                try (PreparedStatement ps =
                        con.prepareStatement(enrolledSQL)) {

                    ps.setInt(1, sessionId);

                    try (ResultSet rs = ps.executeQuery()) {

                        while (rs.next()) {
                            enrolledStudents.add(rs.getInt("STUDENT_ID"));
                        }
                    }
                }

                if (enrolledStudents.isEmpty()) {
                    response.setStatus(400);
                    out.print("{\"success\":false,\"message\":\"No enrolled students found for this session\"}");
                    return;
                }

                // Validate every attendance entry before saving
                java.util.Set<Integer> submittedStudents =
                    new java.util.HashSet<Integer>();

                for (int i = 0; i < attendanceArray.length(); i++) {

                    JSONObject item = attendanceArray.getJSONObject(i);

                    int studentId = item.getInt("studentId");

                    String status = item.getString("status");

                    if (!enrolledStudents.contains(studentId) ||
                        !submittedStudents.add(studentId)) {

                        response.setStatus(400);
                        out.print("{\"success\":false,\"message\":\"Invalid or duplicate student in attendance data\"}");
                        return;
                    }

                    if (!status.equals("PRESENT") &&
                        !status.equals("ABSENT") &&
                        !status.equals("LATE") &&
                        !status.equals("EXCUSED")) {

                        response.setStatus(400);
                        out.print("{\"success\":false,\"message\":\"Invalid attendance status\"}");
                        return;
                    }
                }

                // Save or update attendance
                String mergeSQL =
                    "MERGE INTO ATTENDANCE A " +
                    "USING (SELECT ? SESSION_ID, ? STUDENT_ID FROM DUAL) X " +
                    "ON (A.SESSION_ID = X.SESSION_ID " +
                    "AND A.STUDENT_ID = X.STUDENT_ID) " +
                    "WHEN MATCHED THEN UPDATE SET " +
                    "A.STATUS = ?, A.REMARKS = ? " +
                    "WHEN NOT MATCHED THEN INSERT " +
                    "(SESSION_ID, STUDENT_ID, STATUS, REMARKS) " +
                    "VALUES (X.SESSION_ID, X.STUDENT_ID, ?, ?)";

                boolean originalAutoCommit = con.getAutoCommit();

                try {
                    con.setAutoCommit(false);

                    try (PreparedStatement ps =
                            con.prepareStatement(mergeSQL)) {

                        for (int i = 0; i < attendanceArray.length(); i++) {

                            JSONObject item =
                                attendanceArray.getJSONObject(i);

                            int studentId = item.getInt("studentId");

                            String status = item.getString("status");

                            String remarks =
                                item.optString("remarks", "");

                            if (remarks.trim().isEmpty()) {
                                remarks = null;
                            }

                            ps.setInt(1, sessionId);
                            ps.setInt(2, studentId);
                            ps.setString(3, status);
                            ps.setString(4, remarks);
                            ps.setString(5, status);
                            ps.setString(6, remarks);

                            ps.addBatch();
                        }

                        ps.executeBatch();
                    }

                    con.commit();

                    out.print("{\"success\":true,\"message\":\"Attendance saved successfully\"}");

                } catch (Exception ex) {

                    con.rollback();
                    throw ex;

                } finally {
                    con.setAutoCommit(originalAutoCommit);
                }

            } else {

                // =====================================
                // LOAD STUDENTS OR VIEW RECORDS
                // =====================================

                boolean viewRecords =
                    "records".equalsIgnoreCase(
                        request.getParameter("view"));

                String sql;

                if (viewRecords) {

                    sql =
                        "SELECT S.STUDENT_ID, S.STUDENT_NAME, " +
                        "A.STATUS, A.REMARKS " +
                        "FROM ENROLLMENTS E " +
                        "JOIN SESSIONS CS ON E.OFFERING_ID = CS.OFFERING_ID " +
                        "JOIN STUDENTS S ON E.STUDENT_ID = S.STUDENT_ID " +
                        "LEFT JOIN ATTENDANCE A ON " +
                        "A.SESSION_ID = CS.SESSION_ID " +
                        "AND A.STUDENT_ID = S.STUDENT_ID " +
                        "WHERE CS.SESSION_ID = ? " +
                        "ORDER BY S.STUDENT_ID";

                } else {

                    sql =
                        "SELECT S.STUDENT_ID, S.STUDENT_NAME, S.BATCH, " +
                        "A.STATUS, A.REMARKS " +
                        "FROM ENROLLMENTS E " +
                        "JOIN SESSIONS CS ON E.OFFERING_ID = CS.OFFERING_ID " +
                        "JOIN STUDENTS S ON E.STUDENT_ID = S.STUDENT_ID " +
                        "LEFT JOIN ATTENDANCE A ON " +
                        "A.SESSION_ID = CS.SESSION_ID " +
                        "AND A.STUDENT_ID = S.STUDENT_ID " +
                        "WHERE CS.SESSION_ID = ? " +
                        "ORDER BY S.STUDENT_ID";
                }

                StringBuilder json = new StringBuilder();

                if (viewRecords) {
                    json.append("{\"success\":true,\"records\":[");
                } else {
                    json.append("{\"success\":true,\"students\":[");
                }

                try (PreparedStatement ps =
                        con.prepareStatement(sql)) {

                    ps.setInt(1, sessionId);

                    try (ResultSet rs = ps.executeQuery()) {

                        boolean first = true;

                        while (rs.next()) {

                            if (!first) {
                                json.append(",");
                            }

                            first = false;

                            json.append("{");

                            json.append("\"studentId\":")
                                .append(rs.getInt("STUDENT_ID"))
                                .append(",");

                            json.append("\"studentName\":")
                                .append(JSONObject.quote(
                                    rs.getString("STUDENT_NAME")))
                                .append(",");

                            if (!viewRecords) {
                                json.append("\"batch\":")
                                    .append(JSONObject.quote(
                                        rs.getString("BATCH")))
                                    .append(",");
                            }

                            String status = rs.getString("STATUS");

                            json.append("\"status\":");

                            if (status == null) {
                                json.append("null");
                            } else {
                                json.append(JSONObject.quote(status));
                            }

                            json.append(",");

                            String remarks = rs.getString("REMARKS");

                            json.append("\"remarks\":");

                            if (remarks == null) {
                                json.append("null");
                            } else {
                                json.append(JSONObject.quote(remarks));
                            }

                            json.append("}");
                        }
                    }
                }

                json.append("]}");

                out.print(json.toString());
            }
        }

    } catch (Exception e) {

        application.log("Error in attendance.jsp", e);

        if (!response.isCommitted()) {
            response.setStatus(500);
            out.print("{\"success\":false,\"message\":\"An internal server error occurred\"}");
        }
    }
%>

3. How the Code Works

  1. Session verification: Checks whether the selected class session exists.
  2. Student retrieval: Retrieves students enrolled in the selected course offering.
  3. Attendance validation: Checks student IDs and attendance status values.
  4. MERGE statement: Updates existing attendance records or inserts new records.
  5. Transaction management: Saves all submitted attendance records together. If an error occurs, the transaction is rolled back.
  6. Attendance retrieval: Uses SQL JOIN operations to retrieve saved attendance information.
  7. JSON response: Sends student and attendance information to attendance.html.

4. Expected Database Table

Execute this SQL statement if the ATTENDANCE table has not already been created:

CREATE TABLE ATTENDANCE (
    ATTENDANCE_ID NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    SESSION_ID NUMBER NOT NULL,
    STUDENT_ID NUMBER NOT NULL,
    STATUS VARCHAR2(20) NOT NULL,
    REMARKS VARCHAR2(300),

    CONSTRAINT FK_ATT_SESSION
        FOREIGN KEY (SESSION_ID)
        REFERENCES SESSIONS(SESSION_ID),

    CONSTRAINT FK_ATT_STUDENT
        FOREIGN KEY (STUDENT_ID)
        REFERENCES STUDENTS(STUDENT_ID),

    CONSTRAINT UK_SESSION_STUDENT
        UNIQUE (SESSION_ID, STUDENT_ID),

    CONSTRAINT CK_ATT_STATUS
        CHECK (STATUS IN ('PRESENT', 'ABSENT', 'LATE', 'EXCUSED'))
);

5. How to Test

  1. Start Oracle Database and Apache Tomcat.
  2. Log in as an administrator.
  3. Open admin/attendance.html.
  4. Select an existing class session.
  5. Click Load Students.
  6. Assign attendance statuses to students.
  7. Click Save Attendance.
  8. Click View Attendance to verify the saved records.
  9. Change a student's attendance status and save again. The existing record should be updated instead of duplicated.

6. Important Configuration

  • Replace YOUR_DB_USERNAME and YOUR_DB_PASSWORD with your Oracle credentials.
  • Ensure ojdbc8.jar and json.jar are available in Tomcat's library folder.
  • Use the same database schema as the previous project files.
  • This implementation assumes the Oracle SESSIONS, OFFERINGS, ENROLLMENTS, STUDENTS, and ATTENDANCE tables have been created.

Important concept: The SQL MERGE statement is useful when an application needs to insert a record if it does not exist or update it if it already exists.


Next File: File 27 of 28 — admin/reports.html

In the next tutorial, we will create an attendance reporting page to view student attendance summaries and records.

কোন মন্তব্য নেই:

একটি মন্তব্য পোস্ট করুন