Apache Struts has changed considerably since the old Struts 2.5 examples. The current best-available release is Struts 7.2.1. Struts 7 requires Java 17 or newer and Jakarta Servlet 6 or newer, so Java 25 is a natural runtime for a new application.
This tutorial deliberately uses struts.xml rather than annotations so the framework's request mapping is easy to see. The request-response flow is simple:
- An HTML form posts a name to
hello.action. - Struts maps that action to
HelloWorldAction. - The action returns
success. - Struts renders
results.jsp.
Struts 7 struts.xml configuration
Place struts.xml in src/main/resources. The action name and result mapping can be configured explicitly:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
"https://struts.apache.org/dtds/struts-6.0.dtd">
<struts>
<package
name="default"
namespace="/"
extends="struts-default">
<action
name="hello"
class="com.mcnz.struts.HelloWorldAction">
<result name="success">
/results.jsp
</result>
</action>
</package>
</struts>The URL hello.action resolves to the action named hello, which Struts instantiates and executes.
HTML input form
The browser submits a parameter named firstName. Struts populates the matching JavaBean property on the action before execute() runs.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Struts Hello World</title>
</head>
<body>
<form action="hello.action" method="post">
<label for="firstName">
Please tell me your name:
</label>
<input
id="firstName"
name="firstName"
type="text"
value="World"
required
>
<button type="submit">Submit</button>
</form>
</body>
</html>Struts action class with Java 25
The action remains a plain Java class. Extending ActionSupport provides the standard SUCCESS result constant and other Struts conveniences.
package com.mcnz.struts;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport {
private String firstName;
@Override
public String execute() {
IO.println("Value of firstName: " + firstName);
return SUCCESS;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}IO.println() is fine for a teaching example. In a production web application, use the application's logging framework rather than writing diagnostics directly to standard output.
JSP result page
The JSP uses the standard Struts tag library to render the property populated on the action.
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Struts Result</title>
</head>
<body>
<h1>
Hello <s:property value="firstName" />!
</h1>
</body>
</html>Jakarta Servlet web.xml for Struts 7
Struts 7 uses Jakarta Servlet APIs. The old java.sun.com/xml/ns/javaee namespace and javax.servlet dependencies belong to pre-Jakarta applications.
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="https://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>Struts 7 Hello World</display-name>
<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>Maven POM for Struts 7.2.1 and Java 25
A new project should not copy the old Java 8, Struts 2.5 or javax.servlet dependencies. Use Struts 7.2.1, Jakarta Servlet 6 and Java 25.
<project xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mcnz</groupId>
<artifactId>struts-hello-world</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<properties>
<maven.compiler.release>25</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<struts.version>7.2.1</struts.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-bom</artifactId>
<version>${struts.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>struts-hello-world</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>25</release>
</configuration>
</plugin>
</plugins>
</build>
</project>Run the Struts 7 Hello World app
Package the application as a WAR and deploy it to a Jakarta Servlet 6 compatible container. Current Tomcat and Jetty releases are common choices.
The request path is now easy to trace: the browser submits firstName, the Struts filter receives the request, struts.xml selects HelloWorldAction, the action returns SUCCESS, and Struts renders results.jsp.
The MVC pattern is still recognizably Struts. The important modernization is the surrounding platform: supported Struts 7 binaries, Jakarta APIs and a current Java runtime.
Cameron McKenzie is an AWS Certified AI Practitioner, Machine Learning Engineer, Solutions Architect and author of many popular books in the software development and Cloud Computing space. His growing YouTube channel training devs in Java, Spring, AI and ML has well over 30,000 subscribers.