Info |
---|
This plugin is only available with Struts 2.1.1 or later |
Table of Contents | ||||
---|---|---|---|---|
|
Overview
The REST Plugin
Excerpt |
---|
provides high level support for the implementation of RESTful resource based web applications |
...
RESTful URL Mapping Logic
This Restful action mapper enforces Ruby-On-Rails REST-style mappings. If the method is not specified (via '!' or 'method:' 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.
This mapper supports the following parameters:
struts.mapper.idParameterName
- 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.struts.mapper.indexMethodName
- The method name to call for a GET request with no id parameter. Defaults to index.struts.mapper.getMethodName
- The method name to call for a GET request with an id parameter. Defaults to show.struts.mapper.postMethodName
- The method name to call for a POST request with no id parameter. Defaults to create.struts.mapper.putMethodName
- The method name to call for a PUT request with an id parameter. Defaults to update.struts.mapper.deleteMethodName
- The method name to call for a DELETE request with an id parameter. Defaults to destroy.struts.mapper.editMethodName
- The method name to call for a GET request with an id parameter and the edit view specified. Defaults to edit.struts.mapper.newMethodName
- The method name to call for a GET request with no id parameter and the new view specified. Defaults to editNew.
The following URL's will invoke its methods:
GET: /movies
=> method="index"GET: /movies/Thrillers
=> method="show", id="Thrillers"GET: /movies/Thrillers;edit
=> method="edit", id="Thrillers"GET: /movies/Thrillers/edit
=> method="edit", id="Thrillers"GET: /movies/new
=> method="editNew"POST: /movies
=> method="create"PUT: /movies/Thrillers
=> method="update", id="Thrillers"DELETE: /movies/Thrillers
=> method="destroy", id="Thrillers"
Note |
---|
To simulate the HTTP methods PUT and DELETE, since they aren't supported by HTML, the HTTP parameter "_method" will be used. |
Wiki Markup |
{snippet:url=rest-plugin/src/main/java/org/apache/struts2/rest/RestActionMapper.java|id=description|javadoc=true} |
Or, expressed as a table:
...
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:*
- HTML
...
- XML
...
- JSON
There is nothing configure here, just add the conent 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
Code Block |
---|
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
|
...
This section will walk you through a quick demo. Here are the steps in the sequence that we will follow.*
- Setting Up your Project
...
- Configuring your Project
...
- Writing your Controllers
Setting Up
Assuming you have a normal Struts 2 application, all you need to do for this REST demo is to add the following two plugins: *
- Struts 2 Rest Plugin
...
Note, you can download the jars for these plugins from Maven Central
...
Instruct Struts to use the REST action mapper:
Code Block | ||||
---|---|---|---|---|
| ||||
<constant name="struts.mapper.class" value="rest" />
|
...
We're relying on the Convention plugin to find our controllers, so we need to configure the convention plugin a bit:
Code Block | ||||
---|---|---|---|---|
| ||||
<constant name="struts.convention.action.suffix" value="Controller"/>
<constant name="struts.convention.action.mapAllMatches" value="true"/>
<constant name="struts.convention.default.parent.package" value="rest-default"/>
<constant name="struts.convention.package.locators" value="example"/>
|
...
First, you'll need to re-assert the extensions that struts knows about because the rest plugin will have thrown out the default action
extension.
Code Block | ||||
---|---|---|---|---|
| ||||
<constant name="struts.action.extension" value="xhtml,,xml,json,action"/>
|
Next, we will configure the PrefixBasedActionMapper
, 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.
Code Block | ||||
---|---|---|---|---|
| ||||
<constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.PrefixBasedActionMapper" />
<constant name="struts.mapper.prefixMapping" value="/rest:rest,:struts"/>
|
And, again, we're relying on the Convention plugin to find our controllers, so we need to configure the convention plugin a bit:
Code Block | ||||
---|---|---|---|---|
| ||||
<constant name="struts.convention.action.suffix" value="Controller"/>
<constant name="struts.convention.action.mapAllMatches" value="true"/>
<constant name="struts.convention.default.parent.package" value="rest-default"/>
<constant name="struts.convention.package.locators" value="example"/>
|
...
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 execute
method as their target method. Here's a sample controller for a orders 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.
Code Block | ||
---|---|---|
| ||
package org.apache.struts2.rest.example;
public class OrdersController implements ModelDriven<Order> {
private OrderManager orderManager;
private String id;
private Order model;
// Handles /orders/{id} GET requests
public HttpHeaders show() {
model = orderManager.findOrder(id);
return new DefaultHttpHeaders("show")
.withETag(model.getUniqueStamp())
.lastModified(model.getLastModified());
}
// Handles /orders/{id} PUT requests
public String update() {
orderManager.updateOrder(model);
return "update";
}
// getters and setters
}
|
...
If you need to handle extensions that aren't supported by the default handlers, you can create your own ContentTypeHandler
implementation and define it in your struts.xml
:
Code Block | ||
---|---|---|
| ||
<bean name="yaml" type="org.apache.struts2.rest.handler.ContentTypeHandler" class="com.mycompany.MyYamlContentHandler" />
|
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 ContentTypeHandler
and declare with its own alias. For example:
Code Block | ||
---|---|---|
| ||
<bean name="myXml" type="org.apache.struts2.rest.handler.ContentTypeHandler" class="com.mycompany.MyXmlContentHandler" />
|
Then, tell the REST Plugin to override the handler for the desired extension with yours. In struts.properties
, it would look like this:
Code Block |
---|
struts.rest.handlerOverride.xml=myXml
|
...