blob: d8148915f78ff7c8fd2dbba9602346fdafc2a427 [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>REST 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="/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/plugins/rest/index.md" title="Edit this page on GitHub">Edit on GitHub</a>
<a href="../" title="back to Plugins"><< back to Plugins</a>
<h1 class="no_toc" id="rest-plugin">REST Plugin</h1>
<p>This plugin is only available with Struts 2.1.1 or later.</p>
<ul id="markdown-toc">
<li><a href="#overview" id="markdown-toc-overview">Overview</a> <ul>
<li><a href="#features" id="markdown-toc-features">Features</a></li>
<li><a href="#mapping-rest-urls-to-struts-2-actions" id="markdown-toc-mapping-rest-urls-to-struts-2-actions">Mapping REST URLs to Struts 2 Actions</a></li>
<li><a href="#actions-or-controllers-" id="markdown-toc-actions-or-controllers-">Actions or Controllers ?</a></li>
<li><a href="#restful-url-mapping-logic" id="markdown-toc-restful-url-mapping-logic">RESTful URL Mapping Logic</a></li>
<li><a href="#content-types" id="markdown-toc-content-types">Content Types</a></li>
</ul>
</li>
<li><a href="#usage" id="markdown-toc-usage">Usage</a> <ul>
<li><a href="#setting-up" id="markdown-toc-setting-up">Setting Up</a></li>
<li><a href="#configuration---strutsxml" id="markdown-toc-configuration---strutsxml">Configuration - struts.xml</a></li>
<li><a href="#rest-only-configuration" id="markdown-toc-rest-only-configuration">REST Only Configuration</a></li>
<li><a href="#rest-and-non-restful-urls-together-configuration" id="markdown-toc-rest-and-non-restful-urls-together-configuration">REST and non-RESTful URL’s Together Configuration</a></li>
<li><a href="#write-your-controller-actions" id="markdown-toc-write-your-controller-actions">Write Your Controller Actions</a></li>
</ul>
</li>
<li><a href="#advanced-topics" id="markdown-toc-advanced-topics">Advanced Topics</a> <ul>
<li><a href="#xstream-configuration" id="markdown-toc-xstream-configuration">XStream configuration</a></li>
<li><a href="#custom-contenttypehandlers" id="markdown-toc-custom-contenttypehandlers">Custom ContentTypeHandlers</a></li>
<li><a href="#settings" id="markdown-toc-settings">Settings</a></li>
</ul>
</li>
<li><a href="#resources" id="markdown-toc-resources">Resources</a></li>
<li><a href="#version-history" id="markdown-toc-version-history">Version History</a></li>
</ul>
<h2 id="overview">Overview</h2>
<p>The REST Plugin provides high level support for the implementation of RESTful resource based web applications
<a href="../convention">Convention Plugin</a>.</p>
<p>If you prefer to see a working code example, instead of reading through an explanation, you can download
the <a href="/download.cgi#struts-ga">Struts2 Example Applications</a> and check out the <code class="language-plaintext highlighter-rouge">struts2-rest-showcase</code> application,
a complete WAR file, that demonstrates a simple REST web program.</p>
<h3 id="features">Features</h3>
<ul>
<li>Ruby on Rails REST-style URLs</li>
<li>Zero XML config when used with Convention Plugin</li>
<li>Built-in serialization and deserialization support for XML and JSON</li>
<li>Automatic error handling</li>
<li>Type-safe configuration of the HTTP response</li>
<li>Automatic conditional GET support</li>
</ul>
<h3 id="mapping-rest-urls-to-struts-2-actions">Mapping REST URLs to Struts 2 Actions</h3>
<p>The main functionality of the REST plugin lies in the interpretation of incoming request URL’s according the RESTful
rules. In the Struts 2 framework, this <code class="language-plaintext highlighter-rouge">mapping</code> of request URL’s to Actions is handled by in implementation of
the <a href="/maven/struts2-core/apidocs/org/apache/struts2/dispatcher/mapper/ActionMapper">ActionMapper</a> interface.
Out of the box, Struts 2 uses the <a href="/maven/struts2-core/apidocs/org/apache/struts2/dispatcher/mapper/DefaultActionMapper">DefaultActionMapper</a>
to map URL’s to Actions via the logic you are probably already familiar with.</p>
<h3 id="actions-or-controllers-">Actions or Controllers ?</h3>
<p>Most Struts 2 developers are familiar with the Action. They are the things that get executed by the incoming requests.
In the context of the REST plugin, just to keep you on your toes, we’ll adopt the RESTful lingo and refer to our
Actions as <strong>Controllers</strong>. Don’t be confused; it’s just a name!</p>
<p>The REST plugin provides an alternative implementation, <a href="/maven/struts2-plugins/struts2-rest-plugin/apidocs/org/apache/struts2/rest/RestActionMapper">RestActionMapper</a>,
that provides the RESTful logic that maps a URL to a give action class ( aka <code class="language-plaintext highlighter-rouge">controller</code> in RESTful terms ) and,
more specifically, to the invocation of a method on that controller class. The following section, which comes from
the Javadoc for the class, details this logic.</p>
<h3 id="restful-url-mapping-logic">RESTful URL Mapping Logic</h3>
<p>This Restful action mapper enforces Ruby-On-Rails REST-style mappings. If the method is not specified (via <code class="language-plaintext highlighter-rouge">!</code>
or <code class="language-plaintext highlighter-rouge">method:</code> prefix), the method is “guessed” at using REST-style conventions that examine the URL and the HTTP method.
Special care has been given to ensure this mapper works correctly with the Convention plugin so that XML configuration
is unnecessary.</p>
<p>This mapper supports the following parameters:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">struts.mapper.idParameterName</code> - If set, this value will be the name of the parameter under which the id is stored.
The id will then be removed from the action name. Whether the method is specified, the mapper will try
to truncate the identifier from the url and store it as a parameter.</li>
<li><code class="language-plaintext highlighter-rouge">struts.mapper.indexMethodName</code> - The method name to call for a GET request with no id parameter. Defaults to <strong>index</strong>.</li>
<li><code class="language-plaintext highlighter-rouge">struts.mapper.getMethodName</code> - The method name to call for a GET request with an id parameter. Defaults to <strong>show</strong>.</li>
<li><code class="language-plaintext highlighter-rouge">struts.mapper.postMethodName</code> - The method name to call for a POST request with no id parameter. Defaults to <strong>create</strong>.</li>
<li><code class="language-plaintext highlighter-rouge">struts.mapper.putMethodName</code> - The method name to call for a PUT request with an id parameter. Defaults to <strong>update</strong>.</li>
<li><code class="language-plaintext highlighter-rouge">struts.mapper.deleteMethodName</code> - The method name to call for a DELETE request with an id parameter. Defaults to <strong>destroy</strong>.</li>
<li><code class="language-plaintext highlighter-rouge">struts.mapper.editMethodName</code> - The method name to call for a GET request with an id parameter and the <strong>edit</strong> view specified. Defaults to <strong>edit</strong>.</li>
<li><code class="language-plaintext highlighter-rouge">struts.mapper.newMethodName</code> - The method name to call for a GET request with no id parameter and the <strong>new</strong> view specified. Defaults to <strong>editNew</strong>.</li>
</ul>
<p>The following URL’s will invoke its methods:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">GET: /movies</code> =&gt; method=<strong>index</strong></li>
<li><code class="language-plaintext highlighter-rouge">GET: /movies/Thrillers</code> =&gt; method=<strong>show</strong>, id=<strong>Thrillers</strong></li>
<li><code class="language-plaintext highlighter-rouge">GET: /movies/Thrillers;edit</code> =&gt; method=<strong>edit</strong>, id=<strong>Thrillers</strong></li>
<li><code class="language-plaintext highlighter-rouge">GET: /movies/Thrillers/edit</code> =&gt; method=<strong>edit</strong>, id=<strong>Thrillers</strong></li>
<li><code class="language-plaintext highlighter-rouge">GET: /movies/new</code> =&gt; method=<strong>editNew</strong></li>
<li><code class="language-plaintext highlighter-rouge">POST: /movies</code> =&gt; method=<strong>create</strong></li>
<li><code class="language-plaintext highlighter-rouge">PUT: /movies/Thrillers</code> =&gt; method=<strong>update</strong>, id=<strong>Thrillers</strong></li>
<li><code class="language-plaintext highlighter-rouge">DELETE: /movies/Thrillers</code> =&gt; method=<strong>destroy</strong>, id=<strong>Thrillers</strong></li>
</ul>
<p>To simulate the HTTP methods PUT and DELETE, since they aren’t supported by HTML, the HTTP parameter <code class="language-plaintext highlighter-rouge">_method</code> will be used.</p>
<p>Or, expressed as a table:</p>
<table>
<thead>
<tr>
<th>HTTP method</th>
<th>URI</th>
<th>Class.method</th>
<th>parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td>/movie</td>
<td>Movie.index</td>
<td> </td>
</tr>
<tr>
<td>POST</td>
<td>/movie</td>
<td>Movie.create</td>
<td> </td>
</tr>
<tr>
<td>PUT</td>
<td>/movie/Thrillers</td>
<td>Movie.update</td>
<td>id=”Thrillers”</td>
</tr>
<tr>
<td>DELETE</td>
<td>/movie/Thrillers</td>
<td>Movie.destroy</td>
<td>id=”Thrillers”</td>
</tr>
<tr>
<td>GET</td>
<td>/movie/Thrillers</td>
<td>Movie.show</td>
<td>id=”Thrillers”</td>
</tr>
<tr>
<td>GET</td>
<td>/movie/Thrillers/edit</td>
<td>Movie.edit</td>
<td>id=”Thrillers”</td>
</tr>
<tr>
<td>GET</td>
<td>/movie/new</td>
<td>Movie.editNew</td>
<td> </td>
</tr>
</tbody>
</table>
<h3 id="content-types">Content Types</h3>
<p>In addition to providing mapping of RESTful URL’s to Controller ( Action ) invocations, the REST plugin also provides
the ability to produce multiple representations of the resource data. By default, the plugin can return the resource
in the following content types:</p>
<ul>
<li>HTML</li>
<li>XML</li>
<li>JSON</li>
</ul>
<p>There is nothing configure here, just add the content type extension to your RESTful URL. The framework will take care
of the rest. So, for instance, assuming a Controller called Movies and a movie with the id of superman, the following
URL’s will all hit the</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://my.company.com/myapp/movies/superman
http://my.company.com/myapp/movies/superman.xml
http://my.company.com/myapp/movies/superman.xhtml
http://my.company.com/myapp/movies/superman.json
</code></pre></div></div>
<blockquote>
<p>Note, these content types are supported as incoming data types as well. And, if you need, you can extend
the functionality by writing your own implementations of org.apache.struts2.rest.handler.ContentTypeHandler
and registering them with the system.</p>
</blockquote>
<h2 id="usage">Usage</h2>
<p>This section will walk you through a quick demo. Here are the steps in the sequence that we will follow.</p>
<ul>
<li>Setting Up your Project</li>
<li>Configuring your Project</li>
<li>Writing your Controllers</li>
</ul>
<h3 id="setting-up">Setting Up</h3>
<p>Assuming you have a normal Struts 2 application, all you need to do for this REST demo is to add the following two plugins:</p>
<ul>
<li>Struts 2 Rest Plugin</li>
<li><a href="../convention">Struts 2 Convention Plugin</a></li>
</ul>
<blockquote>
<p>Note, you can download the jars for these plugins from <a href="http://search.maven.org/#search%7Cga%7C1%7Cstruts2-convention-plugin">Maven Central</a></p>
</blockquote>
<h3 id="configuration---strutsxml">Configuration - struts.xml</h3>
<p>Just dropping the plugin’s into your application may not produce exactly the desired effect. There are a couple of considerations.
The first consideration is whether you want to have any non-RESTful URL’s coexisting with your RESTful URL’s. We’ll
show two configurations. The first assumes all you want to do is REST. The second assumes you want to keep other
non-RESTful URL’s alive in the same Struts 2 application.</p>
<p>As with all configuration of Struts 2, we prefer using <code class="language-plaintext highlighter-rouge">&lt;constant/&gt;</code> elements in our <code class="language-plaintext highlighter-rouge">struts.xml</code>.</p>
<h3 id="rest-only-configuration">REST Only Configuration</h3>
<p>Instruct Struts to use the REST action mapper:</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.mapper.class"</span> <span class="na">value=</span><span class="s">"rest"</span> <span class="nt">/&gt;</span>
</code></pre></div></div>
<p>At this point, the REST mapper has replaced the DefaultActionMapper so all incoming URL’s will be interpreted as RESTful URL’s.</p>
<p>We’re relying on the Convention plugin to find our controllers, so we need to configure the convention plugin a bit:</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.convention.action.suffix"</span> <span class="na">value=</span><span class="s">"Controller"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;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">/&gt;</span>
<span class="nt">&lt;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">/&gt;</span>
<span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.convention.package.locators"</span> <span class="na">value=</span><span class="s">"example"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<blockquote>
<p>Note, you don’t have to use the Convention plugin just to use the REST plugin. The actions of your RESTful application
can be defined in XML just as easily as by convention. The REST mapper doesn’t care how the application came to know
about your actions when it maps a URL to an invocation of one of it’s methods.</p>
</blockquote>
<h3 id="rest-and-non-restful-urls-together-configuration">REST and non-RESTful URL’s Together Configuration</h3>
<p>If you want to keep using some non-RESTful URL’s alongside your REST stuff, then you’ll have to provide
for a configuration that utilizes to mappers.</p>
<p>Plugins contain their own configuration. If you look in the Rest plugin jar, you’ll see the struts-plugin.xml and in that
you’ll see some configuration settings made by the plugin. Often, the plugin just sets things the way it wants them.
You may frequently need to override those settings in your own struts.xml.</p>
<p>First, you’ll need to re-assert the extensions that struts knows about because the rest plugin will have thrown out
the default <code class="language-plaintext highlighter-rouge">action</code> extension.</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.action.extension"</span> <span class="na">value=</span><span class="s">"xhtml,,xml,json,action"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<p>Next, we will configure the <a href="../../core-developers/action-mapper.html#prefixbasedactionmapper">PrefixBasedActionMapper</a>,
which is part of the core Struts 2 distribution, to have some URL’s routed to the Rest mapper and others to the default mapper.</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.mapper.class"</span> <span class="na">value=</span><span class="s">"org.apache.struts2.dispatcher.mapper.PrefixBasedActionMapper"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.mapper.prefixMapping"</span> <span class="na">value=</span><span class="s">"/rest:rest,:struts"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.actionProxyFactory"</span> <span class="na">value=</span><span class="s">"prefix"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<blockquote>
<p>Please be aware that you should also use the <code class="language-plaintext highlighter-rouge">PrefixBasedActionProxyFactory</code> factory together with the <code class="language-plaintext highlighter-rouge">PrefixBasedActionMapper</code>
mapper to allow the framework to create proper <code class="language-plaintext highlighter-rouge">ActionProxy</code>s per given prefix.</p>
</blockquote>
<p>And, again, we’re relying on the Convention plugin to find our controllers, so we need to configure the convention plugin a bit:</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.convention.action.suffix"</span> <span class="na">value=</span><span class="s">"Controller"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;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">/&gt;</span>
<span class="nt">&lt;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">/&gt;</span>
<span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.convention.package.locators"</span> <span class="na">value=</span><span class="s">"example"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<h3 id="write-your-controller-actions">Write Your Controller Actions</h3>
<p>Once everything is configured, you need to create the controllers. Controllers are simply actions created with
the purpose of handling requests for a give RESTful resource. As we saw in the mapping logic above, various REST URL’s
will hit different methods on the controller. Traditionally, normal Struts 2 actions expose the <code class="language-plaintext highlighter-rouge">execute</code> method as their
target method. Here’s a sample controller for a <code class="language-plaintext highlighter-rouge">orders</code> resource. Note, this sample doesn’t implement all of the methods
that can be hit via the RESTful action mapper’s interpretation of URL’s.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">org.apache.struts2.rest.example</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">OrdersController</span> <span class="kd">implements</span> <span class="nc">ModelDriven</span><span class="o">&lt;</span><span class="nc">Order</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="kd">private</span> <span class="nc">OrderManager</span> <span class="n">orderManager</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">String</span> <span class="n">id</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">Order</span> <span class="n">model</span><span class="o">;</span>
<span class="c1">// Handles /orders/{id} GET requests</span>
<span class="kd">public</span> <span class="nc">HttpHeaders</span> <span class="nf">show</span><span class="o">()</span> <span class="o">{</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">orderManager</span><span class="o">.</span><span class="na">findOrder</span><span class="o">(</span><span class="n">id</span><span class="o">);</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">DefaultHttpHeaders</span><span class="o">(</span><span class="s">"show"</span><span class="o">)</span>
<span class="o">.</span><span class="na">withETag</span><span class="o">(</span><span class="n">model</span><span class="o">.</span><span class="na">getUniqueStamp</span><span class="o">())</span>
<span class="o">.</span><span class="na">lastModified</span><span class="o">(</span><span class="n">model</span><span class="o">.</span><span class="na">getLastModified</span><span class="o">());</span>
<span class="o">}</span>
<span class="c1">// Handles /orders/{id} PUT requests</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">update</span><span class="o">()</span> <span class="o">{</span>
<span class="n">orderManager</span><span class="o">.</span><span class="na">updateOrder</span><span class="o">(</span><span class="n">model</span><span class="o">);</span>
<span class="k">return</span> <span class="s">"update"</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// getters and setters</span>
<span class="o">}</span>
</code></pre></div></div>
<p>In this example, the <code class="language-plaintext highlighter-rouge">ModelDriven</code> interface is used to ensure that only my model, the Order object in this case, is
returned to the client, otherwise, the whole <code class="language-plaintext highlighter-rouge">OrdersController</code> object would be serialized.</p>
<p>Where’s ActionSupport? Normally, you extend ActionSupport when writing Struts 2 actions. In these case, our controller
doesn’t do that. Why, you ask? ActionSupport provides a bunch of important functionality to our actions, including support
for i18n and validation. All of this functionality, in the RESTful case, is provided by the default interceptor stack
defined in the REST plugin’s struts-plugin.xml file. Unless you willfully break your controller’s membership
in the rest-default package in which that stack is defined, then you’ll get all that functionality you are used
to inheriting from ActionSupport.</p>
<p>You may wonder why the <code class="language-plaintext highlighter-rouge">show()</code> method returns a <code class="language-plaintext highlighter-rouge">HttpHeaders</code> object and the <code class="language-plaintext highlighter-rouge">update()</code> method returns the expected
result code String. The REST Plugin adds support for action methods that return <code class="language-plaintext highlighter-rouge">HttpHeaders</code> objects as a way for
the action to have more control over the response. In this example, we wanted to ensure the response included the ETag
header and a last modified date so that the information will be cached properly by the client. The <code class="language-plaintext highlighter-rouge">HttpHeaders</code> object
is a convenient way to control the response in a type-safe way.</p>
<p>Also, notice we aren’t returning the usual “success” result code in either method. This allows us to use the special
features of the <a href="../convention">Conventio Plugin</a> to intuitively select the result template to process when this
resource is accessed with the <code class="language-plaintext highlighter-rouge">.xhtml</code> extension. In this case, we can provide a customized XHTML view of the resource
by creating <code class="language-plaintext highlighter-rouge">/orders-show.jsp</code> and <code class="language-plaintext highlighter-rouge">/orders-update.jsp</code> for the respective methods.</p>
<h2 id="advanced-topics">Advanced Topics</h2>
<p>The following sections describe some non-standard bells and whistles that you might need to utilize for your
application’s more non-standard requirements.</p>
<h3 id="xstream-configuration">XStream configuration</h3>
<p>Since Struts 6.1.0 you can customise XStream handler by implementing a few interfaces:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">XStreamAllowedClasses</code> - to control which classes can be accessed by the XStream</li>
<li><code class="language-plaintext highlighter-rouge">XStreamAllowedClassNames</code> - similar to the above but you can specify class names</li>
<li><code class="language-plaintext highlighter-rouge">XStreamPermissionProvider</code> - you can define a custom set of <code class="language-plaintext highlighter-rouge">TypePermission</code>s used by XStream</li>
<li><code class="language-plaintext highlighter-rouge">XStreamProvider</code> - you can create your own instance of <code class="language-plaintext highlighter-rouge">XStream</code> which will be used to serialise/deserialize objects</li>
</ul>
<p>These interfaces need to be implemented by an action:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">SimpleAction</span> <span class="kd">extends</span> <span class="nc">ActionSupport</span> <span class="kd">implements</span> <span class="nc">XStreamProvider</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="nc">XStream</span> <span class="nf">createXStream</span><span class="o">()</span> <span class="o">{</span>
<span class="nc">XStream</span> <span class="n">stream</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">XStream</span><span class="o">(</span><span class="k">new</span> <span class="nc">StaxDriver</span><span class="o">());</span>
<span class="n">stream</span><span class="o">.</span><span class="na">alias</span><span class="o">(</span><span class="s">"parents"</span><span class="o">,</span> <span class="nc">ArrayList</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">stream</span><span class="o">.</span><span class="na">alias</span><span class="o">(</span><span class="s">"data"</span><span class="o">,</span> <span class="nc">SimpleBean</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="k">return</span> <span class="n">stream</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h3 id="custom-contenttypehandlers">Custom ContentTypeHandlers</h3>
<p>If you need to handle extensions that aren’t supported by the default handlers, you can create your own <code class="language-plaintext highlighter-rouge">ContentTypeHandler</code>
implementation and define it in your <code class="language-plaintext highlighter-rouge">struts.xml</code>:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;bean</span> <span class="na">name=</span><span class="s">"yaml"</span> <span class="na">type=</span><span class="s">"org.apache.struts2.rest.handler.ContentTypeHandler"</span> <span class="na">class=</span><span class="s">"com.mycompany.MyYamlContentHandler"</span> <span class="nt">/&gt;</span>
</code></pre></div></div>
<p>If the built-in content type handlers don’t do what you need, you can override the handling of any extension by providing
an alternate handler. First, define your own <code class="language-plaintext highlighter-rouge">ContentTypeHandler</code> and declare with its own alias. For example:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;bean</span> <span class="na">name=</span><span class="s">"myXml"</span> <span class="na">type=</span><span class="s">"org.apache.struts2.rest.handler.ContentTypeHandler"</span> <span class="na">class=</span><span class="s">"com.mycompany.MyXmlContentHandler"</span> <span class="nt">/&gt;</span>
</code></pre></div></div>
<p>Then, tell the REST Plugin to override the handler for the desired extension with yours. In <code class="language-plaintext highlighter-rouge">struts.properties</code>, it would
look like this:</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.rest.handlerOverride.xml"</span> <span class="na">value=</span><span class="s">"myXml"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<h3 id="settings">Settings</h3>
<p>The following settings can be customized. See the <a href="/core-developers/configuration-files">developer guide</a>.
For more configuration options see the <a href="../convention">Convention Plugin Documentation</a></p>
<table>
<thead>
<tr>
<th>Setting</th>
<th>Description</th>
<th>Default</th>
<th>Possible Values</th>
</tr>
</thead>
<tbody>
<tr>
<td>struts.rest.handlerOverride.EXTENSION</td>
<td>The alias for the ContentTypeHandler implementation that handles the EXTENSION value</td>
<td>N/A</td>
<td>Any declared alias for a ContentTypeHandler implementation</td>
</tr>
<tr>
<td>struts.rest.defaultExtension</td>
<td>The default extension to use when none is explicitly specified in the request</td>
<td>xhtml</td>
<td>Any extension</td>
</tr>
<tr>
<td>struts.rest.validationFailureStatusCode</td>
<td>The HTTP status code to return on validation failure</td>
<td>400</td>
<td>Any HTTP status code as an integer</td>
</tr>
<tr>
<td>struts.rest.namespace</td>
<td>Optional parameter to specify namespace for REST services</td>
<td>/</td>
<td>eg. /rest</td>
</tr>
<tr>
<td>struts.rest.content.restrictToGET</td>
<td>Optional parameter, if set to true blocks returning content from any other methods than GET, if set to false, the content can be returned for any kind of method</td>
<td>true</td>
<td>eg. put struts.rest.content.restrictToGET = false in struts.properties</td>
</tr>
</tbody>
</table>
<h2 id="resources">Resources</h2>
<ul>
<li><a href="http://www.b-simple.de/documents">http://www.b-simple.de/documents</a> - Short RESTful Rails tutorial (PDF, multiple languages)</li>
<li><a href="http://www.amazon.com/RESTful-Web-Services-Leonard-Richardson/dp/0596529260">RESTful Web Services</a> - Highly recommend book from O’Reilly</li>
<li><a href="http://raibledesigns.com/rd/entry/go_light_with_apache_struts">Go Light with Apache Struts 2 and REST</a> - Presentation by Don Brown at ApacheCon US 2008</li>
</ul>
<h2 id="version-history">Version History</h2>
<p>From Struts 2.1.1+</p>
</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>