A must-have feature for modern Java web frameworks is a simple mechanism for integrating with the business tier. Top of the list here is integration with the Spring Framework.
Strecks allows for clean and elegant integration with Spring in three ways.
To enable Spring bean injection, two things need to be in place. You need one or more Spring application context XML files, which contains your Spring bean definitions, and you need an entry in WEB-INF/web.xml. The context XML files will be present in any Spring application; you can consult the Spring documentation for more details. The web.xml requires an entry similar to the following. Note that entries similar to these are required in any Spring web application, and not just ones involving Strecks.
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-context.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
The contextConfigLocation
parameter simply denotes where the Spring configuration files are located.
The ContextLoaderListener
is used to load the Spring application context from this location.
Any bean referenced in the Spring configuration file can be injected into the action bean using the
@InjectSpringBean
annotation. For example,
if spring-context.xml contains a bean named serviceBean
, this
bean can be injected into the action bean using code such as the following.
private Service serviceBean; @InjectSpringBean(name = "serviceBean") public void setServiceBean(Service serviceBean) { this.serviceBean = serviceBean; } public void execute() { //call serviceBean methods and do presentation logic }
Strecks includes a very simple mechanism to allow an action bean to be defined as a Spring bean. This could be particularly useful, for example, if you wish to add Spring's Aspect Oriented Programming capabilities to your action beans. It also allows you to resolve any Spring bean dependencies in your action bean class using Spring's Inversion of Control (IOC) container.
Assuming you already have an action bean named myActionBean
configured as a Spring
bean in your spring XML configuration file, all that is required to expose this as
a Strecks action bean is a @SpringBean
annotation to your action bean class declaration.
The example below shows how this could be done.
@Controller(name = BasicController.class) @SpringBean(name = "springActionBean") public class SpringControlledAction implements BasicAction { private String message; private SpringService springService; public String execute() { int count = springService.getCount(); message = "Executed Spring controlled action, count result obtained: " + count; return "success"; } public String getMessage() { return message; } //note no @InjectSpringBean annotation required public void setSpringService(SpringService service) { this.springService = service; } }
Note that the class SpringControlledAction
will still need to be registered
in struts-config.xml in the same way as any other Struts action or Strecks action
bean.
One of the most powerful features of Spring MVC is its support for alternative view technologies. Streck's pluggable view rendering allows you to seamlessly tap into this power. Use of Spring view rendering can be useful in a number of situations:
Enabling Spring view rendering is achieved through the use of the @SpringView
annotation.
To show how the @SpringView
annotation can be used, we'll begin with a Struts-based
view rendering example, then modify this to achieve the same result using Spring
MVC view rendering in a few different ways.
In the navigation section, we described the use of
the @NavigateForward
annotation. In the example below, the @NavigateForward
denotes
the method whose return type is used to look up the ActionForward
corresponding to the
target JSP.
@Controller(name = NavigableController.class) public class ExampleNavigableAction implements NavigableAction { public void execute() { //implementation omitted } @NavigateForward public String getResult() { return "success"; } }
Using an entry in struts-config.xml, the result success is mapped to the JSP message.jsp, so that when action execution is complete, control will be forwarded to message.jsp.
The first example shows the use of @SpringView
with the view supplied
programmatically.
@Controller(name = NavigableController.class) public class SpringViewAction implements NavigableAction { private String message; public void execute() { //implementation omitted } @SpringView() public ModelAndView getResult() { JstlView view = new JstlView(); view.setUrl("/message.jsp"); return new ModelAndView(view); } }
Note that this example, no views or view resolver entries are required in the Spring XML configuration file. In fact, we don't even need a Spring configuration file. We are simply using the Spring API to enable forwarding to message.jsp.
While the example above clearly offers little additional benefit, we'd get much more
out of this mechanism if our purpose was to enable view rendering using one of the
alternative views, such as an AbstractPdfView
or AbstractExcelView
subclass.
Another thing to note: the method annotated with @SpringView
must always return
ModelAndView
.
We can get a similar result to our Struts-based example by the @SpringView
annotation to enable obtaining a named Spring view. The action bean code in
this case will look as follows.
public class SpringNamedViewAction implements NavigableAction { private String message; public void execute() { //omitted } /** * Uses looks for view named "messageView" in application context */ @SpringView() public ModelAndView getResult() { return new ModelAndView("messageView"); } }
The only difference with the previous example is that instead of returning a ModelAndView
with a programmatically created View
instance, we reference a named view. Of course, this
view needs to be defined somewhere, and that place is in the Spring configuration file
which is used to build your application's ApplicationContext
. An entry such as the
following would be suitable.
<bean id = "messageView" class = "org.springframework.web.servlet.view.JstlView"> <property name = "url" value = "/message.jsp"/> </bean>
Conceptually, the usage here similar to the use of the success
String
to obtain an ActionForward
,
as in our first example. The scheme offers some flexibility
while remaining simple. The problem is that we need a bean entry for each named Spring
view, which for a large application could result in a lot of XML configuration.
Also, in this example at least, we are no better off than using the Struts-based
ActionMapping
view resolution mechanism.
We can add an additional level of indirection and flexibility by using a Spring
ViewResolver
. The purpose of a
ViewResolver
is to dynamically find views based
on some contextual information. To enable finding views via a ViewResolver
,
our example would change to the following.
public class SpringViewResolverAction implements NavigableAction { public void execute() { //implementation omitted } /** * Uses looks for view named "message" using * resolver "viewResolver" obtained from application context */ @SpringView(resolver = "viewResolver") public ModelAndView getResult() { return new ModelAndView("message"); } }
In this case, there is still a named view. Instead of looking it up directly by name in
from the Spring ApplicationContext
, we use a ViewResolver
to find the view.
Each ViewResolver
implementation will use a different
strategy for finding or creating a view based on the view name
and other contextual information. One commonly used
ViewResolver
is the InternalResourceViewResolver
,
which supports localized views. A suitable Spring configuration bean entry to go with
our SpringViewResolverAction
action is shown below.
<bean id = "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name = "viewClass" value = "org.springframework.web.servlet.view.JstlView"/> <property name = "prefix" value = "/"/> <property name = "suffix" value = ".jsp"/> </bean>
The InternalResourceViewResolver
maps the view name to
a localized version of a resource with the same
name, allowing a prefix and suffix to be specified for extra flexibility.
The real power in integrating Strecks with Spring MVC view rendering
becomes evident when we want to use alternative view technologies.
In the next example, we show how Excel-based view generation can be
enabled in a Strecks action bean. The example uses a subclass of
AbstractExcelView
, which relies on the Apache Jakarta POI library.
@Controller(name = NavigableController.class) public class SpringExcelViewAction implements NavigableAction { public void execute() { //implementation omitted } @SpringView() public ModelAndView getResult() { View view = new AbstractExcelView() { protected void buildExcelDocument(Map model, HSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { HSSFSheet sheet = workbook.createSheet("Spring Excel View"); sheet.setDefaultColumnWidth((short) 12); // Write a text at A1. HSSFCell cell = getCell(sheet, 0, 0); setText(cell, "Spring Excel View Via Strecks"); // Write the current date at A2. HSSFCellStyle dateStyle = workbook.createCellStyle(); dateStyle.setDataFormat( HSSFDataFormat.getBuiltinFormat("m/d/yy")); cell = getCell(sheet, 1, 0); cell.setCellValue(new Date()); cell.setCellStyle(dateStyle); } }; return new ModelAndView(view); } }
In this example, we are programmatically creating a our View
object. Improvements
to this example would involve registering our implementation as a named view or obtaining
it via a ViewResolver
, as we did in previous examples.
However, it does demonstrate the basic practicalities involved in using Spring MVC
view generation. Applying the same techniques for other view types would be no more difficult.