| <!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="/highlighter/github-theme.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> |
| </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="/download.cgi">Download</a></li> |
| <li><a href="/releases.html">Releases</a></li> |
| <li><a href="/announce-2021.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> |
| </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="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><a href="/contributors/">Contributors Guide</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="https://cwiki.apache.org/confluence/display/WW/Contributors+Guide">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="#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="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="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.html">ActionMapper</a> interface. |
| Out of the box, Struts 2 uses the <a href="/maven/struts2-core/apidocs/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.html">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.html">RestActionMapper</a>, |
| that provides the RESTful logic that maps a URL to a give action class ( aka <code class="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="highlighter-rouge">!</code> |
| or <code class="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 codebehind plugin so that XML configuration |
| is unnecessary.</p> |
| |
| <p>This mapper supports the following parameters:</p> |
| |
| <ul> |
| <li><code class="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 or not 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="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="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="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="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="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="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="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="highlighter-rouge">GET: /movies</code> => method=<strong>index</strong></li> |
| <li><code class="highlighter-rouge">GET: /movies/Thrillers</code> => method=<strong>show</strong>, id=<strong>Thrillers</strong></li> |
| <li><code class="highlighter-rouge">GET: /movies/Thrillers;edit</code> => method=<strong>edit</strong>, id=<strong>Thrillers</strong></li> |
| <li><code class="highlighter-rouge">GET: /movies/Thrillers/edit</code> => method=<strong>edit</strong>, id=<strong>Thrillers</strong></li> |
| <li><code class="highlighter-rouge">GET: /movies/new</code> => method=<strong>editNew</strong></li> |
| <li><code class="highlighter-rouge">POST: /movies</code> => method=<strong>create</strong></li> |
| <li><code class="highlighter-rouge">PUT: /movies/Thrillers</code> => method=<strong>update</strong>, id=<strong>Thrillers</strong></li> |
| <li><code class="highlighter-rouge">DELETE: /movies/Thrillers</code> => 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="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="highlighter-rouge"><constant/></code> elements in our <code class="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"><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">/></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"><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> |
| <span class="nt"><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">/></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="highlighter-rouge">action</code> extension.</p> |
| |
| <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><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">/></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"><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">/></span> |
| <span class="nt"><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">/></span> |
| <span class="nt"><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">/></span> |
| </code></pre></div></div> |
| |
| <blockquote> |
| <p>Please be aware that you should also use the <code class="highlighter-rouge">PrefixBasedActionProxyFactory</code> factory together with the <code class="highlighter-rouge">PrefixBasedActionMapper</code> |
| mapper to allow the framework to create proper <code class="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"><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> |
| <span class="nt"><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">/></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="highlighter-rouge">execute</code> method as their |
| target method. Here’s a sample controller for a <code class="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="n">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">rest</span><span class="o">.</span><span class="na">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="n">ModelDriven</span><span class="o"><</span><span class="n">Order</span><span class="o">></span> <span class="o">{</span> |
| |
| <span class="kd">private</span> <span class="n">OrderManager</span> <span class="n">orderManager</span><span class="o">;</span> |
| <span class="kd">private</span> <span class="n">String</span> <span class="n">id</span><span class="o">;</span> |
| <span class="kd">private</span> <span class="n">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="n">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="n">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="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="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="highlighter-rouge">show()</code> method returns a <code class="highlighter-rouge">HttpHeaders</code> object and the <code class="highlighter-rouge">update()</code> method returns the expected |
| result code String. The REST Plugin adds support for action methods that return <code class="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="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="../codebehind">Codebehind Plugin</a> to intuitively select the result template to process when this |
| resource is accessed with the <code class="highlighter-rouge">.xhtml</code> extension. In this case, we can provide a customized XHTML view of the resource |
| by creating <code class="highlighter-rouge">/orders-show.jsp</code> and <code class="highlighter-rouge">/orders-update.jsp</code> for the respective methods.</p> |
| |
| <h2 id="advanced-topics">Advanced Topics</h2> |
| |
| <p>The following sections describe some of the non-standard bells and whistles that you might need to utilize for your |
| application’s more non-standard requirements.</p> |
| |
| <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="highlighter-rouge">ContentTypeHandler</code> |
| implementation and define it in your <code class="highlighter-rouge">struts.xml</code>:</p> |
| |
| <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><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">/></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="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"><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">/></span> |
| </code></pre></div></div> |
| |
| <p>Then, tell the REST Plugin to override the handler for the desired extension with yours. In <code class="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"><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">/></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.html">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 © 2000-2018 <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> |
| |
| |
| </body> |
| </html> |