Java 3 - 2025

Week 6

EditProfile Servlet

  • Create a new servlet called "EditProfile". Add the following code.
  • This page should be restricted to logged in users.
    • Get the "activeUser" session attribute from the session.
    • If the attribute is not set, redirect them to the login page.
  • In top-nav.jspf, update the "Edit Profile" button link.
    <a href="${appURL}/edit-profile" class="btn btn-primary me-2">Edit Profile</a>

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;

@WebServlet("/edit-profile")
public class EditProfile extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        User user = (User)session.getAttribute("activeUser");
        if(user == null) {
            session.setAttribute("flashMessageWarning", "You must be logged in to edit your profile.");
            resp.sendRedirect(resp.encodeRedirectURL(req.getContextPath() + "/login?redirect=edit-profile"));
            return;
        } else if(user != null && !user.getStatus().equals("active")) {
            session.setAttribute("flashMessageDanger", "Your account is locked or inactive.");
            resp.sendRedirect(resp.encodeRedirectURL(req.getContextPath() + "/"));
            return;
        }
        req.setAttribute("pageTitle", "Edit Profile");
        req.getRequestDispatcher("WEB-INF/edit-profile.jsp").forward(req, resp);
    }
}

Login Servlet doGet

  • Add these lines to the doGet method of the Login Servlet.
String redirect = req.getParameter("redirect");
if(redirect != null && !redirect.equals("")) {
    req.setAttribute("redirect", redirect);
}

login.jsp

  • Add this hidden field as a child of the form tag.
<input type="hidden" name="redirect" value="${redirect}">

Login Servlet doPost

  • Add this code to the doPost method of the Login Servlet.
  • Instead of always redirecting to the home page, write an if statement to determine where to redirect.
String redirect = req.getParameter("redirect");
req.setAttribute("redirect", redirect);
// code omitted
// Flash Message that greets the user
if(redirect != null && !redirect.equals("")) {
    resp.sendRedirect(resp.encodeRedirectURL(req.getContextPath() + "/" + redirect));
} else {
    resp.sendRedirect(resp.encodeRedirectURL(req.getContextPath() + "/")); // Redirects to the home page
}

left-sidebar.jspf

  • Create a new JSP called "left-sidebar.jspf". Add this code.
  • Note the class attribute of each a tag. Be sure it includes an expression to apply the active class dynamically.
<div class="col-lg-3">
    <!-- Responsive offcanvas body START -->
    <div class="offcanvas-lg offcanvas-start" tabindex="-1" id="offcanvasSidebar">
        <!-- Offcanvas header -->
        <div class="offcanvas-header bg-light">
            <button  type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#offcanvasSidebar" aria-label="Close"></button>
        </div>
        <!-- Offcanvas body -->
        <div class="offcanvas-body p-3 p-lg-0">
            <div class="bg-light border rounded-3 p-3 w-100">
                <!-- Dashboard menu -->
                <div class="list-group list-group-light list-group-borderless">
                    <a class="list-group-item ${pageTitle == "Edit Profile" ? "active" : ""}" href="${appURL}/edit-profile"><i class="bi bi-person-gear me-2"></i>Edit Profile</a>
                    <a class="list-group-item ${pageTitle == "Delete Account" ? "active" : ""}" href="${appURL}/delete-account"><i class="bi bi-trash me-2"></i>Delete Account</a>
                </div>
            </div>
        </div>
    </div>
    <!-- Responsive offcanvas body END -->
</div>

edit-profile-header.jspf

  • Create a new JSP called "edit-profile-header.jspf". Add this code.
<section class="my-4">
    <div class="container">
        <div class="row">
            <!-- Profile banner START -->
            <div class="col-12">
                <div class="card bg-light card-body">
                    <!-- Profile info -->
                    <div class="col d-flex justify-content-between align-items-center">
                        <div>
                            <h4>Good morning<c:if test="${not empty activeUser.firstName}">, ${activeUser.firstName}</c:if>!</h4>
                            <ul class="list-inline mb-0">
                                <li class="list-item"><i class="bi bi-calendar-event-fill fs-6"></i> March 1 20XX, 8:00 AM</li>
                                <li class="list-item"><i class="bi bi-star-fill fs-6"></i> Member since January 1, 20XX</li>
                            </ul>
                        </div>
                        <!-- Responsive toggler START -->
                        <button class="btn btn-primary d-lg-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasSidebar" aria-controls="offcanvasSidebar">
                            <i class="bi bi-list fs-4"></i>
                        </button>
                        <!-- Responsive toggler END -->
                    </div>
                </div>
            </div>
            <!-- Profile banner END -->
        </div>
    </div>
</section>

edit-profile.jsp

  • Create a new JSP called "edit-profile.jsp". Add this code.
  • Run the program and test the redirect functionality by visiting "/edit-profile".
<main>
    <%@ include file="/WEB-INF/edit-profile-header.jspf" %>

    <!-- Page content START -->
    <section class="pt-0">
        <div class="container">
            <div class="row">
                <%@ include file="/WEB-INF/left-sidebar.jspf" %>

                <!-- Main content START -->
                <div class="col-lg-9">
                    <!-- Edit profile START -->
                    <div class="card bg-transparent border rounded-3">
                        <!-- Card header -->
                        <div class="card-header bg-light border-bottom">
                            <h3 class="card-header-title mb-0">Edit Profile</h3>
                        </div>
                        <!-- Card body START -->
                        <div class="card-body">
                            <!-- Form -->
                            <form class="row g-4">

                                <!-- First name -->
                                <div class="col-md-6">
                                    <label class="form-label" for="firstName">First Name</label>
                                    <input class="form-control" type="text" id="firstName" name="firstName">
                                </div>

                                <!-- Last name -->
                                <div class="col-md-6">
                                    <label class="form-label" for="lastName">Last Name</label>
                                    <input type="text" class="form-control" id="lastName" name="lastName">
                                </div>

                                <!-- Email id -->
                                <div class="col-md-6">
                                    <label class="form-label" for="email">Email</label>
                                    <input class="form-control" type="text" id="email" name="email">
                                </div>

                                <!-- Phone number -->
                                <div class="col-md-6">
                                    <label class="form-label" for="phone">Phone number</label>
                                    <input type="text" class="form-control" id="phone" name="phone">
                                </div>

                                <!-- Select option -->
                                <div class="col-md-6">
                                    <!-- Language Preference -->
                                    <label class="form-label" for="language">Language</label>
                                    <select class="form-select js-choice z-index-9 bg-transparent" aria-label=".form-select-sm" id="language" name="language">
                                        <option value="en-US">English</option>
                                        <option value="es-MX">Spanish</option>
                                        <option value="fr-FR">French</option>
                                    </select>
                                </div>

                                <!-- Save button -->
                                <div class="d-sm-flex justify-content-end">
                                    <button type="submit" class="btn btn-primary mb-0">Save changes</button>
                                </div>
                            </form>
                        </div>
                        <!-- Card body END -->
                    </div>
                    <!-- Edit profile END -->
                </div>
                <!-- Main content END -->
            </div><!-- Row END -->
        </div>
    </section>
</main>

End Day 11

edit-profile.jsp

  • Add this value attribute to the Email field.

    value="${activeUser.email}"

  • Refresh the page and the user's email will be populated in the form.

  • The remaining fields currently don't have values in the database, but we should still set them.

  • Add a value attribute to the First name input.
    value="${activeUser.firstName}"

  • Add a value attribute to the Last name input.
    value="${activeUser.lastName}"

  • Add a value attribute to the Phone input.
    value="${activeUser.phone}"

edit-profile.jsp

  • Add an expression to select one of the languages. You are welcome to add or remove languages. You must have at least 3.
    <option value="en-US" ${activeUser.language == 'en-US' ? 'selected' : ''}>English</option>
    <option value="es-MX" ${activeUser.language == 'es-MX' ? 'selected' : ''}>Spanish</option>
    <option value="fr-FR" ${activeUser.language == 'fr-FR' ? 'selected' : ''}>French</option>

  • Use language code and country code combinations.
  • Here are some common combinations.
  • Set the form attributes.

    <form class="row g-4" method="POST" action="${appURL}/edit-profile">

EditProfile Servlet doPost

  • Create a doPost method in the EditProfile Servlet. Add this code to get the form parameters and the active user object.

  • I only set the email and phone as request attributes because those are the only two text inputs that will be validated

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String firstName = req.getParameter("firstName");
    String lastName = req.getParameter("lastName");
    String email = req.getParameter("email");
    String phone = req.getParameter("phone");
    String language = req.getParameter("language");
	req.setAttribute("email", email);
    req.setAttribute("phone", phone);
    
    HttpSession session = req.getSession();
    User activeUser = (User)session.getAttribute("activeUser");
    

    req.setAttribute("pageTitle", "Edit Profile");
    req.getRequestDispatcher("WEB-INF/edit-profile.jsp").forward(req, resp);
}

2026???

  • Do I need to make a hard copy of the activeUser?

  • As written, calling the set method updates the user in the session.

  • Create new user
    Error when immediately visiting edit profile page because "created at" isn't set 

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String firstName = req.getParameter("firstName");
    String lastName = req.getParameter("lastName");
    String email = req.getParameter("email");
    String phone = req.getParameter("phone");
    String language = req.getParameter("language");
	req.setAttribute("email", email);
    req.setAttribute("phone", phone);
    
    HttpSession session = req.getSession();
    User activeUser = (User)session.getAttribute("activeUser");
    

    req.setAttribute("pageTitle", "Edit Profile");
    req.getRequestDispatcher("WEB-INF/edit-profile.jsp").forward(req, resp);
}

EditProfile Servlet doPost

  • Create a series of try-catch statements that check if the input value differs from the current values set in the activeUser object.

    • If true, call the User class set methods to validate the input.

  • For the email validation, note that I am first checking if the email already exists, then I am checking if it is valid. If I reversed the order of the statements, the program would set any valid email, even if it were already taken.

boolean errorFound = false;
try {
    if(!firstName.equals(activeUser.getFirstName())) {
        activeUser.setFirstName(firstName);
    }
} catch(IllegalArgumentException e) {
	errorFound = true;
    req.setAttribute("firstNameError", e.getMessage());
}

try {
    if(!lastName.equals(activeUser.getLastName())) {
        activeUser.setLastName(lastName);
    }
} catch(IllegalArgumentException e) {
	errorFound = true;
    req.setAttribute("lastNameError", e.getMessage());
}

if(email != null && !email.equals("") && !email.equals(activeUser.getEmail()) && UserDAO.get(email) != null) {
	errorFound = true;
    req.setAttribute("emailError", "A user with that email already exists.");
} else {
    try {
        activeUser.setEmail(email);
    } catch(IllegalArgumentException e) {
        req.setAttribute("emailError", e.getMessage());
    }
}

try {
    if(phone != null && !phone.equals(activeUser.getPhone())) {
        activeUser.setPhone(phone);
    }
} catch(IllegalArgumentException e) {
	errorFound = true;
    req.setAttribute("phoneError", e.getMessage());
}

try {
    if(!language.equals(activeUser.getLanguage())) {
        activeUser.setLanguage(language);
    }
} catch(IllegalArgumentException e) {
	errorFound = true;
    req.setAttribute("languageError", e.getMessage());
}

Validators Class

  • Add Patterns for a US Phone number and Language.

  • You may change the language code to whatever matches your select menu.

public static boolean isValidPhone(String phone) {
    String regex = "^\\D?(\\d{3})\\D?\\D?(\\d{3})\\D?(\\d{4})$";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(phone);
    return matcher.matches();
}

public static boolean isValidLanguage(String language) {
    String regex = "^(en-US|es-MX|fr-FR)$";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(language);
    return matcher.matches();
}

User Class

  • Write code to validate the phone number and language in the set methods.

  • The phone number will allow empty strings because they are optional.

  • If a phone number is entered it will be validated.

public void setPhone(String phone) {
    if (phone != null && !phone.trim().isEmpty() && !Validators.isValidPhone(phone)) {
        throw new IllegalArgumentException("Invalid phone number");
    }
    this.phone = phone;
}

public void setLanguage(String language) {
    if (!Validators.isValidLanguage(language)) {
        throw new IllegalArgumentException("Invalid language");
    }
    this.language = language;
}

EditProfile Servlet doPost

  • If there are no errors, update the user in the database and reset the activeUser session attribute.

if (!errorFound) {
    UserDAO.update(activeUser);
    session.setAttribute("activeUser", activeUser);
    session.setAttribute("flashMessageSuccess", "Your profile was updated");
} else {
    session.setAttribute("flashMessageWarning", "Your profile was not updated");
}

Update User

CREATE PROCEDURE sp_update_user(
    IN orig_user_id int,
    IN orig_first_name VARCHAR(255),
    IN orig_last_name VARCHAR(255),
    IN orig_email VARCHAR(255),
    IN orig_phone VARCHAR(255),
    IN orig_language VARCHAR(255),
    IN orig_status VARCHAR(255),
    IN orig_privileges VARCHAR(255),
    IN orig_timezone VARCHAR(50),
    IN new_first_name VARCHAR(255),
    IN new_last_name VARCHAR(255),
    IN new_email VARCHAR(255),
    IN new_phone VARCHAR(255),
    IN new_language VARCHAR(255),
    IN new_status VARCHAR(255),
    IN new_privileges VARCHAR(255),
    IN new_timezone VARCHAR(50)
)
BEGIN
    UPDATE user
    SET first_name =  new_first_name,
        last_name =  new_last_name,
        email =  new_email,
        phone =  new_phone,
        language =  new_language,
        status = new_status,
        privileges = new_privileges,
        timezone = new_timezone
    WHERE user_id = orig_user_id
      AND first_name =  orig_first_name
        AND last_name =  orig_last_name
        AND email =  orig_email
        AND phone =  orig_phone
        AND language =  orig_language
        AND status = orig_status
        AND privileges = orig_privileges
        AND timezone = orig_timezone;
END

2026, Also delete any password_reset records. If a record exists, the foreign key constraint will prevent you from updating your email address.

See the code I wrote in week 9

public static boolean update(User user) {
    try(Connection connection = getConnection();
        CallableStatement statement = connection.prepareCall("{CALL sp_update_user(?,?,?,?,?,?,?,?,?)}")
    ) {
        statement.setInt(1, user.getUserId());
        statement.setString(2, user.getFirstName());
        statement.setString(3, user.getLastName());
        statement.setString(4, user.getEmail());
        statement.setString(5, user.getPhone());
        statement.setString(6, user.getLanguage());
        statement.setString(7, user.getStatus());
        statement.setString(8, user.getPrivileges());
        statement.setString(9, user.getTimezone());
        int rowsAffected = statement.executeUpdate();
        return rowsAffected == 1;
    } catch(SQLException e) {
        System.out.println(e.getMessage());
        return false;
    }
}
  • Implement a method to update a User. 

UserDAO

edit-profile.jsp

  • Add invalid-feedback blocks below each of the form inputs.

    <c:if test="${not empty firstNameError}"><div class="invalid-feedback">${firstNameError}</div></c:if>

    <c:if test="${not empty lastNameError}"><div class="invalid-feedback">${lastNameError}</div></c:if>

    <c:if test="${not empty emailError }"><div class="invalid-feedback">${emailError}</div></c:if>

    <c:if test="${not empty phoneError }"><div class="invalid-feedback">${phoneError}</div></c:if>

    <c:if test="${not empty languageError }"><div class="invalid-feedback">${languageError}</div></c:if>

edit-profile.jsp

  • Add a statement to the class attribute of each input tag.

    class="form-control <c:if test="${not empty firstNameError}">is-invalid</c:if>"

    class="form-control <c:if test="${not empty lastNameError}">is-invalid</c:if>"

    class="form-control <c:if test="${not empty emailError}">is-invalid</c:if>"

    class="form-control <c:if test="${not empty phoneError}">is-invalid</c:if>"

    class="form-select <c:if test="${not empty languageError}">is-invalid</c:if>

Run the program

  • Run the program to test the form. If an invalid email address or phone number is entered, the values from the activeUser session variable will display.

  • We will eventually use the phone number to send text messages and phone calls, and use the language to display content on our website in a different language.

  • We will edit the "Good morning" text, current date/time, and replace "January 1, 2000" with the created_at date in an upcoming lesson.

Time Zone

  • An opportunity to exceed expectation this week will be to add a form field asking the user for their time zone.

  • Run this code to view a list of all supported time zone IDs.

public static void main(String[] args) {
    java.util.Arrays.asList(java.util.TimeZone.getAvailableIDs()).forEach(System.out::println);
}

2026

  • Use white label text if your project has a dark background

  • Storing the user's date of birth as a date in the database.
    Declare the date of birth as a LocalDate in the User class. Use LocalDate instead.
    Call setDate in the UserDAO methods.
    Convert LocalDate to Date in the update method. https://www.baeldung.com/java-date-to-localdate-and-localdatetime#localdate-date

Java 3 - Week 6

By Marc Hauschildt

Java 3 - Week 6

  • 243