blob: 1aa161d728278afa1c1d64e28fdbfcf1ce3733f7 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="Date-Revision-yyyymmdd" content="20140918"/>
<meta http-equiv="Content-Language" content="en"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Action Configuration</title>
<link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,400italic,600italic,700italic" rel="stylesheet" type="text/css">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<link href="/css/main.css" rel="stylesheet">
<link href="/css/custom.css" rel="stylesheet">
<link href="/css/syntax.css" rel="stylesheet">
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="/js/community.js"></script>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* We explicitly disable cookie tracking to avoid privacy issues */
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//analytics.apache.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '41']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
</head>
<body>
<a href="https://github.com/apache/struts" class="github-ribbon">
<img decoding="async" loading="lazy" style="position: absolute; right: 0; border: 0;" width="149" height="149" src="https://github.blog/wp-content/uploads/2008/12/forkme_right_red_aa0000.png?resize=149%2C149" class="attachment-full size-full" alt="Fork me on GitHub" data-recalc-dims="1">
</a>
<header>
<nav>
<div role="navigation" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" data-toggle="collapse" data-target="#struts-menu" class="navbar-toggle">
Menu
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/index.html" class="navbar-brand logo"><img src="/img/struts-logo.svg"></a>
</div>
<div id="struts-menu" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Home<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/index.html">Welcome</a></li>
<li><a href="/download.cgi">Download</a></li>
<li><a href="/releases.html">Releases</a></li>
<li><a href="/announce-2024.html">Announcements</a></li>
<li><a href="http://www.apache.org/licenses/">License</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html">Thanks!</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
<li><a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Support<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/mail.html">User Mailing List</a></li>
<li><a href="https://issues.apache.org/jira/browse/WW">Issue Tracker</a></li>
<li><a href="/security.html">Reporting Security Issues</a></li>
<li><a href="/commercial-support.html">Commercial Support</a></li>
<li class="divider"></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Migration+Guide">Version Notes</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Security+Bulletins">Security Bulletins</a></li>
<li class="divider"></li>
<li><a href="/maven/project-info.html">Maven Project Info</a></li>
<li><a href="/maven/struts2-core/dependencies.html">Struts Core Dependencies</a></li>
<li><a href="/maven/struts2-plugins/modules.html">Plugin Dependencies</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Documentation<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/birdseye.html">Birds Eye</a></li>
<li><a href="/primer.html">Key Technologies</a></li>
<li><a href="/kickstart.html">Kickstart FAQ</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Home">Wiki</a></li>
<li class="divider"></li>
<li><a href="/getting-started/">Getting Started</a></li>
<li><a href="/security/">Security Guide</a></li>
<li><a href="/core-developers/">Core Developers Guide</a></li>
<li><a href="/tag-developers/">Tag Developers Guide</a></li>
<li><a href="/maven-archetypes/">Maven Archetypes</a></li>
<li><a href="/plugins/">Plugins</a></li>
<li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li>
<li><a href="/tag-developers/tag-reference.html">Tag reference</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/FAQs">FAQs</a></li>
<li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Contributing<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/youatstruts.html">You at Struts</a></li>
<li><a href="/helping.html">How to Help FAQ</a></li>
<li><a href="/dev-mail.html">Development Lists</a></li>
<li class="divider"></li>
<li><a href="/submitting-patches.html">Submitting patches</a></li>
<li><a href="/builds.html">Source Code and Builds</a></li>
<li><a href="/coding-standards.html">Coding standards</a></li>
<li><a href="/contributors/">Contributors Guide</a></li>
<li class="divider"></li>
<li><a href="/release-guidelines.html">Release Guidelines</a></li>
<li><a href="/bylaws.html">PMC Charter</a></li>
<li><a href="/volunteers.html">Volunteers</a></li>
<li><a href="https://gitbox.apache.org/repos/asf?p=struts.git">Source Repository</a></li>
<li><a href="/updating-website.html">Updating the website</a></li>
</ul>
</li>
<li class="apache"><a href="http://www.apache.org/"><img src="/img/apache.png"></a></li>
</ul>
</div>
</div>
</div>
</nav>
</header>
<article class="container">
<section class="col-md-12">
<a class="edit-on-gh" href="https://github.com/apache/struts-site/edit/master/source/core-developers/action-configuration.md" title="Edit this page on GitHub">Edit on GitHub</a>
<a href="index.html" title="back to Core Developers Guide"><< back to Core Developers Guide</a>
<h1 class="no_toc" id="action-configuration">Action Configuration</h1>
<ul id="markdown-toc">
<li><a href="#action-mappings" id="markdown-toc-action-mappings">Action Mappings</a></li>
<li><a href="#action-names" id="markdown-toc-action-names">Action Names</a></li>
<li><a href="#action-methods" id="markdown-toc-action-methods">Action Methods</a></li>
<li><a href="#wildcard-method" id="markdown-toc-wildcard-method">Wildcard Method</a></li>
<li><a href="#dynamic-method-invocation" id="markdown-toc-dynamic-method-invocation">Dynamic Method Invocation</a> <ul>
<li><a href="#strict-dmi" id="markdown-toc-strict-dmi">Strict DMI</a></li>
<li><a href="#strict-method-invocation" id="markdown-toc-strict-method-invocation">Strict Method Invocation</a></li>
</ul>
</li>
<li><a href="#actionsupport-default" id="markdown-toc-actionsupport-default">ActionSupport Default</a></li>
<li><a href="#post-back-default" id="markdown-toc-post-back-default">Post-Back Default</a></li>
<li><a href="#action-default" id="markdown-toc-action-default">Action Default</a></li>
</ul>
<p>The action mappings are the basic “unit-of-work” in the framework. Essentially, the action maps an identifier to
a handler class. When a request matches the action’s name, the framework uses the mapping to determine how to process
the request.</p>
<h2 id="action-mappings">Action Mappings</h2>
<p>The action mapping can specify a set of result types, a set of exception handlers, and an interceptor stack. Only the
<code class="language-plaintext highlighter-rouge">name</code> attribute is required. The other attributes can also be provided at package scope.</p>
<p><strong>A Logon Action</strong></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"Logon"</span> <span class="na">class=</span><span class="s">"tutorial.Logon"</span><span class="nt">&gt;</span>
<span class="nt">&lt;result</span> <span class="na">type=</span><span class="s">"redirectAction"</span><span class="nt">&gt;</span>Menu<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"input"</span><span class="nt">&gt;</span>/Logon.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;/action&gt;</span>
</code></pre></div></div>
<p>When using <em>Convention Plugin</em> the action mapping can be configured with annotations:</p>
<p><strong>A Logon Action with annotations</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">tutorial</span>
<span class="nd">@Action</span><span class="o">(</span><span class="s">"Logon"</span><span class="o">)</span> <span class="c1">// actually that is not necessary as it is added by convention</span>
<span class="nd">@Results</span><span class="o">(</span>
<span class="nd">@Result</span><span class="o">(</span><span class="n">type</span><span class="o">=</span><span class="s">"redirectAction"</span><span class="o">,</span> <span class="n">location</span><span class="o">=</span><span class="s">"Menu"</span><span class="o">),</span>
<span class="nd">@Result</span><span class="o">(</span><span class="n">name</span><span class="o">=</span><span class="s">"input"</span><span class="o">,</span> <span class="n">location</span><span class="o">=</span><span class="s">"/Logon.jsp"</span><span class="o">)</span>
<span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Logon</span> <span class="o">{</span>
</code></pre></div></div>
<h2 id="action-names">Action Names</h2>
<p>In a web application, the <code class="language-plaintext highlighter-rouge">name</code> attribute is matched as part of the location requested by a browser (or other HTTP
client). The framework will drop the host and application name and the extension and match what’s in the middle:
the action name. So, a request for <code class="language-plaintext highlighter-rouge">http://www.planetstruts.org/struts2-mailreader/Welcome.action</code> will map to the
<code class="language-plaintext highlighter-rouge">Welcome</code> action.</p>
<p>Within an application a link to an action is usually generated by a Struts Tag. The tag can specify the action by name,
and the framework will render the default extension and anything else that is needed. Forms may also submit directly
to a Struts Action name (rather than a “raw” URI).</p>
<p><strong>A Hello Form</strong></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;s:form</span> <span class="na">action=</span><span class="s">"Hello"</span><span class="nt">&gt;</span>
<span class="nt">&lt;s:textfield</span> <span class="na">label=</span><span class="s">"Please enter your name"</span> <span class="na">name=</span><span class="s">"name"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;s:submit/&gt;</span>
<span class="nt">&lt;/s:form&gt;</span>
</code></pre></div></div>
<p><strong>Action Names With Slashes</strong></p>
<p>If your action names have slashes in them (for example, <code class="language-plaintext highlighter-rouge">&lt;action name="admin/home" class="tutorial.Admin"/&gt;</code>) you need
to specifically allow slashes in your action names via a constant in the <code class="language-plaintext highlighter-rouge">struts.xml</code> file by specifying</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.enable.SlashesInActionNames"</span> <span class="na">value=</span><span class="s">"true"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<p>See <a href="https://issues.apache.org/jira/browse/WW-1383">JIRA Issue WW-1383</a> for discussion as there are side effects
to setting this property to <code class="language-plaintext highlighter-rouge">true</code>.</p>
<p><strong>Action Names with Dots and Dashes</strong></p>
<p>Although action naming is pretty flexible, one should pay attention when using dots (eg. create.user) and/or dashes
(eg. my-action). While the dot notation has no known side effects at this time, the dash notation will cause problems
with the generated JavaScript for certain tags and themes. Use with caution, and always try to use camelcase action
names (eg. createUser) or underscores (eg. my_action).</p>
<p><strong>Allowed action names</strong></p>
<p><code class="language-plaintext highlighter-rouge">DefaultActionMapper</code> is using pre-defined RegEx to check if action name matches allowed names. The default RegEx is
defined as follow: <code class="language-plaintext highlighter-rouge">[a-zA-Z0-9._!/-]*</code> - if at some point this doesn’t match your action naming schema you can define
your own RegEx and override the default using constant named <code class="language-plaintext highlighter-rouge">struts.allowed.action.names</code>, e.g.:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;struts&gt;</span>
<span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.allowed.action.names"</span> <span class="na">value=</span><span class="s">"[a-z{}]"</span><span class="err">*</span><span class="nt">/&gt;</span>
...
<span class="nt">&lt;/struts&gt;</span>
</code></pre></div></div>
<p><strong>NOTE</strong>: Please be aware that action names not matching the RegEx will rise an exception.</p>
<h2 id="action-methods">Action Methods</h2>
<p>The default entry method to the handler class is defined by the Action interface.</p>
<p><strong>Action interface</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">Action</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">execute</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<blockquote>
<p>Implementing the Action interface is optional. If Action is not implemented, the framework will use reflection to
look for an<code class="language-plaintext highlighter-rouge">execute</code> method.</p>
</blockquote>
<p>Sometimes, developers like to create more than one entry point to an Action. For example, in the case of a data-access
Action, a developer might want separate entry-points for <code class="language-plaintext highlighter-rouge">create</code>, <code class="language-plaintext highlighter-rouge">retrieve</code>, <code class="language-plaintext highlighter-rouge">update</code>, and <code class="language-plaintext highlighter-rouge">delete</code>. A different
entry point can be specified by the <code class="language-plaintext highlighter-rouge">method</code> attribute.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"delete"</span> <span class="na">class=</span><span class="s">"example.CrudAction"</span> <span class="na">method=</span><span class="s">"delete"</span><span class="nt">&gt;</span>
...
</code></pre></div></div>
<blockquote>
<p>If there is no <code class="language-plaintext highlighter-rouge">execute</code> method and no other method specified in the configuration the framework will throw an exception.</p>
</blockquote>
<p><em>Convention Plugin</em> allows that by annotating methods:</p>
<p><strong>Annotated action method</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Action</span><span class="o">(</span><span class="s">"crud"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">CrudAction</span> <span class="o">{</span>
<span class="nd">@Action</span><span class="o">(</span><span class="s">"delete"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">delete</span><span class="o">()</span> <span class="o">{</span>
<span class="o">...</span>
</code></pre></div></div>
<h2 id="wildcard-method">Wildcard Method</h2>
<p>Many times, a set of action mappings will share a common pattern. For example, all your <code class="language-plaintext highlighter-rouge">edit</code> actions might start
with the word “edit”, and call the <code class="language-plaintext highlighter-rouge">edit</code> method on the Action class. The <code class="language-plaintext highlighter-rouge">delete</code> actions might use the same pattern,
but call the <code class="language-plaintext highlighter-rouge">delete</code> method instead.</p>
<p>Rather than code a separate mapping for each action class that uses this pattern, you can write it once as a wildcard mapping.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"*Crud"</span> <span class="na">class=</span><span class="s">"example.Crud"</span> <span class="na">method=</span><span class="s">"{1}"</span><span class="nt">&gt;</span>
...
</code></pre></div></div>
<p>Here, a reference to “editCrud” will call the <code class="language-plaintext highlighter-rouge">edit</code> method on an instance of the Crud Action class. Likewise,
a reference to “deleteCrud” will call the <code class="language-plaintext highlighter-rouge">delete</code> method instead.</p>
<p>Another common approach is to postfix the method name and set it off with an exclamation point (aka “bang”), underscore,
or other special character.</p>
<ul>
<li>“action=Crud-input”</li>
<li>“action=Crud-delete”</li>
</ul>
<p>To use a postfix wildcard, just move the asterisk and add an underscore.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"Crud_*"</span> <span class="na">class=</span><span class="s">"example.Crud"</span> <span class="na">method=</span><span class="s">"{1}"</span><span class="nt">&gt;</span>
</code></pre></div></div>
<p>From the framework’s perspective, a wildcard mapping creates a new “virtual” mapping with all the same attributes as
a conventional, static mapping. As a result, you can use the expanded wildcard name as the name of validation, type
conversion, and message resource files, just as if it were an Action name (which it is!).</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Crud_input-validation.xml</code></li>
<li><code class="language-plaintext highlighter-rouge">Crud_delete-conversion.xml</code></li>
</ul>
<p>If Wildcard Method mapping uses a “!” in the action name, the Wildcard Method will overlap with another flexible
approach to mapping, . To use action names that include the “!” character, set <code class="language-plaintext highlighter-rouge">struts.enable.DynamicMethodInvocation</code>
to <code class="language-plaintext highlighter-rouge">false</code> in the application configuration.</p>
<h2 id="dynamic-method-invocation">Dynamic Method Invocation</h2>
<p>There’s a feature embedded in Struts 2 that lets the “!” (bang) character invoke a method other than <code class="language-plaintext highlighter-rouge">execute</code> . It is
called “Dynamic Method Invocation” aka DMI.</p>
<p>DMI will use the string following a “!” character in an action name as the name of a method to invoke (instead of
<code class="language-plaintext highlighter-rouge">execute</code>). A reference to <code class="language-plaintext highlighter-rouge">Category!create.action</code>, says to use the “Category” action mapping, but call the <code class="language-plaintext highlighter-rouge">create</code>
method instead.</p>
<p>Another way to use DMI is to provide HTTP parameters prefixed with <code class="language-plaintext highlighter-rouge">method:</code>. For example in the URL it could be
<code class="language-plaintext highlighter-rouge">Category.action?method:create=foo</code>, the parameter value is ignored. In POST-Requests that can be used e.g. with
a hidden parameter (<code class="language-plaintext highlighter-rouge">&lt;s:hidden name="method:create" value="foo" /&gt;</code>) or along with a button (<code class="language-plaintext highlighter-rouge">&lt;s:submit method="create" /&gt;</code>).</p>
<p>For Struts 2, we added a switch to disable DMI for two reasons. First, DMI can cause security issues if POJO actions are
used. Second, DMI overlaps with the Wildcard Method feature that we brought over from Struts 1 (and from Cocoon before
that). If you have security concerns, or would like to use the “!” character with Wildcard Method actions, then set
<code class="language-plaintext highlighter-rouge">struts.enable.DynamicMethodInvocation</code> to <code class="language-plaintext highlighter-rouge">false</code> in the application configuration.</p>
<p>The framework does support DMI, but there are problems with way DMI is implemented. Essentially, the code scans
the action name for a “!” character, and finding one, tricks the framework into invoking the other method instead of
<code class="language-plaintext highlighter-rouge">execute</code>. The other method is invoked, but it uses the same configuration as the <code class="language-plaintext highlighter-rouge">execute</code> method, including
validations. The framework “believes” it is invoking the <code class="language-plaintext highlighter-rouge">Category</code> action with the <code class="language-plaintext highlighter-rouge">execute</code> method.</p>
<p>The Wildcard Method feature is implemented differently. When a Wildcard Method action is invoked, the framework acts as
if the matching action had been hardcoded in the configuration. The framework “believes” it’s executing the action
<code class="language-plaintext highlighter-rouge">Category!create</code> and “knows” it is executing the <code class="language-plaintext highlighter-rouge">create</code> method of the corresponding Action class. Accordingly, we can
add for a Wildcard Method action mapping its own validations, message resources, and type converters, just like
a conventional action mapping. For this reason, the is preferred.</p>
<h3 id="strict-dmi">Strict DMI</h3>
<p>In Struts 2.3, an option was added to restrict the methods that DMI can invoke. First, set the attribute
<code class="language-plaintext highlighter-rouge">strict-method-invocation="true"</code> on your <code class="language-plaintext highlighter-rouge">&lt;package&gt;</code> element. This tells Struts to reject any method that is not
explicitly allowed via either the <code class="language-plaintext highlighter-rouge">method</code> attribute (including wildcards) or the <code class="language-plaintext highlighter-rouge">&lt;allowed-methods&gt;</code> tag. Then specify
<code class="language-plaintext highlighter-rouge">&lt;allowed-methods&gt;</code> as a comma-separated list of method names in your <code class="language-plaintext highlighter-rouge">&lt;action&gt;</code>. (If you specify a <code class="language-plaintext highlighter-rouge">method</code> attribute
for your action, you do not need to list it in <code class="language-plaintext highlighter-rouge">&lt;allowed-methods&gt;</code>).</p>
<p>Note that you can specify <code class="language-plaintext highlighter-rouge">&lt;allowed-methods&gt;</code> even without <code class="language-plaintext highlighter-rouge">strict-method-invocation</code>. This restricts access only for
the specific actions that have <code class="language-plaintext highlighter-rouge">&lt;allowed-methods&gt;</code>.</p>
<p><strong>Example struts.xml</strong></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;</span>
<span class="cp">&lt;!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd"&gt;</span>
<span class="nt">&lt;struts&gt;</span>
<span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.enable.DynamicMethodInvocation"</span> <span class="na">value=</span><span class="s">"true"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;package</span> <span class="na">name=</span><span class="s">"default"</span> <span class="na">extends=</span><span class="s">"struts-default"</span> <span class="na">strict-method-invocation=</span><span class="s">"true"</span><span class="nt">&gt;</span>
<span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"index"</span> <span class="na">class=</span><span class="s">"org.apache.struts2.examples.actions.Index"</span><span class="nt">&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"success"</span> <span class="na">type=</span><span class="s">"redirectAction"</span><span class="nt">&gt;</span>hello<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;/action&gt;</span>
<span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"hello"</span> <span class="na">class=</span><span class="s">"org.apache.struts2.examples.actions.HelloAction"</span><span class="nt">&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"success"</span><span class="nt">&gt;</span>/WEB-INF/content/hello.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"redisplay"</span> <span class="na">type=</span><span class="s">"redirectAction"</span><span class="nt">&gt;</span>hello<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;allowed-methods&gt;</span>add<span class="nt">&lt;/allowed-methods&gt;</span>
<span class="nt">&lt;/action&gt;</span>
<span class="nt">&lt;/package&gt;</span>
<span class="nt">&lt;/struts&gt;</span>
</code></pre></div></div>
<h3 id="strict-method-invocation">Strict Method Invocation</h3>
<p>In Struts 2.5 the Strict DMI was extended and it’s called <strong>Strict Method Invocation</strong> aka SMI. You can imagine that
the DMI is a “border police”, where SMI is a “tax police” and keeps eye on internals. With this version, SMI is enabled
by default (<code class="language-plaintext highlighter-rouge">strict-method-invocation</code> attribute is set to <code class="language-plaintext highlighter-rouge">true</code> by default in <code class="language-plaintext highlighter-rouge">struts-default</code> package), you have
option to disable it per package - there is no global switch to disable SMI for the whole application. To gain advantage
of the new configuration option please use the latest DTD definition:</p>
<p><strong>Struts 2.5 DTD</strong></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;</span>
<span class="cp">&lt;!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd"&gt;</span>
<span class="nt">&lt;struts&gt;</span>
...
<span class="nt">&lt;/struts&gt;</span>
</code></pre></div></div>
<p>SMI works in the following way:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">&lt;allowed-methods&gt;</code> / <code class="language-plaintext highlighter-rouge">@AllowedMethods</code> is defined per action - SMI works without switching it on but just for those
actions (plus adding <code class="language-plaintext highlighter-rouge">&lt;global-allowed-methods/&gt;</code>)</li>
<li>SMI is enabled but no <code class="language-plaintext highlighter-rouge">&lt;allowed-methods&gt;</code> / <code class="language-plaintext highlighter-rouge">@AllowedMethods</code> are defined - SMI works but only with
<code class="language-plaintext highlighter-rouge">&lt;global-allowed-methods/&gt;</code></li>
<li>SMI is disabled - call to any action method is allowed that matches the default RegEx - <code class="language-plaintext highlighter-rouge">([A-Za-z0-9_$]*)</code></li>
</ul>
<p>You can redefine the default RegEx by using a constant as follow </p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.strictMethodInvocation.methodRegex"</span> <span class="na">value=</span><span class="s">"([a-zA-Z]*)"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<p>When using wildcard mapping in actions’ definitions SMI works in two ways:</p>
<ul>
<li>SMI is disabled - any wildcard will be substituted with the default RegEx, ie.: <code class="language-plaintext highlighter-rouge">&lt;action name="Person\*" method="perform\*"&gt;</code>
will be translated into <code class="language-plaintext highlighter-rouge">allowedMethod = "regex:perform(\[A-Za-z0-9-\$\]\*)"</code>.</li>
<li>SMI is enabled - no wildcard substitution will happen, you must strictly define which methods can be accessed
by annotations or <code class="language-plaintext highlighter-rouge">&lt;allowed-method/&gt;</code> tag.</li>
</ul>
<p>You can configure SMI per <code class="language-plaintext highlighter-rouge">&lt;action/&gt;</code> using <code class="language-plaintext highlighter-rouge">&lt;allowed-methods/&gt;</code> tag or via <code class="language-plaintext highlighter-rouge">@AllowedMethod</code> annotation plus using per 
<code class="language-plaintext highlighter-rouge">&lt;package/&gt;</code> <code class="language-plaintext highlighter-rouge">&lt;global-allowed-methods/&gt;</code>, see the examples below:</p>
<p><strong>SMI via struts.xml</strong></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;package</span> <span class="err">...</span><span class="nt">&gt;</span>
...
<span class="nt">&lt;global-allowed-methods&gt;</span>execute,input,back,cancel,browse<span class="nt">&lt;/global-allowed-methods&gt;</span>
...
 
<span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"Bar"</span><span class="nt">&gt;</span>
<span class="nt">&lt;allowed-methods&gt;</span>foo,bar<span class="nt">&lt;/allowed-methods&gt;</span>
<span class="nt">&lt;/action&gt;</span>
 
...
<span class="nt">&lt;/package&gt;</span>
</code></pre></div></div>
<p><strong>SMI via annotation on action class level</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@AllowedMethods</span><span class="o">(</span><span class="s">"end"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ClassLevelAllowedMethodsAction</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">execute</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">...</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p><strong>SMI via annotation on package level (in package-info.java)</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@org</span><span class="o">.</span><span class="na">apache</span><span class="o">.</span><span class="na">struts2</span><span class="o">.</span><span class="na">convention</span><span class="o">.</span><span class="na">annotation</span><span class="o">.</span><span class="na">AllowedMethods</span><span class="o">({</span><span class="s">"home"</span><span class="o">,</span> <span class="s">"start"</span><span class="o">})</span>
<span class="kn">package</span> <span class="nn">org.apache.struts2.convention.actions.allowedmethods</span><span class="o">;</span>
</code></pre></div></div>
<p>Allowed methods can be defined as:</p>
<ul>
<li>literals ie. in xml: <code class="language-plaintext highlighter-rouge">execute,cancel</code> or in annotation: <code class="language-plaintext highlighter-rouge">{"execute", "cancel"}</code></li>
<li>patterns when using with wildcard mapping, i.e <code class="language-plaintext highlighter-rouge">&lt;action ... method="do{2}"/&gt;</code></li>
<li>RegExs using <code class="language-plaintext highlighter-rouge">regex:</code> prefix, ie: <code class="language-plaintext highlighter-rouge">&lt;global-allowed-methods&gt;execute,input,cancel,regex:user([A-Z]*)&lt;/global-allowed-methods&gt;</code></li>
</ul>
<p>Please be aware when using your own <code class="language-plaintext highlighter-rouge">ConfigurationProvider</code> that the logic to set allowed methods is defined in built-in
providers - <code class="language-plaintext highlighter-rouge">XmlConfigurationProvider</code> and <code class="language-plaintext highlighter-rouge">PackageBasedActionConfigBuilder</code> - and you must replicate such logic in your
code as by default only execute method is allowed, even when SMI is disabled.</p>
<h2 id="actionsupport-default">ActionSupport Default</h2>
<p>If the class attribute in an action mapping is left blank, the <code class="language-plaintext highlighter-rouge">com.opensymphony.xwork2.ActionSupport</code> class is used
as a default.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"Hello"</span><span class="nt">&gt;</span>
// ...
<span class="nt">&lt;/action&gt;</span>
</code></pre></div></div>
<blockquote>
<p>The ActionSupport class has an <code class="language-plaintext highlighter-rouge">execute</code> method that returns “success” and an <code class="language-plaintext highlighter-rouge">input</code> method that returns “input”.</p>
</blockquote>
<p>To specify a different class as the default Action class, set the <code class="language-plaintext highlighter-rouge">default-class-ref</code> package attribute.</p>
<blockquote>
<p>For more about using wildcards, see <a href="wildcard-mappings">Wildcard Mappings</a>.</p>
</blockquote>
<h2 id="post-back-default">Post-Back Default</h2>
<p>A good practice is to link to actions rather than pages. Linking to actions encapsulates which server page renders,
and ensures that an Action class can fire before a page renders.</p>
<p>Another common workflow stategy is to first render a page using an alternate method, like <code class="language-plaintext highlighter-rouge">input</code> and then have it
submit back to the default <code class="language-plaintext highlighter-rouge">execute</code> method.</p>
<p>Using these two strategies together creates an opportunity to use a “post-back” form that doesn’t specify an action.
The form simply submits back to the action that created it.</p>
<p><strong>Posting Back</strong></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;s:form&gt;</span>
<span class="nt">&lt;s:textfield</span> <span class="na">label=</span><span class="s">"Please enter your name"</span> <span class="na">name=</span><span class="s">"name"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;s:submit/&gt;</span>
<span class="nt">&lt;/s:form&gt;</span>
</code></pre></div></div>
<h2 id="action-default">Action Default</h2>
<p>Usually, if an action is requested, and the framework can’t map the request to an action name, the result will be
the usual “404 - Page not found” error. But, if you would prefer that an omnibus action handle any unmatched requests,
you can specify a default action. If no other action matches, the default action is used instead.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;package</span> <span class="na">name=</span><span class="s">"Hello"</span> <span class="na">extends=</span><span class="s">"action-default"</span><span class="nt">&gt;</span>
<span class="nt">&lt;default-action-ref</span> <span class="na">name=</span><span class="s">"UnderConstruction"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"UnderConstruction"</span><span class="nt">&gt;</span>
<span class="nt">&lt;result&gt;</span>/UnderConstruction.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;/action&gt;</span>
...
</code></pre></div></div>
<p>There are no special requirements for the default action. Each package can have its own default action, but there should
only be one default action per namespace.</p>
<p><strong>(!) One to a Namespace</strong></p>
<blockquote>
<p>The default action features should be set up so that there is only one default action per namespace. If you have
multiple packages declaring a default action with the same namespace, there is no guarantee which action will be the default.</p>
</blockquote>
<p><strong>Wildcard Default</strong></p>
<p>Using wildcards is another approach to default actions. A wildcard action at the end of the configuration can be used to catch unmatched references.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;action</span> <span class="na">name=</span><span class="s">"*"</span><span class="nt">&gt;</span>
<span class="nt">&lt;result&gt;</span>/{1}.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;/action&gt;</span>
</code></pre></div></div>
<p>When a new action is needed, just add a stub page.</p>
<blockquote>
<p>It’s important to put a “catchall” wildcard mapping like this at the end of your configuration so it won’t attempt
to map every request!</p>
</blockquote>
</section>
</article>
<footer class="container">
<div class="col-md-12">
Copyright &copy; 2000-2022 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
Apache Struts, Struts, Apache, the Apache feather logo, and the Apache Struts project logos are
trademarks of The Apache Software Foundation. All Rights Reserved.
</div>
<div class="col-md-12">Logo and website design donated by <a href="https://softwaremill.com/">SoftwareMill</a>.</div>
</footer>
<script>!function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (!d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = "//platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
}
}(document, "script", "twitter-wjs");</script>
<script src="https://apis.google.com/js/platform.js" async="async" defer="defer"></script>
<div id="fb-root"></div>
<script>(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_GB/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
</body>
</html>