Hello,
I have a simple web application to learn how the controller works in Struts
framework. The build is deployed to Tomcat 11.0.5. The application has two
simple JSP files PgStudent.jsp (configured as the welcome page) and
PgRegistration.jsp. Each page has two buttons to let user go back and forth
between the two pages. It loads the welcome page PgStudent fine, but any
request will encounter web error 404, like this one: There is no Action mapped
for namespace [/] and action name [viewRegistration] associated with context
path [/s2ex1], or from localhost_access log: 0:0:0:0:0:0:0:1 - -
[06/Jun/2025:12:12:28 -0400] "POST /s2ex1/viewRegistration HTTP/1.1" 404 829.
Please help see where I do it wrong. Namespace is specified in JSP files, but
it always sees namespace as /. I am attaching the project file structure and
the list of the files:
Project Files Structure
s2ex1 lib caffeine-3.1.8.jar freemarker-2.3.34.jar
jakarta.servlet-api-5.0.0.jar (to compile only) ognl-3.3.5.jar
struts2-core-7.0.3.jar xwork-core-2.3.35.jar src s2ex1
RegistrationAction.java StudentAction.java WebContent
jsp PgRegistration.jsp PgStudent.jsp WEB-INF
struts.xml web.xml build.xml
List of the 7 files
1. struts.xml<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"https://struts.apache.org/dtds/struts-2.0.dtd"><struts> <constant
name="struts.devMode" value="true"/> <!-- student namespace --> <package
name="student" namespace="/student" extends="struts-default"> <action
name="viewStudent" class="s2ex1.StudentAction" method="viewStudent">
<result name="viewStudent">/jsp/PgStudent.jsp</result> </action>
<action name="updateStudent" class="s2ex1.StudentAction"
method="updateStudent"> <result
name="viewStudent">/jsp/PgStudent.jsp</result> </action> </package>
<!-- registration namespace --> <package name="registration"
namespace="/registration" extends="struts-default"> <action
name="viewRegistration" class="s2ex1.RegistrationAction"
method="viewRegistration"> <result
name="viewRegistration">/jsp/PgRegistration.jsp</result> </action>
<action name="register" class="s2ex1.RegistrationAction"
method="register"> <result
name="viewRegistration">/jsp/PgRegistration.jsp</result> </action>
</package></struts>
2. web.xml<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_5_0.xsd"
version="5.0">
<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>
<!-- Set PgStudent.jsp as the default page --> <welcome-file-list>
<welcome-file>jsp/PgStudent.jsp</welcome-file>
</welcome-file-list></web-app>
3. PgRegistration.jsp<%@ taglib prefix="s" uri="/struts-tags" %><html><head>
<title>Registration Records</title></head><body> <h2>Registration
Records</h2>
<s:form namespace="/registration" action="register" method="post">
<s:submit value="Register for Class"/> </s:form>
<s:form namespace="/student" action="viewStudent" method="post">
<s:submit value="Return to Student Section"/> </s:form></body></html>
4. PgStudent.jsp<%@ taglib prefix="s" uri="/struts-tags" %>
<html><head> <title>Student Info</title></head><body> <h2>Student -
Contact Information</h2>
<s:form namespace="/student" action="updateStudent" method="post">
<s:submit value="Update Contact Info"/> </s:form>
<s:form namespace="/registration" action="viewRegistration" method="post">
<s:submit value="View Registrations"/> </s:form></body></html>
5. RegistrationAction.javapackage s2ex1;
import jakarta.servlet.http.HttpServletRequest;//import
jakarta.servlet.http.HttpSession;
import org.apache.struts2.ActionSupport;import
org.apache.struts2.action.ServletRequestAware;
public class RegistrationAction extends ActionSupport implements
ServletRequestAware { private static final long serialVersionUID =
-4447001525367432296L; private HttpServletRequest request;
@Override public void withServletRequest(HttpServletRequest request) {
this.request = request; } public HttpServletRequest
getWithServletRequest() { return this.request; } public String
viewRegistration() { return "viewRegistration"; } public String
register() { return "viewRegistration"; } public String
viewStudent() { return "viewStudent"; }}
6. StudentAction.javapackage s2ex1;
import jakarta.servlet.http.HttpServletRequest;//import
jakarta.servlet.http.HttpSession;
import org.apache.struts2.ActionSupport;import
org.apache.struts2.action.ServletRequestAware;
public class StudentAction extends ActionSupport implements ServletRequestAware
{ private static final long serialVersionUID = -4056538155914479859L;
private HttpServletRequest request;
@Override public void withServletRequest(HttpServletRequest request) {
this.request = request; }
public HttpServletRequest getWithServletRequest() { return
this.request; } public String viewStudent() { return
"viewStudent"; } public String updateStudent() { return
"viewStudent"; } public String viewRegistration() { return
"viewRegistration"; }}
7. build.xml<project name="s2ex1" default="war" basedir="."> <!-- Define
global properties --> <property name="src.dir" value="src"/> <property
name="web.dir" value="WebContent"/> <property name="build.dir"
value="build"/> <property name="classes.dir" value="${build.dir}/classes"/>
<property name="war.file" value="s2ex1.war"/> <!-- All external libraries
--> <property name="lib.dir" value="${basedir}/lib"/>
<!-- Clean --> <target name="clean"> <delete dir="${build.dir}"/>
<delete file="${war.file}"/> </target>
<!-- Compile Java sources --> <target name="compile"> <mkdir
dir="${classes.dir}"/> <javac srcdir="${src.dir}"
destdir="${classes.dir}" includeantruntime="false" source="21"
target="21" > <classpath> <fileset
dir="${lib.dir}"> <include name="*.jar"/>
</fileset> </classpath> </javac> </target>
<!-- Prepare WAR directory --> <target name="prepare"> <mkdir
dir="${build.dir}/WebContent"/> <copy todir="${build.dir}/WebContent">
<fileset dir="${web.dir}"/> </copy> <copy
file="WebContent/WEB-INF/struts.xml" todir="${build.dir}/WebContent/WEB-INF"/>
<copy todir="${build.dir}/WebContent/WEB-INF/classes">
<fileset dir="${classes.dir}"/> </copy> <copy
todir="${build.dir}/WebContent/WEB-INF/lib"> <fileset
dir="${lib.dir}/"> <include name="struts2-core-7.0.3.jar"/>
<include name="freemarker-2.3.34.jar"/> <include
name="ognl-3.3.5.jar"/> <include name="caffeine-3.1.8.jar"/>
<include name="xwork-core-2.3.35.jar"/> </fileset> </copy> </target>
<!-- Create WAR file --> <target name="war" depends="clean, compile,
prepare"> <mkdir dir="${build.dir}/WebContent"/> <war
destfile="${war.file}" webxml="${build.dir}/WebContent/WEB-INF/web.xml">
<fileset dir="${build.dir}/WebContent"/> </war> <echo
message="Build file created: ${war.file}"/> </target>
</project>
Thank you,Joseph H.