Morari Bapu greets CM Narendra Modi

Morari Bapu greets CM Narendra Modi

Spring 2.5 Web MVC Quick Overview with example

Spring 2.5 introduced special annotations for configuring web form controllers which helps reduce XML configuration to necessary minimum. In this article I will show how to use most of them to easily map requests to URLs, bind request parameters to method parameters, etc.

Let’s start from explaining the request life-cycle of Spring MVC:

1. The request hits servlet container which determines that the URL is mapped to spring dispatcher servlet

2. The servlet searches for request handler using the mappings configured either through XML or in code using annotations

3. If no handler was found a default handler (if any) is invoked

4. Prior to handler invocation handler interceptors are executed, if any

5. A handler adapter is determined for the handler. Handler adapter “knows” how to process a request using the handler. For example if you use SimpleFormController request parameters will be bound to command object, validators will be invoked and if no errors were detected controller is invoked

6. Controller returns either an ModelAndView object which contains model objects to be rendered and a view name or an instance of View

7. If Controller returns null as ModelAndView it is considered that the handler has performed rendering of request and no further processing is required

8. If Controller returns a ModelAndView with String logical view name a ViewResolver is searched for in the config which attempts to resolve view class. Then the class is instantiated, configured and View.render is invoked

9. If there are any interceptors assigned to Controller in Spring configs they are invoked after request has been rendered.

Now let’s see how controllers are registered and how to map them to request URLs using Spring 2.5.

First and foremost – in Spring 2.5 almost any instance method can be used as a Controller. Consider this simple example:

@Controller
@RequestMapping( { "/home", "/products" })
public class HomePage {

private final SampleDao dao;

@Autowired
public HomePage(SampleDao dao) {
this.dao = dao;
}

@RequestMapping(method = RequestMethod.GET, value = “/home”)
public void memberPage() {
// do smth return nothing – view = home
}

@SuppressWarnings(“unchecked”)
@RequestMapping(method = RequestMethod.GET, value = “/products”)
public String productsPage(@RequestParam(“page”) Integer pageNumber, ModelMap map) {
map.put(“products”, dao.getProducts(pageNumber));
return “products”;
}

}

A HomePage class is now a Conroller, which is mapped to 2 URLs – /home and /products. It’s instantiated by Spring using a one argument constructor. The @Autowired annotation means that we let the framework decide how to configure the controller given the available dependencies. The memberPage() method is here just for the sake of an example – it does nothing and returns nothing. However it is mapped to /home URL. You might ask what view will be rendered when this method is complete? If no String is returned as the view name the URL that this controller is mapped to will be returned by default, in our case the memberPage is mapped to /home, so home will be the view name.

Now let’s look at the second method – it is mapped to /products URL and returns the view name of “products” explicitly. In addition it utilizes Spring 2.5 ability to automatically fill method arguments with data from request – request parameter page will be automatically converted to Integer and used as method argument. In addition we request that a ModelMap be provided so that we can fill request scope with data which will be rendered by products view. Spring 2.5 offers a wide flexibility for request method arguments: instead of a spring specific ModelMap object you can just request a java.util.Map and fill it with model data, you can bind request parameters using the @RequestParam annotation, you can declare a command class argument and it will be filled with data from request parameters automatically. Consider this example of Product submission:

@RequestMapping(method = RequestMethod.POST)
public String addProduct(@ModelAttribute("product") Product product, BindingResult errors,
HttpServletRequest rq) {
// the method will be provided with product command automatically filled from request parameters
// you can use errors object to report any validation errors and forward to form view or redirect to success view
// you can access http request/response directly if you wish
// @ModelAttribute is optional - by using it you can expose the command object as model attribute
}

Now for the configuration part – it has been made utterly simple. We have 2 XML files for the config: applicationContext.xml and dispatcher-servlet.xml. The first file is our business layer configuration and dispatcher-servlet.xml is required to configure the DispatcherServlet which invokes controllers.

applicationContext.xml

<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" xmlns:jee="http://www.springframework.org/schema/jee"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
           http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd
           http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-dependency-check="none" default-lazy-init="false">

  <bean id="tilesConfigurer">
    <property name="definitions">
      <list>
        <value>/WEB-INF/tiles-config/basic-templates.xml</value>
      </list>
    </property>
  </bean>
   
  <bean></bean>

  <bean>
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
    <property name="prefix" value="/WEB-INF/views/tiles/"></property>
    <property name="suffix" value=".jsp"></property>
  </bean>

</beans>

We use Tiles2 to easily compose complex pages out of smaller tiles, a simple DAO layer and a ViewResolver which prepends /WEB-INF/views/tiles and appends .jsp suffix to every view name we provide. After this it instantiates JstlView which knows how to render jsp pages. So the home view name becomes /WEB-INF/views/tiles/home.jsp and products -> /WEB-INF/views/tiles/products.jsp. Easy enough.

dispatcher-servlet.xml

<?xml version=”1.0″?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" xmlns:jee="http://www.springframework.org/schema/jee"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
           http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-2.5.xsd
           http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-dependency-check="none" default-lazy-init="false">

  <context:component-scan base-package="com.anydoby.spingmvc.controllers" />

</beans>

This is it for the dispatcher – Spring will automatically search for controllers in the given package. Provided we use auto-wiring we don’t have to declare anything else. The long criticized bulky XML configurations are now in the past 🙂