Added: websites/production/struts/content/plugins/convention/index.html ============================================================================== --- websites/production/struts/content/plugins/convention/index.html (added) +++ websites/production/struts/content/plugins/convention/index.html Thu Jul 13 11:34:56 2017 @@ -0,0 +1,1215 @@ +<!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>Convention plugin</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="/highlighter/github-theme.css" rel="stylesheet"> + + <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> + <script type="text/javascript" src="/bootstrap/js/bootstrap.js"></script> + <script type="text/javascript" src="/js/community.js"></script> +</head> +<body> + +<a href="http://github.com/apache/struts" class="github-ribbon"> + <img style="position: absolute; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub"> +</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="/downloads.html">Downloads</a></li> + <li><a href="/announce.html">Announcements</a></li> + <li><a href="http://www.apache.org/licenses/">License</a></li> + <li><a href="http://apache.org/foundation/thanks.html">Thanks!</a></li> + <li><a href="http://apache.org/foundation/sponsorship.html">Sponsorship</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 class="divider"></li> + <li><a href="/maven/project-info.html">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="/docs/tutorials.html">Tutorials</a></li> + <li><a href="/docs/faqs.html">FAQs</a></li> + <li><a href="/docs/guides.html">Guides</a></li> + <li class="divider"></li> + <li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li> + <li><a href="/docs/plugins.html">Plugin APIs</a></li> + <li><a href="/docs/tag-reference.html">Tag reference</a></li> + <li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li> + <li class="divider"></li> + <li><a href="/core-developers/">Core Developers Guide (WIP)</a></li> + <li><a href="/plugins/">Plugins (WIP)</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</a></li> + <li><a href="/coding-standards.html">Coding standards</a></li> + <li class="divider"></li> + <li><a href="/releases.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://git-wip-us.apache.org/repos/asf?p=struts.git">Source Repository</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 href="../" title="back to Plugins"><< back to Plugins</a> + <h1 class="no_toc" id="convention-plugin">Convention Plugin</h1> + +<p><a href="https://github.com/apache/struts-site/edit/master/source/plugins/convention/index.md" class="edit-on-gh" title="Edit this page on GitHub">Edit on GitHub</a></p> + +<ul id="markdown-toc"> + <li><a href="#introduction" id="markdown-toc-introduction">Introduction</a></li> + <li><a href="#setup" id="markdown-toc-setup">Setup</a></li> + <li><a href="#converting-a-codebehind-based-application-to-convention" id="markdown-toc-converting-a-codebehind-based-application-to-convention">Converting a Codebehind based application to Convention</a></li> + <li><a href="#hello-world" id="markdown-toc-hello-world">Hello world</a></li> + <li><a href="#code-behind-hello-world" id="markdown-toc-code-behind-hello-world">Code behind hello world</a></li> + <li><a href="#results-and-result-codes" id="markdown-toc-results-and-result-codes">Results and result codes</a></li> + <li><a href="#multiple-names" id="markdown-toc-multiple-names">Multiple names</a></li> + <li><a href="#xwork-packages" id="markdown-toc-xwork-packages">XWork packages</a></li> + <li><a href="#annotation-reference" id="markdown-toc-annotation-reference">Annotation reference</a> <ul> + <li><a href="#action-annotation" id="markdown-toc-action-annotation">Action annotation</a> <ul> + <li><a href="#applying-action-and-actions-at-the-class-level" id="markdown-toc-applying-action-and-actions-at-the-class-level">Applying <code class="highlighter-rouge">@Action</code> and <code class="highlighter-rouge">@Actions</code> at the class level</a></li> + </ul> + </li> + <li><a href="#interceptorref-annotation" id="markdown-toc-interceptorref-annotation">InterceptorRef annotation</a></li> + <li><a href="#result-annotation" id="markdown-toc-result-annotation">Result annotation</a></li> + <li><a href="#namespace-annotation" id="markdown-toc-namespace-annotation">Namespace annotation</a></li> + <li><a href="#resultpath-annotation" id="markdown-toc-resultpath-annotation">ResultPath annotation</a></li> + <li><a href="#parentpackage-annotation" id="markdown-toc-parentpackage-annotation">ParentPackage annotation</a></li> + <li><a href="#exceptionmapping-annotation" id="markdown-toc-exceptionmapping-annotation">ExceptionMapping Annotation</a></li> + </ul> + </li> + <li><a href="#actions-in-jar-files" id="markdown-toc-actions-in-jar-files">Actions in jar files</a></li> + <li><a href="#automatic-configuration-reloading" id="markdown-toc-automatic-configuration-reloading">Automatic configuration reloading</a></li> + <li><a href="#jboss" id="markdown-toc-jboss">JBoss</a></li> + <li><a href="#jetty-embedded" id="markdown-toc-jetty-embedded">Jetty (embedded)</a></li> + <li><a href="#troubleshooting" id="markdown-toc-troubleshooting">Troubleshooting</a> <ul> + <li><a href="#tips" id="markdown-toc-tips">Tips</a></li> + <li><a href="#common-errors" id="markdown-toc-common-errors">Common Errors</a></li> + </ul> + </li> + <li><a href="#overwriting-plugin-classes" id="markdown-toc-overwriting-plugin-classes">Overwriting plugin classes</a></li> + <li><a href="#configuration-reference" id="markdown-toc-configuration-reference">Configuration reference</a></li> +</ul> + +<h2 id="introduction">Introduction</h2> + +<p>The Convention Plugin is bundled with Struts since 2.1 and replaces the <em>Codebehind Plugin</em> and Zero Config plugins. +It provides the following features:</p> + +<ul> + <li>Action location by package naming conventions</li> + <li>Result (JSP, FreeMarker, etc) location by naming conventions</li> + <li>Class name to URL naming convention</li> + <li>Package name to namespace convention</li> + <li>SEO compliant URLs (i.e. <code class="highlighter-rouge">my-action</code> rather than <code class="highlighter-rouge">MyAction</code>)</li> + <li>Action name overrides using annotations</li> + <li>Interceptor overrides using annotations</li> + <li>Namespace overrides using annotations</li> + <li>XWork package overrides using annotations</li> + <li>Default action and result handling (i.e. <code class="highlighter-rouge">/products</code> will try <code class="highlighter-rouge">com.example.actions.Products</code> as well as +<code class="highlighter-rouge">com.example.actions.products.Index</code>)</li> +</ul> + +<p>The Convention Plugin should require no configuration to use. Many of the conventions can be controlled using +configuration properties and many of the classes can be extended or overridden.</p> + +<h2 id="setup">Setup</h2> + +<p>In order to use the Convention plugin, you first need to add the JAR file to the <code class="highlighter-rouge">WEB-INF/lib</code> directory of your +application or include the dependency in your projectâs Maven POM file.</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><dependency></span> + <span class="nt"><groupId></span>org.apache.struts<span class="nt"></groupId></span> + <span class="nt"><artifactId></span>struts2-convention-plugin<span class="nt"></artifactId></span> + <span class="nt"><version></span>X.X.X<span class="nt"></version></span> +<span class="nt"></dependency></span> +</code></pre> +</div> + +<p>Where <code class="highlighter-rouge">X.X.X</code> is the current version of Struts 2. Please remember that the Convention Plugin is available from +version 2.1.6.</p> + +<h2 id="converting-a-codebehind-based-application-to-convention">Converting a Codebehind based application to Convention</h2> + +<p>See <a href="converting.html">this page</a> for the required changes and tips.</p> + +<p>If you are using REST with the Convention plugin, make sure you set these constants in <code class="highlighter-rouge">struts.xml</code>:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.action.suffix"</span> <span class="na">value=</span><span class="s">"Controller"</span><span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.action.mapAllMatches"</span> <span class="na">value=</span><span class="s">"true"</span><span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.default.parent.package"</span> <span class="na">value=</span><span class="s">"rest-default"</span><span class="nt">/></span> +</code></pre> +</div> + +<h2 id="hello-world">Hello world</h2> + +<p>Now that the Convention plugin has been added to your application, letâs start with a very simple example. This example +will use an actionless result that is identified by the URL. By default, the Convention plugin assumes that all +of the results are stored in <strong>WEB-INF/content</strong>. This can be changed by setting the property +<code class="highlighter-rouge">struts.convention.result.path</code> in the Struts properties file to the new location. Donât worry about trailing slashes, +the Convention plugin handles this for you. Here is our hello world JSP:</p> + +<pre><code class="language-jsp"><html> +<body> + Hello world! +</body> +</html> +</code></pre> + +<p>If you start Tomcat (or whichever J2EE container you are using) and type in +<a href="http://localhost:8080/hello-world">http://localhost:8080/hello-world</a>Â (assuming that your context path is <code class="highlighter-rouge">/</code>, +ie. starting application from Eclipse) into your browser you should get this result:</p> + +<p><strong>WEB-INF/content/hello-world.jsp</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code>Hello world! +</code></pre> +</div> + +<p>This illustrates that the Convention plugin will find results even when no action exists and it is all based on the URL +passed to Struts.</p> + +<h2 id="code-behind-hello-world">Code behind hello world</h2> + +<p>Letâs expand on this example and add a code behind class. In order to do this we need to ensure that the Convention +plugin is able to find our action classes. By default, the Convention plugin will find all action classes that implement +<code class="highlighter-rouge">com.opensymphony.xwork2.Action</code> or whose name ends with the word <strong>Action</strong> in specific packages.</p> + +<p>These packages are located by the Convention plugin using a search methodology. First the Convention plugin finds +packages named <code class="highlighter-rouge">struts</code>, <code class="highlighter-rouge">struts2</code>, <code class="highlighter-rouge">action</code> or <code class="highlighter-rouge">actions</code>. Any packages that match those names are considered the root +packages for the Convention plugin. Next, the plugin looks at all of the classes in those packages as well +as sub-packages and determines if the classes implement <code class="highlighter-rouge">com.opensymphony.xwork2.Action</code> or if their name ends with +<strong>Action</strong> (i.e. <code class="highlighter-rouge">FooAction</code>). Hereâs an example of a few classes that the Convention plugin will find:</p> + +<p><strong>Classes</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code>com.example.actions.MainAction +com.example.actions.products.Display (implements com.opensymphony.xwork2.Action) +com.example.struts.company.details.ShowCompanyDetailsAction +</code></pre> +</div> + +<p>Each of the action classes that the plugin finds will be configured to respond to specific URLs. The URL is based on +the package name that the class is defined in and the class name itself. First the plugin determines the namespace of +the URL using the package names between the root package and the package the class is defined in. For our examples above, +the namespaces would be:</p> + +<p><strong>Namespaces</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code>com.example.actions.MainAction -> / +com.example.actions.products.Display -> /products +com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details +</code></pre> +</div> + +<p>Next, the plugin determines the URL of the resource using the class name. It first removes the word <strong>Action</strong> from the end of the class name and then converts camel case names to dashes. In our example the full URLs would be:</p> + +<p><strong>Full URLs</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code>com.example.actions.MainAction -> /main +com.example.actions.products.Display -> /products/display +com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details/show-company-details +</code></pre> +</div> + +<p>You can tell the Convention plugin to ignore certain packages using the property <code class="highlighter-rouge">struts.convention.exclude.packages</code>. +You can also tell the plugin to use different strings to locate root packages using the property +<code class="highlighter-rouge">struts.convention.package.locators</code>. Finally, you can tell the plugin to search specific root packages using +the property <code class="highlighter-rouge">struts.convention.action.packages</code>.</p> + +<p>Here is our code behind action class:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> + +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="kd">private</span> <span class="n">String</span> <span class="n">message</span><span class="o">;</span> + + <span class="kd">public</span> <span class="n">String</span> <span class="n">getMessage</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">message</span><span class="o">;</span> + <span class="o">}</span> + + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="n">message</span> <span class="o">=</span> <span class="s">"Hello World!"</span><span class="o">;</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>If you compile this class and place it into your application in the WEB-INF/classes, the Convention plugin will find +the class and map the URL <strong>/hello-world</strong> to it. Next, we need to update our JSP to print out the message we setup in +the action class. Here is the new JSP:</p> + +<p><strong>WEB-INF/content/hello-world.jsp</strong></p> + +<pre><code class="language-jsp"><html> +<body> + The message is ${message} +</body> +</html> +</code></pre> + +<blockquote> + <p>Please notice that the expression <code class="highlighter-rouge">${message}</code> will work without adding JSP directive <code class="highlighter-rouge">isELIgnored="false"</code>.</p> +</blockquote> + +<p>If start up the application server and open up <a href="http://localhost:8080/hello-world">http://localhost:8080/hello-world</a> +in our browser, we should get this result:</p> + +<p><strong>Result</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code>The message is Hello World! +</code></pre> +</div> + +<h2 id="results-and-result-codes">Results and result codes</h2> + +<p>The Convention Plugin will pre-configure all of you action classes when Struts is started. By default, this +configuration will also contain results for any JSPs that it can find within the application. The JSPs have +an additional feature that allows different JSPs to be used based on the result code of the action. Since action +methods return Strings and these Strings are traditionally used to locate results for the action, the Convention plugin +allows you to define different results based on the result code.</p> + +<p>Building on our example from above, letâs say we want to provide a different result if the result code from our action +is the String <code class="highlighter-rouge">zero</code> rather than <code class="highlighter-rouge">success</code>. First, we update the action class to return different result codes:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> + +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="kd">private</span> <span class="n">String</span> <span class="n">message</span><span class="o">;</span> + + <span class="kd">public</span> <span class="n">String</span> <span class="n">getMessage</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">message</span><span class="o">;</span> + <span class="o">}</span> + + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">if</span> <span class="o">(</span><span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">()</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span> + <span class="n">message</span> <span class="o">=</span> <span class="s">"It's 0"</span><span class="o">;</span> + <span class="k">return</span> <span class="s">"zero"</span><span class="o">;</span> + <span class="o">}</span> + + <span class="n">message</span> <span class="o">=</span> <span class="s">"It's 1"</span><span class="o">;</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>Next, we add a new JSP to the application named <code class="highlighter-rouge">WEB-INF/content/hello-world-zero.jsp</code>. Notice that the first part +of the file name is the same as the URL of the action and the last part of the name is the result code. This is +the convention that the plugin uses to determine which results to render. Here is our new JSP:</p> + +<p><strong>WEB-INF/content/hello-world.jsp</strong></p> + +<pre><code class="language-jsp"><html> +<body> + The error message is ${message} +</body> +</html> +</code></pre> + +<p>Now, if you compile the action and restart the application, based on the current time, youâll either see the result from +<code class="highlighter-rouge">WEB-INF/content/hello-world.jsp</code> or <code class="highlighter-rouge">WEB-INF/content/hello-world-zero.jsp</code>.</p> + +<p>The result type is based on the extension of the file. The supported extensions are: jsp,ftl,vm,html,html. +Examples of Action and Result to Template mapping:</p> + +<table> + <thead> + <tr> + <th>URL</th> + <th>Result</th> + <th>File that could match</th> + <th>Result Type</th> + </tr> + </thead> + <tbody> + <tr> + <td>/hello</td> + <td>success</td> + <td>/WEB-INF/content/hello.jsp</td> + <td>Dispatcher</td> + </tr> + <tr> + <td>/hello</td> + <td>success</td> + <td>/WEB-INF/content/hello-success.htm</td> + <td>Dispatcher</td> + </tr> + <tr> + <td>/hello</td> + <td>success</td> + <td>/WEB-INF/content/hello.ftl</td> + <td>FreeMarker</td> + </tr> + <tr> + <td>/hello-world</td> + <td>input</td> + <td>/WEB-INF/content/hello-world-input.vm</td> + <td>Velocity</td> + </tr> + <tr> + <td>/test1/test2/hello</td> + <td>error</td> + <td>/WEB-INF/content/test/test2/hello-error.html</td> + <td>Dispatcher</td> + </tr> + </tbody> +</table> + +<h2 id="multiple-names">Multiple names</h2> + +<p>It is possible to define multiple names for the same result:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nd">@Action</span><span class="o">(</span><span class="n">results</span> <span class="o">=</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">"error"</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">"input-form.jsp"</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">"success"</span><span class="o">,</span> <span class="n">location</span><span class="o">=</span><span class="s">"success.jsp"</span><span class="o">)</span> +<span class="o">})</span> +</code></pre> +</div> + +<p>Such functionality was added in Struts version 2.5.</p> + +<p>##Chaining</p> + +<p>If one action returns the name of another action in the same package, they will be chained together, if the first action +doesnât have any result defined for that code. In the following example:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> + +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloAction</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="s">"foo"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">foo</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="s">"bar"</span><span class="o">;</span> + <span class="o">}</span> + + <span class="nd">@Action</span><span class="o">(</span><span class="s">"foo-bar"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">bar</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>The âfooâ action will be executed, because no result is found, the Convention plugin tries to find an action named +âfoo-barâ on the same package where âfooâ is defined. If such an action is found, it will be invoked using +the âchainâ result.</p> + +<h2 id="xwork-packages">XWork packages</h2> + +<p>Actions are placed on a custom XWork package which prevents conflicts. The name of this package is based on the Java +package the action is defined in, the namespace part of the URL for the action and the parent XWork package for +the action. The parent XWork package is determined based on the property named <code class="highlighter-rouge">struts.convention.default.parent.package</code> +(defaults to <code class="highlighter-rouge">convention-default</code>), which is a custom XWork package that extends <code class="highlighter-rouge">struts-default</code>.</p> + +<p>Therefore the naming for XWork packages used by the Convention plugin are in the form:</p> + +<p><strong>XWork package naming</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><java-package>#<namespace>#<parent-package> +</code></pre> +</div> + +<p>Using our example from above, the XWork package for our action would be:</p> + +<p><strong>XWork package naming</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code>com.example.actions#/#conventionDefault +</code></pre> +</div> + +<h2 id="annotation-reference">Annotation reference</h2> + +<p>The Convention plugin uses a number of different annotations to override the default conventions that are used to map +actions to URLs and locate results. In addition, you can modify the parent XWork package that actions are configured with.</p> + +<h3 id="action-annotation">Action annotation</h3> + +<p>The Convention plugin allows action classes to change the URL that they are mapped to using the <strong>Action</strong> annotation. +This annotation can also be used inside the <strong>Actions</strong> annotation to allow multiple URLs to map to a single action +class. This annotation must be defined on action methods like this:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> + +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="s">"/different/url"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>Our action class will now map to the URL <code class="highlighter-rouge">/different/url</code> rather than <code class="highlighter-rouge">/hello-world</code>. If no <code class="highlighter-rouge">@Result</code> (see next section) +is specified, then the namespace of the action will be used as the path to the result, on our last example it would be +<code class="highlighter-rouge">/WEB-INF/content/different/url.jsp</code>.</p> + +<p>A single method within an action class can also map to multiple URLs using the <strong>Actions</strong> annotation like this:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Actions</span><span class="o">;</span> + +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Actions</span><span class="o">({</span> + <span class="nd">@Action</span><span class="o">(</span><span class="s">"/different/url"</span><span class="o">),</span> + <span class="nd">@Action</span><span class="o">(</span><span class="s">"/another/url"</span><span class="o">)</span> + <span class="o">})</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>Another usage of the <strong>Action</strong> or <strong>Actions</strong> annotation is to define multiple action methods within a single action +class, each of which respond to a different URL. Here is an example of multiple action methods:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Actions</span><span class="o">;</span> + +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="s">"/different/url"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + + + <span class="o">}</span> + + <span class="nd">@Action</span><span class="o">(</span><span class="s">"url"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">doSomething</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>The previous example defines a second URL that is not fully qualified. This means that the namespace for the URL +is determined using the Java package name rather than the Action annotation.</p> + +<p>Interceptor and interceptor stacks can be specified using the <code class="highlighter-rouge">interceptorRefs</code> attribute. The following example applies +the <code class="highlighter-rouge">validation</code> interceptor and the <code class="highlighter-rouge">defaultStack</code> interceptor stack to the action:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Actions</span><span class="o">;</span> + +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="n">interceptorRefs</span><span class="o">={</span><span class="nd">@InterceptorRef</span><span class="o">(</span><span class="s">"validation"</span><span class="o">),</span> <span class="nd">@InterceptorRef</span><span class="o">(</span><span class="s">"defaultStack"</span><span class="o">)})</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> + + <span class="nd">@Action</span><span class="o">(</span><span class="s">"url"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">doSomething</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>Parameters can be passed to results using the <strong>params</strong> attribute. The value of this attribute is a string array with +an even number of elements in the form <code class="highlighter-rouge"><span class="p">{</span><span class="nt">"key0"</span><span class="err">,</span><span class="w"> </span><span class="nt">"value0, "</span><span class="err">key1</span><span class="nt">", "</span><span class="err">value1</span><span class="nt">" ... "</span><span class="err">keyN</span><span class="nt">", "</span><span class="err">valueN"}</span></code>. For example:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Actions</span><span class="o">;</span> + +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="n">interceptorRefs</span><span class="o">=</span><span class="nd">@InterceptorRef</span><span class="o">(</span><span class="n">value</span><span class="o">=</span><span class="s">"validation"</span><span class="o">,</span><span class="n">params</span><span class="o">={</span><span class="s">"programmatic"</span><span class="o">,</span> <span class="s">"false"</span><span class="o">,</span> <span class="s">"declarative"</span><span class="o">,</span> <span class="s">"true})) + public String execute() { + return SUCCESS; + } + + @Action("</span><span class="n">url</span><span class="err">"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">doSomething</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>If interceptors are not specified, the default stack is applied.</p> + +<blockquote> + <p>You can specify className parameter which can be especially useful when Spring Framework is used to instantiate actions.</p> +</blockquote> + +<h4 id="applying-action-and-actions-at-the-class-level">Applying <code class="highlighter-rouge">@Action</code> and <code class="highlighter-rouge">@Actions</code> at the class level</h4> + +<p>There are circumstances when this is desired, like when using <em>Dynamic Method Invocation</em> . If an <code class="highlighter-rouge">execute</code> method is +defined in the class, then it will be used for the action mapping, otherwise the method to be used will be determined +when a request is made (by Dynamic Method Invocation for example)</p> + +<h3 id="interceptorref-annotation">InterceptorRef annotation</h3> + +<p>Interceptors can be specified at the method level, using the <strong>Action</strong> annotation or at the class level using +the <code class="highlighter-rouge">InterceptorRefs</code> annotation. Interceptors specified at the class level will be applied to all actions defined +on that class. In the following example:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Actions</span><span class="o">;</span> + +<span class="nd">@InterceptorRefs</span><span class="o">({</span> + <span class="nd">@InterceptorRef</span><span class="o">(</span><span class="s">"interceptor-1"</span><span class="o">),</span> + <span class="nd">@InterceptorRef</span><span class="o">(</span><span class="s">"defaultStack"</span><span class="o">)</span> +<span class="o">})</span> +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="n">value</span><span class="o">=</span><span class="s">"action1"</span><span class="o">,</span> <span class="n">interceptorRefs</span><span class="o">=</span><span class="nd">@InterceptorRef</span><span class="o">(</span><span class="s">"validation"</span><span class="o">))</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> + + <span class="nd">@Action</span><span class="o">(</span><span class="n">value</span><span class="o">=</span><span class="s">"action2"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">doSomething</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>The following interceptors will be applied to âaction1â: <code class="highlighter-rouge">interceptor-1</code> , all interceptors from <code class="highlighter-rouge">defaultStack</code>, +<code class="highlighter-rouge">validation</code>. All interceptors from <code class="highlighter-rouge">defaultStack</code> will be applied to âaction2â.</p> + +<blockquote> + <p>If you get errors like âUnable to find interceptor class referenced by ref-name XYZâ. This means that the package +where Convention is placing your actions, does not extend the package where the interceptor is defined. To fix this +problem either 1)Use @ParentPackage annotation(or struts.convention.default.parent.package) passing the name of the +package that defines the interceptor, or 2) Create a package in XML that extends the package that defines the +interceptor, and use @ParentPackage(or struts.convention.default.parent.package) to point to it.</p> +</blockquote> + +<h3 id="result-annotation">Result annotation</h3> + +<p>The Convention plugin allows action classes to define different results for an action. Results fall into two categories, +global and local. Global results are shared across all actions defined within the action class. These results are +defined as annotations on the action class. Local results apply only to the action method they are defined on. Here is +an example of the different types of result annotations:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Actions</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Result</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Results</span><span class="o">;</span> + +<span class="nd">@Results</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">"failure"</span><span class="o">,</span> <span class="n">location</span><span class="o">=</span><span class="s">"fail.jsp"</span><span class="o">)</span> +<span class="o">})</span> +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="n">value</span><span class="o">=</span><span class="s">"/different/url"</span><span class="o">,</span> + <span class="n">results</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">"success"</span><span class="o">,</span> <span class="n">location</span><span class="o">=</span><span class="s">"http://struts.apache.org"</span><span class="o">,</span> <span class="n">type</span><span class="o">=</span><span class="s">"redirect"</span><span class="o">)}</span> + <span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> + + <span class="nd">@Action</span><span class="o">(</span><span class="s">"/another/url"</span><span class="o">)</span> + + <span class="kd">public</span> <span class="n">String</span> <span class="n">doSomething</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>Parameters can be passed to results using the <strong>params</strong> attribute. The value of this attribute is a string array with +an even number of elements in the form <code class="highlighter-rouge"><span class="p">{</span><span class="nt">"key0"</span><span class="err">,</span><span class="w"> </span><span class="nt">"value0, "</span><span class="err">key1</span><span class="nt">", "</span><span class="err">value1</span><span class="nt">" ... "</span><span class="err">keyN</span><span class="nt">", "</span><span class="err">valueN"}</span></code>. For example:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Actions</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Result</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Results</span><span class="o">;</span> + +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="n">value</span><span class="o">=</span><span class="s">"/different/url"</span><span class="o">,</span> + <span class="n">results</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">"success"</span><span class="o">,</span> <span class="n">type</span><span class="o">=</span><span class="s">"httpheader"</span><span class="o">,</span> <span class="n">params</span><span class="o">={</span><span class="s">"status"</span><span class="o">,</span> <span class="s">"500"</span><span class="o">,</span> <span class="s">"errorMessage"</span><span class="o">,</span> <span class="s">"Internal Error"</span><span class="o">})}</span> + <span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> + + <span class="nd">@Action</span><span class="o">(</span><span class="s">"/another/url"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">doSomething</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>From 2.1.7 on, global results (defined on the class level) defined using annotations will be inherited. Child classes +can override the inherited result(s) by redefining it. Also, results defined at the method level take precedence +(overwrite), over results with the same name at the action level.</p> + +<h3 id="namespace-annotation">Namespace annotation</h3> + +<p>The namespace annotation allows the namespace for action classes to be changed instead of using the convention of the Java +package name. This annotation can be placed on an action class or within the package-info.java class that allows +annotations to be placed on Java packages. When this annotation is put on an action class, it applies to all actions +defined in the class, that are not fully qualified action URLs. When this annotation is place in the <code class="highlighter-rouge">package-info.java</code> +file, it changes the default namespace for all actions defined in the Java package. Here is an example of the annotation +on an action class:</p> + +<p><strong>com.example.actions.HelloWorl</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Namespace</span><span class="o">;</span> + +<span class="nd">@Namespace</span><span class="o">(</span><span class="s">"/custom"</span><span class="o">)</span> +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="s">"/different/url"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> + + <span class="nd">@Action</span><span class="o">(</span><span class="s">"url"</span><span class="o">)</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">doSomething</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>In this example, the action will respond to two different URLs <code class="highlighter-rouge">/different/url</code> and <code class="highlighter-rouge">/custom/url</code>. Here is an example +of using this annotation in the package-info.java file:</p> + +<p><strong>com/example/actions/package-info.java</strong></p> + +<div class="highlighter-rouge"><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">Namespace</span><span class="o">(</span><span class="s">"/custom"</span><span class="o">)</span> +<span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> +</code></pre> +</div> + +<p>This changes the default namespace for all actions defined in the package <code class="highlighter-rouge">com.example.actions</code>. This annotation however +doesnât apply to sub-packages.</p> + +<h3 id="resultpath-annotation">ResultPath annotation</h3> + +<p>The ResultPath annotation allows applications to change the location where results are stored. This annotation can be +placed on an action class and also in the package-info.java file. Here is an example of using this annotation:</p> + +<p><strong>com.example.actions.HelloWorl</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.ResultPath</span><span class="o">;</span> + +<span class="nd">@ResultPath</span><span class="o">(</span><span class="s">"/WEB-INF/jsps"</span><span class="o">)</span> +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>The result for this class will be located in <code class="highlighter-rouge">WEB-INF/jsps</code> rather than the default of <code class="highlighter-rouge">WEB-INF/content</code>.</p> + +<h3 id="parentpackage-annotation">ParentPackage annotation</h3> + +<p>The ParentPackage annotation allows applications to define different parent Struts package for specific action classes +or Java packages. Here is an example of using the annotation on an action class:</p> + +<p><strong>com.example.actions.HelloWorld</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">example</span><span class="o">.</span><span class="na">actions</span><span class="o">;</span> + +<span class="kn">import</span> <span class="nn">com.opensymphony.xwork2.ActionSupport</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.Action</span><span class="o">;</span> +<span class="kn">import</span> <span class="nn">org.apache.struts2.convention.annotation.ParentPackage</span><span class="o">;</span> + +<span class="nd">@ParentPackage</span><span class="o">(</span><span class="s">"customXWorkPackage"</span><span class="o">)</span> +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloWorld</span> <span class="kd">extends</span> <span class="n">ActionSupport</span> <span class="o">{</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="o">{</span> + <span class="k">return</span> <span class="n">SUCCESS</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>To apply this annotation to all actions in a package (and subpackages), add it to package-info.java. An alternative +to this annotation is to set <code class="highlighter-rouge">struts.convention.default.parent.package</code> in XML.</p> + +<h3 id="exceptionmapping-annotation">ExceptionMapping Annotation</h3> + +<p>This annotation can be used to define exception mappings to actions. See the <em>exception mapping documentation</em> for more +details. These mappings can be applied to the class level, in which case they will be applied to all actions defined +on that class:</p> + +<p><strong>ExceptionsActionLevelAction.java</strong></p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nd">@ExceptionMappings</span><span class="o">({</span> + <span class="nd">@ExceptionMapping</span><span class="o">(</span><span class="n">exception</span> <span class="o">=</span> <span class="s">"java.lang.NullPointerException"</span><span class="o">,</span> <span class="n">result</span> <span class="o">=</span> <span class="s">"success"</span><span class="o">,</span> <span class="n">params</span> <span class="o">=</span> <span class="o">{</span><span class="s">"param1"</span><span class="o">,</span> <span class="s">"val1"</span><span class="o">})</span> +<span class="o">})</span> +<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ExceptionsActionLevelAction</span> <span class="o">{</span> + + <span class="kd">public</span> <span class="n">String</span> <span class="n">execute</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span> + <span class="k">return</span> <span class="kc">null</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<p>The parameters defined by <code class="highlighter-rouge">params</code> are passed to the result. Exception mappings can also be applied to the action level:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ExceptionsMethodLevelAction</span> <span class="o">{</span> + <span class="nd">@Action</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="s">"exception1"</span><span class="o">,</span> <span class="n">exceptionMappings</span> <span class="o">=</span> <span class="o">{</span> + <span class="nd">@ExceptionMapping</span><span class="o">(</span><span class="n">exception</span> <span class="o">=</span> <span class="s">"java.lang.NullPointerException"</span><span class="o">,</span> <span class="n">result</span> <span class="o">=</span> <span class="s">"success"</span><span class="o">,</span> <span class="n">params</span> <span class="o">=</span> <span class="o">{</span><span class="s">"param1"</span><span class="o">,</span> <span class="s">"val1"</span><span class="o">})</span> + <span class="o">})</span> + <span class="kd">public</span> <span class="n">String</span> <span class="n">run1</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span> + <span class="k">return</span> <span class="kc">null</span><span class="o">;</span> + <span class="o">}</span> +<span class="o">}</span> +</code></pre> +</div> + +<h2 id="actions-in-jar-files">Actions in jar files</h2> + +<p>By default the Convention plugin will <strong>not</strong> scan jar files for actions. For a jar to be scanned, its URL needs +to match at least one of the regular expressions in <code class="highlighter-rouge">struts.convention.action.includeJars</code> . In this example +<code class="highlighter-rouge">myjar1.jar</code> and <code class="highlighter-rouge">myjar2.jar</code> will be scanned:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.action.includeJars"</span> <span class="na">value=</span><span class="s">".*?/myjar1.*?jar(!/)?,.*?/myjar2*?jar(!/)?"</span> +</code></pre> +</div> + +<p>Note that <strong>the regular expression will be evaluated against the URL of the jar, and not the file name</strong>, the jar URL +can contain a path to the jar file and a trailing <code class="highlighter-rouge">!/</code>.</p> + +<h2 id="automatic-configuration-reloading">Automatic configuration reloading</h2> + +<p>The Convention plugin can automatically reload configuration changes, made in classes the contain actions, without +restarting the container. This is a similar behavior to the automatic xml configuration reloading. To enable this +feature, add this to your <code class="highlighter-rouge">struts.xml</code> file:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.devMode"</span> <span class="na">value=</span><span class="s">"true"</span><span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.classes.reload"</span> <span class="na">value=</span><span class="s">"true"</span> <span class="nt">/></span> +</code></pre> +</div> + +<p>This feature is experimental and has not been tested on all container, and it is <strong>strongly</strong> advised not to use it +in production environments.</p> + +<h2 id="jboss">JBoss</h2> + +<p>When using this plugin with JBoss, you need to set the following constants:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.exclude.parentClassLoader"</span> <span class="na">value=</span><span class="s">"true"</span> <span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.action.fileProtocols"</span> <span class="na">value=</span><span class="s">"jar,vfsfile,vfszip"</span> <span class="nt">/></span> +</code></pre> +</div> + +<p>You can also check the <em>JBoss 5</em> Â page for more details.</p> + +<h2 id="jetty-embedded">Jetty (embedded)</h2> + +<p>When using this plugin with Jetty in embedded mode, you need to set the following constants:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.exclude.parentClassLoader"</span> <span class="na">value=</span><span class="s">"false"</span> <span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.action.fileProtocols"</span> <span class="na">value=</span><span class="s">"jar,code-source"</span> <span class="nt">/></span> +</code></pre> +</div> + +<h2 id="troubleshooting">Troubleshooting</h2> + +<h3 id="tips">Tips</h3> + +<ul> + <li> + <p>Make sure the namespace of the action is matched by one of the locators. The rest of the namespace after the locator, +will be the namespace of the action, and will be used to find the results. For example, a class called âViewActionâ in +the package âmy.example.actions.ordersâ will be mapped to the URL /orders/view.action, and the results must be under +/WEB-INF/content/orders, like /WEB-INF/content/orders/view-success.jsp.</p> + </li> + <li> + <p>Add the <em>Config Browser Plugin</em> plugin to the lib folder or maven dependencies, and then visit: + <a href="http://localhost:8080/CONTEXT/config-browser/index.action">http://localhost:8080/CONTEXT/config-browser/index.action</a>, + to see the current action mappings.</p> + </li> + <li> + <p>The Convention plugin can generate a rather verbose output when set to debug mode for logging. Use âTraceâ logging +level if you are using the JDK logger. If you are using Log4J, you can do something like: +log4j.logger.org.apache.struts2.convention=DEBUG</p> + </li> +</ul> + +<h3 id="common-errors">Common Errors</h3> + +<ol> + <li> + <p>I get an error like âThere is no Action mapped for namespace /orders and action name view.â. This means that the URL + <code class="highlighter-rouge">/orders/view.action</code> is not mapping to any action class. Check the namespace and the name of the action.</p> + </li> + <li> + <p>I get an error like âNo result defined for action my.example.actions.orders.ViewAction and result successâ. This + means that the action was mapped to the right URL, but the Convention plugin was unable to find a <code class="highlighter-rouge">success</code> result + for it. Check that the result file exists, like <code class="highlighter-rouge">/WEB-INF/content/orders/view-success.jsp</code>.</p> + </li> + <li> + <p>I get lots of errors like âjava.lang.Exception: Could not load org/apache/velocity/runtime/resource/loader/ClasspathResourceLoader.classâ. + This happens when <code class="highlighter-rouge">struts.convention.action.includeJars</code> is matching jar URLs from external jars.</p> + </li> + <li> + <p>I am using a custom interceptor stack and I get an error like âUnable to find interceptor class referenced by ref-name XYZâ. + This means that the package where Convention is placing your actions, does not extend the package where the interceptor + is defined. To fix this problem either 1)Use @ParentPackage annotation (or <code class="highlighter-rouge">struts.convention.default.parent.package</code>) + passing the name of the package that defines the interceptor, or 2) Create a package in XML that extends the package + that defines the interceptor, and use @ParentPackage (or <code class="highlighter-rouge">struts.convention.default.parent.package</code>) to point to it.</p> + </li> +</ol> + +<h2 id="overwriting-plugin-classes">Overwriting plugin classes</h2> + +<p>The Convention plugin can be extended in the same fashion that Struts does. The following beans are defined by default:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><bean</span> <span class="na">type=</span><span class="s">"org.apache.struts2.convention.ActionConfigBuilder"</span> <span class="na">name=</span><span class="s">"convention"</span> + <span class="na">class=</span><span class="s">"org.apache.struts2.convention.PackageBasedActionConfigBuilder"</span><span class="nt">/></span> +<span class="c"><!-- +This interface defines how the action configurations for the current web application can be constructed. This must +find all actions that are not specifically defined in the struts XML files or any plugins. Furthermore, it must make +every effort to locate all action results as well. +--></span> + +<span class="nt"><bean</span> <span class="na">type=</span><span class="s">"org.apache.struts2.convention.ActionNameBuilder"</span> <span class="na">name=</span><span class="s">"convention"</span> + <span class="na">class=</span><span class="s">"org.apache.struts2.convention.SEOActionNameBuilder"</span><span class="nt">/></span> +<span class="c"><!-- +This interface defines the method that is used to create action names based on the name of a class. +--></span> + +<span class="nt"><bean</span> <span class="na">type=</span><span class="s">"org.apache.struts2.convention.ResultMapBuilder"</span> <span class="na">name=</span><span class="s">"convention"</span> + <span class="na">class=</span><span class="s">"org.apache.struts2.convention.DefaultResultMapBuilder"</span><span class="nt">/></span> +<span class="c"><!-- +This interface defines how results are constructed for an Action. The action information is supplied and the result is +a mapping of ResultConfig instances to the result name. +--></span> + +<span class="nt"><bean</span> <span class="na">type=</span><span class="s">"org.apache.struts2.convention.InterceptorMapBuilder"</span> <span class="na">name=</span><span class="s">"convention"</span> + <span class="na">class=</span><span class="s">"org.apache.struts2.convention.DefaultInterceptorMapBuilder"</span><span class="nt">/></span> +<span class="c"><!-- +This interface defines how interceptors are built from annotations. +--></span> + +<span class="nt"><bean</span> <span class="na">type=</span><span class="s">"org.apache.struts2.convention.ConventionsService"</span> <span class="na">name=</span><span class="s">"convention"</span> + <span class="na">class=</span><span class="s">"org.apache.struts2.convention.ConventionsServiceImpl"</span><span class="nt">/></span> +<span class="c"><!-- +This interface defines the conventions that are used by the convention plugin. In most cases the methods on this class +will provide the best default for any values and also handle locating overrides of the default via the annotations that +are part of the plugin. +--></span> + +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.actionConfigBuilder"</span> <span class="na">value=</span><span class="s">"convention"</span><span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.actionNameBuilder"</span> <span class="na">value=</span><span class="s">"convention"</span><span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.resultMapBuilder"</span> <span class="na">value=</span><span class="s">"convention"</span><span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.interceptorMapBuilder"</span> <span class="na">value=</span><span class="s">"convention"</span><span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.conventionsService"</span> <span class="na">value=</span><span class="s">"convention"</span><span class="nt">/></span> +</code></pre> +</div> + +<p>To plugin a different implementation for one of these classes, implement the interface, define a bean for it, and set +the appropriate constantâs value with the name of the new bean, for example:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><bean</span> <span class="na">type=</span><span class="s">"org.apache.struts2.convention.ActionNameBuilder"</span> <span class="na">name=</span><span class="s">"MyActionNameBuilder"</span> <span class="na">class=</span><span class="s">"example.SultansOfSwingNameBuilder"</span><span class="nt">/></span> +<span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.actionNameBuilder"</span> <span class="na">value=</span><span class="s">"MyActionNameBuilder"</span><span class="nt">/></span> +</code></pre> +</div> + +<h2 id="configuration-reference">Configuration reference</h2> + +<p>Add a <strong>constant</strong> element to your struts config file to change the value of a configuration setting, like:</p> + +<div class="highlighter-rouge"><pre class="highlight"><code><span class="nt"><constant</span> <span class="na">name=</span><span class="s">"struts.convention.result.path"</span> <span class="na">value=</span><span class="s">"/WEB-INF/mytemplates/"</span><span class="nt">/></span> +</code></pre> +</div> + +<table> + <thead> + <tr> + <th>Name</th> + <th>Default Value</th> + <th>Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>struts.convention.action.alwaysMapExecute</td> + <td>true</td> + <td>Set to false, to prevent Convention from creating a default mapping to âexecuteâ when there are other methods annotated as actions in the class</td> + </tr> + <tr> + <td>struts.convention.action.includeJars</td> + <td>Â </td> + <td>Comma separated list of regular expressions of jar URLs to be scanned. eg. â.<strong>myJar-0\.2.</strong>, .<strong>thirdparty-0\.1.</strong>â</td> + </tr> + <tr> + <td>struts.convention.action.packages</td> + <td>Â </td> + <td>An optional list of action packages that this should create configuration for (they donât need to match a locator pattern)</td> + </tr> + <tr> + <td>struts.convention.result.path</td> + <td>/WEB-INF/content/</td> + <td>Directory where templates are located</td> + </tr> + <tr> + <td>struts.convention.result.flatLayout</td> + <td>true</td> + <td>If set to false, the result can be put in its own directory: resultsRoot/namespace/actionName/result.extension</td> + </tr> + <tr> + <td>struts.convention.action.suffix</td> + <td>Action</td> + <td>Suffix used to find actions based on class names</td> + </tr> + <tr> + <td>struts.convention.action.disableScanning</td> + <td>false</td> + <td>Scan packages for actions</td> + </tr> + <tr> + <td>struts.convention.action.mapAllMatches</td> + <td>false</td> + <td>Create action mappings, even if no @Action is found</td> + </tr> + <tr> + <td>struts.convention.action.checkImplementsAction</td> + <td>true</td> + <td>Check if an action implements com.opensymphony.xwork2.Action to create an action mapping</td> + </tr> + <tr> + <td>struts.convention.default.parent.package</td> + <td>convention-default</td> + <td>Default parent package for action mappins</td> + </tr> + <tr> + <td>struts.convention.action.name.lowercase</td> + <td>true</td> + <td>Convert action name to lowercase</td> + </tr> + <tr> + <td>struts.convention.action.name.separator</td> + <td>-</td> + <td>Separator used to build the action name, MyAction -> my-action. This character is also used as the separator between the action name and the result in templates, like action-result.jsp</td> + </tr> + <tr> + <td>struts.convention.package.locators</td> + <td>action,actions,struts,struts2</td> + <td>Packages whose name end with one of these strings will be scanned for actions</td> + </tr> + <tr> + <td>struts.convention.package.locators.disable</td> + <td>false</td> + <td>Disable the scanning of packages based on package locators</td> + </tr> + <tr> + <td>struts.convention.exclude.packages</td> + <td><code class="highlighter-rouge">org.apache.struts.\*</code>, <code class="highlighter-rouge">org.apache.struts2.\*</code>, <code class="highlighter-rouge">org.springframework.web.struts.\*</code>, <code class="highlighter-rouge">org.springframework.web.struts2.\*</code>, <code class="highlighter-rouge">org.hibernate.\*</code></td> + <td>Packages excluded from the action scanning, packages already excluded cannot be included in other way, eg. org.demo.actions.exclude is specified as a part of the struts.convention.exclude.packages so all packages below are also excluded, eg. org.demo.actions.exclude.include even if <strong>include</strong> is specified as a struts.convention.package.locators or struts.convention.action.packages</td> + </tr> + <tr> + <td>struts.convention.package.locators.basePackage</td> + <td>Â </td> + <td>If set, only packages that start with its value will be scanned for actions</td> + </tr> + <tr> + <td>struts.convention.relative.result.types</td> + <td>dispatcher,velocity,freemarker</td> + <td>The list of result types that can have locations that are relative and the result location (which is the resultPath plus the namespace) prepended to them</td> + </tr> + <tr> + <td>struts.convention.redirect.to.slash</td> + <td>true</td> + <td>A boolean parameter that controls whether or not this will handle unknown actions in the same manner as Apache, Tomcat and other web servers. This handling will send back a redirect for URLs such as /foo to /foo/ if there doesnât exist an action that responds to /foo</td> + </tr> + <tr> + <td>struts.convention.classLoader.excludeParent</td> + <td>true</td> + <td>Exclude URLs found by the parent class loader from the list of URLs scanned to find actions (needs to be set to false for JBoss 5)</td> + </tr> + <tr> + <td>struts.convention.action.eagerLoading</td> + <td>false</td> + <td>If set, found action classes will be instantiated by the ObjectFactory to accelerate future use, setting it up can clash with Spring managed beans</td> + </tr> + </tbody> +</table> + + </section> +</article> + + +<footer class="container"> + <div class="col-md-12"> + Copyright © 2000-2016 <a href="http://www.apache.org/">The Apache Software Foundation </a>. + All Rights Reserved. + </div> + <div class="col-md-12"> + Apache Struts, Struts, Apache, the Apache feather logo, and the Apache Struts project logos are + trademarks of The Apache Software Foundation. + </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> + + +<script> +$(function() { + return $("h2, h3, h4, h5, h6").each(function(i, el) { + var $el, id; + $el = $(el); + id = $el.attr('id'); + if (id) { + $el.removeAttr('id'); + return $el.before($("<a />").addClass('anchor').attr('name', id)); + } + }); +}); +</script> + +</body> +</html>
