Java Struts2

Struts2 CRUD – Insert, Update, Delete, Retrieve with MySQL and Bootstrap

Struts2 CRUD – Insert, Update, Delete, Retrieve with MySQL and Bootstrap

This tutorial builds a complete Struts2 CRUD application for a User management screen. The stack is: Struts2 2.5 (Action classes + struts.xml) + JDBC (raw SQL, no ORM) + MySQL + Bootstrap 5 + JSTL for the data table. All four operations — add, edit, delete, list — run on a single JSP with Bootstrap modals for the forms.

MySQL Table

CREATE TABLE user_details (
    user_id    INT          AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(100) NOT NULL,
    last_name  VARCHAR(100) NOT NULL,
    email      VARCHAR(200) NOT NULL,
    mobile     VARCHAR(15)
);

Maven Dependencies (pom.xml)

<dependencies>
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts2-core</artifactId>
        <version>2.5.33</version>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

Project Structure

src/main/
  java/com/java9r/
    model/      UserBean.java
    dao/        UserDAO.java
    db/         DBConnection.java
    action/     UserAction.java
  resources/
    struts.xml
  webapp/
    WEB-INF/
      web.xml
    index.jsp          (redirects to list)
    UserList.jsp       (main CRUD page)

DBConnection.java

package com.java9r.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBConnection {

    private static final String URL      = "jdbc:mysql://localhost:3306/java9rdb?useSSL=false&serverTimezone=UTC";
    private static final String USER     = "root";
    private static final String PASSWORD = "yourpassword";

    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("MySQL driver not found", e);
        }
    }

    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }
}

UserBean.java

package com.java9r.model;

public class UserBean {

    private int    userId;
    private String firstName;
    private String lastName;
    private String email;
    private String mobile;

    // Getters and Setters
    public int    getUserId()    { return userId;    }
    public String getFirstName() { return firstName; }
    public String getLastName()  { return lastName;  }
    public String getEmail()     { return email;     }
    public String getMobile()    { return mobile;    }

    public void setUserId(int userId)       { this.userId = userId;       }
    public void setFirstName(String firstName) { this.firstName = firstName; }
    public void setLastName(String lastName)   { this.lastName = lastName;   }
    public void setEmail(String email)         { this.email = email;         }
    public void setMobile(String mobile)       { this.mobile = mobile;       }
}

UserDAO.java

package com.java9r.dao;

import com.java9r.db.DBConnection;
import com.java9r.model.UserBean;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class UserDAO {

    public List<UserBean> getAllUsers() {
        List<UserBean> list = new ArrayList<>();
        String sql = "SELECT user_id, first_name, last_name, email, mobile FROM user_details ORDER BY user_id";

        try (Connection con = DBConnection.getConnection();
             Statement  st  = con.createStatement();
             ResultSet  rs  = st.executeQuery(sql)) {

            while (rs.next()) {
                UserBean u = new UserBean();
                u.setUserId(rs.getInt("user_id"));
                u.setFirstName(rs.getString("first_name"));
                u.setLastName(rs.getString("last_name"));
                u.setEmail(rs.getString("email"));
                u.setMobile(rs.getString("mobile"));
                list.add(u);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }

    public void addUser(UserBean u) {
        String sql = "INSERT INTO user_details (first_name, last_name, email, mobile) VALUES (?,?,?,?)";

        try (Connection con = DBConnection.getConnection();
             PreparedStatement ps = con.prepareStatement(sql)) {

            ps.setString(1, u.getFirstName());
            ps.setString(2, u.getLastName());
            ps.setString(3, u.getEmail());
            ps.setString(4, u.getMobile());
            ps.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void updateUser(UserBean u) {
        String sql = "UPDATE user_details SET first_name=?, last_name=?, email=?, mobile=? WHERE user_id=?";

        try (Connection con = DBConnection.getConnection();
             PreparedStatement ps = con.prepareStatement(sql)) {

            ps.setString(1, u.getFirstName());
            ps.setString(2, u.getLastName());
            ps.setString(3, u.getEmail());
            ps.setString(4, u.getMobile());
            ps.setInt(5, u.getUserId());
            ps.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void deleteUser(int userId) {
        String sql = "DELETE FROM user_details WHERE user_id=?";

        try (Connection con = DBConnection.getConnection();
             PreparedStatement ps = con.prepareStatement(sql)) {

            ps.setInt(1, userId);
            ps.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

UserAction.java

The Action class holds the form bean as a property. Struts2 binds nested properties like user.firstName from HTTP parameters automatically via OGNL.

package com.java9r.action;

import com.java9r.dao.UserDAO;
import com.java9r.model.UserBean;
import com.opensymphony.xwork2.ActionSupport;

import java.util.List;

public class UserAction extends ActionSupport {

    private static final long serialVersionUID = 1L;

    // Nested bean — form parameters use prefix "user." e.g. user.firstName
    private UserBean       user  = new UserBean();
    private List<UserBean> users;

    private final UserDAO dao = new UserDAO();

    // List all users — mapped to /listUsers
    public String listUsers() {
        users = dao.getAllUsers();
        return SUCCESS;
    }

    // Add new user — mapped to /addUser
    public String addUser() {
        dao.addUser(user);
        users = dao.getAllUsers();
        user  = new UserBean();
        return SUCCESS;
    }

    // Update user — mapped to /updateUser
    public String updateUser() {
        dao.updateUser(user);
        users = dao.getAllUsers();
        user  = new UserBean();
        return SUCCESS;
    }

    // Delete user — mapped to /deleteUser
    public String deleteUser() {
        dao.deleteUser(user.getUserId());
        users = dao.getAllUsers();
        user  = new UserBean();
        return SUCCESS;
    }

    // Getters and Setters
    public UserBean       getUser()  { return user;  }
    public List<UserBean> getUsers() { return users; }
    public void setUser(UserBean user)         { this.user  = user;  }
    public void setUsers(List<UserBean> users) { this.users = users; }
}

struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>

    <constant name="struts.devMode"                       value="false"/>
    <constant name="struts.enable.DynamicMethodInvocation" value="false"/>

    <package name="user" namespace="/" extends="struts-default">

        <action name="listUsers"
                class="com.java9r.action.UserAction"
                method="listUsers">
            <result name="success">/UserList.jsp</result>
        </action>

        <action name="addUser"
                class="com.java9r.action.UserAction"
                method="addUser">
            <result name="success" type="redirectAction">listUsers</result>
        </action>

        <action name="updateUser"
                class="com.java9r.action.UserAction"
                method="updateUser">
            <result name="success" type="redirectAction">listUsers</result>
        </action>

        <action name="deleteUser"
                class="com.java9r.action.UserAction"
                method="deleteUser">
            <result name="success" type="redirectAction">listUsers</result>
        </action>

    </package>

</struts>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <display-name>Struts2 CRUD</display-name>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>
            org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

index.jsp – Redirect to List

<%@ page contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="refresh" content="0; url=listUsers">
</head>
<body></body>
</html>

UserList.jsp – CRUD Table with Bootstrap Modals

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
    <title>User Management</title>
    <link rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-4">

    <div class="d-flex justify-content-between align-items-center mb-3">
        <h3>User Management</h3>
        <!-- Button to open Add User modal -->
        <button class="btn btn-success"
                data-bs-toggle="modal" data-bs-target="#addModal">+ Add User</button>
    </div>

    <!-- Users Table -->
    <table class="table table-bordered table-hover">
        <thead class="table-dark">
            <tr>
                <th>#</th>
                <th>First Name</th>
                <th>Last Name</th>
                <th>Email</th>
                <th>Mobile</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
        <c:forEach var="u" items="${users}">
            <tr>
                <td>${u.userId}</td>
                <td>${u.firstName}</td>
                <td>${u.lastName}</td>
                <td>${u.email}</td>
                <td>${u.mobile}</td>
                <td>
                    <!-- Edit button opens a per-row modal -->
                    <button class="btn btn-sm btn-primary"
                            data-bs-toggle="modal"
                            data-bs-target="#editModal${u.userId}">Edit</button>

                    <!-- Delete (inline form, no modal needed) -->
                    <form action="deleteUser" method="post" style="display:inline"
                          onsubmit="return confirm('Delete this user?')">
                        <input type="hidden" name="user.userId" value="${u.userId}">
                        <button type="submit" class="btn btn-sm btn-danger">Delete</button>
                    </form>
                </td>
            </tr>

            <!-- Edit Modal (one per row, identified by userId) -->
            <div class="modal fade" id="editModal${u.userId}" tabindex="-1">
                <div class="modal-dialog">
                    <div class="modal-content">
                        <form action="updateUser" method="post">
                        <div class="modal-header">
                            <h5 class="modal-title">Edit User</h5>
                            <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                        </div>
                        <div class="modal-body">
                            <input type="hidden" name="user.userId" value="${u.userId}">
                            <div class="mb-2">
                                <label>First Name</label>
                                <input type="text" name="user.firstName"
                                       class="form-control" value="${u.firstName}" required>
                            </div>
                            <div class="mb-2">
                                <label>Last Name</label>
                                <input type="text" name="user.lastName"
                                       class="form-control" value="${u.lastName}" required>
                            </div>
                            <div class="mb-2">
                                <label>Email</label>
                                <input type="email" name="user.email"
                                       class="form-control" value="${u.email}" required>
                            </div>
                            <div class="mb-2">
                                <label>Mobile</label>
                                <input type="text" name="user.mobile"
                                       class="form-control" value="${u.mobile}">
                            </div>
                        </div>
                        <div class="modal-footer">
                            <button type="submit" class="btn btn-primary">Update</button>
                            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                        </div>
                        </form>
                    </div>
                </div>
            </div>
            <!-- End Edit Modal -->

        </c:forEach>
        </tbody>
    </table>

</div>

<!-- Add User Modal -->
<div class="modal fade" id="addModal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <form action="addUser" method="post">
            <div class="modal-header">
                <h5 class="modal-title">Add New User</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body">
                <div class="mb-2">
                    <label>First Name</label>
                    <input type="text" name="user.firstName" class="form-control" required>
                </div>
                <div class="mb-2">
                    <label>Last Name</label>
                    <input type="text" name="user.lastName" class="form-control" required>
                </div>
                <div class="mb-2">
                    <label>Email</label>
                    <input type="email" name="user.email" class="form-control" required>
                </div>
                <div class="mb-2">
                    <label>Mobile</label>
                    <input type="text" name="user.mobile" class="form-control">
                </div>
            </div>
            <div class="modal-footer">
                <button type="submit" class="btn btn-success">Save</button>
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
            </div>
            </form>
        </div>
    </div>
</div>
<!-- End Add Modal -->

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

How Struts2 Binds Nested Form Parameters

The form fields use the prefix user. (e.g. name="user.firstName"). Struts2 reads this as: get the user property from the action (getUser()), then call setFirstName() on that object. This is OGNL object graph navigation — it works to any depth: user.address.city, etc.

HTML input name Struts2 calls
user.firstName action.getUser().setFirstName(value)
user.userId action.getUser().setUserId(value)
user.email action.getUser().setEmail(value)

Summary

This Struts2 CRUD application follows the pattern: one Action class with four methods (list, add, update, delete), each mapped to its own URL in struts.xml, all returning a redirect to the list after write operations (PRG — Post/Redirect/Get pattern). The DAO layer uses try-with-resources for automatic connection cleanup. The JSP uses JSTL <c:forEach> to render the table and Bootstrap 5 modals for the Add and Edit forms. Nested bean binding (user.firstName) keeps the action's form fields organized as a single object instead of loose fields.

Topics: Java Struts2
← Newer Post Older Post →

Comments

https://www.blogger.com/comment/frame/6690124484600543990?po=7661773642293226669&hl=en&saa=85391&origin=https://www.java9r.com