Spring MVC relies on DispatcherServlet
, which sends requests to controllers that are configurable mapping handlers with view and theme resolution. In Struts, the controller's name is Action
. While Action
instances will be instantiated for every request in Struts 2 to tackle the thread safety issue, Spring MVC creates controllers once, and each controller's instance serves all requests.
To enable Spring integration with Struts 2, Struts provides struts2-spring-plugin
. In Struts 2.1, Struts introduced the convention plugin (struts2-convention-plugin
), which simplified the creation of Action
classes (by annotation) without any configuration file (struts.xml
). The plugin expects a set of naming conventions for the Action
class, package, and view naming that will be explained in this section.
To integrate Struts 2 with Spring, you need to add these dependencies:
<dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.3.20</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-spring-plugin</artifactId> <version>2.3.20</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-convention-plugin</artifactId> <version>2.3.20</version> </dependency>
The struts2-convention-plugin
plugin searches for packages with the strings "struts", "struts2", "action", or "actions", and detects Action
classes either whose names end with Action
(*Action
) or who implement the interface com.opensymphony.xwork2.Action
(or extend its subclass com.opensymphony.xwork2.ActionSupport
). The code for the ViewOrderAction
class is as follows:
package com.springessentialsbook.chapter7.struts; ... @Action("/order") @ResultPath("/WEB-INF/pages") @Result(name = "success", location = "orderEntryForm.jsp") public class ViewOrderAction extends ActionSupport { @Override public String execute() throws Exception { return super.execute(); } }
@Action
maps /order
(in the request URL) to this action class and @ResultPath
specifies where views (JSP files) exist. @Result
specifies navigation to the next page up to the string value of the execute()
method. We created ViewOrderAction
to be able to navigate to a new page and to perform an action (business logic) when submitting a form within a view (orderEntryForm.jsp
):
package com.springessentialsbook.chapter7.struts; …... @Action("/doOrder") @ResultPath("/WEB-INF/pages") @Results({ @Result(name = "success", location = "orderProceed.jsp"), @Result(name = "error", location = "failedOrder.jsp") }) public class DoOrderAction extends ActionSupport { @Autowired private OrderService orderService; private OrderVO order; public void setOrder(OrderVO order) { this.order = order; } public OrderVO getOrder() { return order; } @Override public String execute( ) throws Exception { if ( orderService.isValidOrder(order.getOrderId())) { order.setOrderName(orderService.placeAnOrder(order.getOrderId())); return SUCCESS; } return ERROR; }
Also, here is the JSP code that calls the Action
class. Notice the form's doOrder
action, which calls the DoOrderAction
class (using @Action("doOrder")
).
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <div align="center"> <h1>Spring and Struts Integration</h1> <h2>Place an order</h2> <s:form action="doOrder" method="post"> <s:textfield label="OrderId" name="order.orderId" /> <s:submit value="Order" /> </s:form> </div> </body> </html>
As you can see, we used OrderVO
, whose code is as follows, as the data model in the view. Any changes to this object in the JSP code or action class will be carried forward to the next page:
public class OrderVO { private String orderName; private String orderId; public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; }
In the DoOrderAction
action class, in the method execution, we implement the business logic and return the string value of the method specified in the navigation logic in the presentation layer. Here, the action class either goes to orderProceed.jsp
(if it is a valid order) or failedOrder.jsp
(in the case of a failure). Here is the orderProceed.jsp page, to which a success order will be forwarded:
<%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <div align="center"> <h1>Order confirmation</h1> <s:label label="OrderId" name="order.orderId" />, <s:label label="OrderName" name="order.orderName" /> <br/> has been successfully placed. </div> </body> </html>