* In Struts2 Rest application must contains some naming conventions
struts.xml:
----------
<struts>
<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"/>
</struts>
* Ur class name must start with action name with suffix as Controller (e.g suppose ur action name is orders ur class name must be OrdersController).
*Another role is ur controller class must be contains in the "example" package.(it means which package are mentioned in the constant (e.g <constant name="struts.convention.package.locators" value="example">).
web.xml:
-------
<web-app id="starter" version="2.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/j2ee" xsi:schemalocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Struts 2 Rest Example</display-name>
<filter>
<filter-name>action2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>action2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
index.jsp:
---------
<%
response.sendRedirect("usersviews");
%>
below java class contains in the org.apache.struts2.rest.example packages
Order.java:
----------
package org.apache.struts2.rest.example;
public class Order {
String id;
String clientName;
int amount;
public Order() {}
public Order(String id, String clientName, int amount) {
super();
this.id = id;
this.clientName = clientName;
this.amount = amount;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + amount;
result = prime * result
+ ((clientName == null) ? 0 : clientName.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Order other = (Order) obj;
if (amount != other.amount)
return false;
if (clientName == null) {
if (other.clientName != null)
return false;
} else if (!clientName.equals(other.clientName))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
OrdersController.java:
----------------------
package org.apache.struts2.rest.example;
import java.util.Collection;
import org.apache.struts2.dispatcher.ServletActionRedirectResult;
import org.apache.struts2.rest.DefaultHttpHeaders;
import org.apache.struts2.rest.HttpHeaders;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Namespaces;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.InterceptorRef;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Validateable;
import com.opensymphony.xwork2.ValidationAwareSupport;
@Results({ @Result(name = "success", type = "redirectAction", params = {
"actionName", "orders" }) })
public class OrdersController extends ValidationAwareSupport implements
ModelDriven<Object>, Validateable {
private Order model = new Order();
private String id;
private Collection<Order> list;
private OrdersService ordersService = new OrdersService();
// GET /orders/1
public HttpHeaders show() {
return new DefaultHttpHeaders("show");
}
// GET /orders
public HttpHeaders index() {
list = ordersService.getAll();
return new DefaultHttpHeaders("index").disableCaching();
}
// GET /orders/1/edit
public String edit() {
return "edit";
}
// GET /orders/new
public String editNew() {
model = new Order();
return "editNew";
}
// GET /orders/1/deleteConfirm
public String deleteConfirm() {
return "deleteConfirm";
}
// DELETE /orders/1
public String destroy() {
ordersService.remove(id);
addActionMessage("Order removed successfully");
return "success";
}
// POST /orders
public HttpHeaders create() {
ordersService.save(model);
addActionMessage("New order created successfully");
return new DefaultHttpHeaders("success").setLocationId(model.getId());
}
// PUT /orders/1
public String update() {
ordersService.save(model);
addActionMessage("Order updated successfully");
return "success";
}
public void validate() {
if (model.getClientName() == null
|| model.getClientName().length() == 0) {
addFieldError("clientName", "The client name is empty");
}
}
public void setId(String id) {
if (id != null) {
this.model = ordersService.get(id);
}
this.id = id;
}
public Object getModel() {
return (list != null ? list : model);
}
}
OrdersService.java:
-------------------
package org.apache.struts2.rest.example;
import java.util.*;
public class OrdersService {
private static Map<String,Order> orders = new HashMap<String,Order>();
private static int nextId = 6;
static {
orders.put("3", new Order("3", "Bob", 33));
orders.put("4", new Order("4", "Sarah", 44));
orders.put("5", new Order("5", "Jim", 66));
}
public Order get(String id) {
return orders.get(id);
}
public List<Order> getAll() {
return new ArrayList<Order>(orders.values());
}
public void save(Order order) {
if (order.getId() == null) {
order.setId(String.valueOf(nextId++));
}
orders.put(order.getId(), order);
}
public void remove(String id) {
orders.remove(id);
}
}
jsps:(these jsps contains in the content folder in the webcontent folder)
orders-edit.jsp:
----------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@taglib prefix="s" uri="/struts-tags" %> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Order <s:property value="id" /></title> </head>
<body> <s:form method="post" action="%{#request.contextPath}/orders/%{id}">
<s:hidden name="_method" value="put" />
<table> <s:textfield name="id" label="ID" disabled="true"/>
<s:textfield name="clientName" label="Client"/>
<s:textfield name="amount" label="Amount" />
<tr> <td colspan="2">
<s:submit /> </td> </table> </s:form>
<a href="<%=request.getContextPath() %>/orders">Back to Orders</a> </body> </html>
orders-editNew.jsp:
-------------------
<%@taglib prefix="s" uri="/struts-tags" %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>New Order</title>
</head>
<body>
<s:form method="post" action="%{#request.contextPath}/orders">
<table>
<s:textfield name="clientName" label="Client"/>
<s:textfield name="amount" label="Amount" />
<tr>
<td colspan="2">
<s:submit />
</td>
</table>
</s:form>
<a href="<%=request.getContextPath() %>/orders">Back to Orders</a>
</body>
</html>
orders-index.jsp:
-----------------
<%@taglib prefix="s" uri="/struts-tags" %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Orders</title>
</head>
<body>
<s:actionmessage />
<table>
<tr>
<th>ID</th>
<th>Client</th>
<th>Amount</th>
<th>Actions</th>
</tr>
<s:iterator value="model">
<tr>
<td>${id}</td>
<td>${clientName}</td>
<td>${amount}</td>
<td><a href="orders/${id}">View</a> |
<a href="orders/${id}/edit">Edit</a> |
<a href="orders/${id}/deleteConfirm">Delete</a></td>
</tr>
</s:iterator>
</table>
<a href="orders/new">Create a new order</a>
</body>
</html>
orders-show.jsp:
----------------
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <title>Order ${id}</title> </head>
<body>
<table> <tr> <th>ID</th>
<td>${id}</td>
</tr>
<tr> <th>Client</th>
<td>${clientName}</td>
</tr>
<tr> <th>Amount</th> <td>${amount}</td> </tr>
</table>
<a href="../orders">Back to Orders</a> </body> </html>
orders-deleteConfirm.jsp
------------------------
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Order ${id}</title>
</head>
<body>
<form action="../${id}?_method=DELETE" method="post">
<p>
Are you sure you want to delete order ${id}?
</p>
<div>
<input type="submit" value="Delete" />
<input type="button" value="Cancel" onclick="window.location.href = '../../orders'" />
</div>
</form>
<br />
<a href="../../orders">Back to Orders</a>
</body>
</html>
Note: Here jsp names must be action name-return type <p>
jar files:
-------
commons-beanutils-1.7.0.jar
commons-collections-3.2.jar
commons-fileupload-1.2.1.jar
commons-io-1.3.2.jar
commons-lang-2.3.jar
commons-logging-1.1.jar
ezmorph-1.0.3.jar
freemarker-2.3.13.jar
json-lib-2.1-jdk15.jar
log4j-1.2.16.jar
ognl-2.6.11.jar
struts2-convention-plugin-2.1.6.jar
struts2-core-2.1.6.jar
struts2-rest-plugin-2.1.6.jar
struts2-rest-showcase-2.3.1.1-javadoc.jar
xpp3_min-1.1.3.4.O.jar
xstream-1.2.2.jar
xwork-2.1.2.jar
Hi, Nice post thanks. It would be great if you can explaing how different request uri's are getting mapped to different methods eventhough you have not configured them anywhere. For instance /orders/new maps to editNew(), if i keep a new method how it will be mapped with which uri. I am new to struts and rest, thanks in advance.
ReplyDeleteAwesome, but how to call my web services REST using jQuery JSONP ??? support The REST Plugin call JSONP???
ReplyDeleteDo i need Maven to run this project?
ReplyDeleteyou can download above jars from maven or download manually add to ur build path
DeleteYeah! but do i need maven integration separately coz i have older version of eclipse(Indigo)
Deleteyes
DeleteHTTP Status 404 - There is no Action mapped for namespace / and action name usersviews is showing please help
ReplyDeleteHow Will I get XML response ?? what extra code we need to add for that
ReplyDeleteI am getting HTTP Status 404 - There is no Action mapped for namespace / and action name orders. this error ?? How i can sol
ReplyDeletehi is there any way to convert show() action to POST Http method?
ReplyDelete