Spring Annotations and Forms | PermGen error
Home > Spring Framework > Spring Annotations and Forms

Spring Annotations and Forms

November 6th, 2009 admin Leave a comment Go to comments

Since the release of Spring 2.5, the framework has allowed for MVC annotations for mapping your URL’s to your various controllers.

This tutorial gives an example of how the annotations can be used within your application.

Grab the Spring Framework

First of all grab the latest stable release of Spring (version 2.5.6)

I’m going to assume you’re comfortable in creating Web Application Java projects using Eclipse so I’ll ignore this step.

Configuring your build path

We simply need to add the following JAR’s to our build path. Add the Jars into your lib directory.

commons-beanutils.jar
commons-collections.jar
commons-digester.jar
jstl.jar
spring.jar
spring-core.jar
spring-webmvc.jar
standard.jar
tiles-api-2.0.6.jar
tiles-core-2.0.6.jar
tiles-jsp-2.0.6.jar

Note: This is the minimum amount of required libs for this example and all Jars can be taken from the Spring Framework download lib and dist directories.

JSP Form page creation

If you haven’t already create a new folder in your project called pages and add a file in it called form.jsp (Of course depending on configuration you can name the files however you like.

Add the following to the form.jsp file. This creates the simple JSP page that is our form

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
 
<form:form method="post" name="nameForm" id="nameForm" commandName="nameCommand">
	<table>
		<tr>
			<td>Name:</td>
			<td><form:input path="name" size="40" /></td>
		</tr>
		<tr>
			<td>&nbsp;</td>
			<td><input type="submit" value="Send my name" /></td>
		</tr>
	</table>
</form:form>

In the JSP you can see I’m using the Spring frameworks form tag library. Also note we specify and commandName, if you haven’t already encountered this – that is important. We specify the nameCommand and we shall be using that later.

Now add another JSP called formResult.jsp. This is the JSP that gets displayed when the form has been submitted. Add the following code:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 
<p>${formResult}</p>

Configuring the web.xml

Next we can move onto the web.xml and what setup requirements we need to make our Web application work with Spring MVC

If you haven’t already create a web.xml file in your WEB-INF folder

Add the following into your web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
 
<web-app version="2.4"
		 xmlns="http://java.sun.com/xml/ns/j2ee"
		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 
	<display-name>Spring Annotations Example</display-name>
 
 
	<servlet>
		<servlet-name>annotations</servlet-name>
                <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                <load-on-startup>1</load-on-startup>
       </servlet>
 
	<servlet-mapping>
    	        <servlet-name>annotations</servlet-name>
    	         <url-pattern>*.page</url-pattern>
        </servlet-mapping>
 
        <listener>
  	         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
 
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
</web-app>

To explain we’re going to create a web application under the context name annotations and then we’re mapping the Spring DispatcherServlet to it and Spring will handle any URL’s ending in .page

Again depending on configuration this doesn’t have to be .page it can be something of your choice.

Tiles configuration

For this example I am using Tiles for the ‘View’ part of our MVC

Under the WEB-INF folder create a new directory called ’tiles-defs’ and add a file in it called ‘templates.xml’.

Add the following to your templates.xml file

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
 
<tiles-definitions>
 
	<definition name="form.view" template="/pages/form.jsp">
	</definition>
 
        <definition name="formResult.view" template="/pages/formResult.jsp">
	</definition>
 
 
</tiles-definitions>

Very basically we are defining a new View called form.view that relates to our previously created form.jsp page and formResult.view that maps to the formResult.jsp

Spring MVC Servlet.xml

Now we can configure the Spring MVC servlet.xml file. Create a new file called annotations-servlet.xml and place it in the WEB-INF directory. (The same place as the web.xml.

Note: we call the file annotations-servlet.xml because of the servlet mapping named using in our web.xml – you can of course change this.

Add the following to the file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context.xsd">
 
 
 
	<context:component-scan base-package="com.annotations.controller" />
        <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
	<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
 
	<!-- Enables plain Controllers -->
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
 
        <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
	    <property name="definitions">
                <list>
		    <value>/WEB-INF/tiles-defs/templates.xml</value>
		</list>
	    </property>
	</bean>
 
	<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
	</bean>                
</beans>

This file sets up a few things – firstly you’ll notice that we use the context-component scan – this means that Spring will look through the package we specify for any annotations which means when we annotate our URL’s they will work. In this example I scan the com.annotations.controller package. We also setup the Spring annotation handlers.

The items after that basically configure our view resolver which in our case is Tiles and we specify the location of the templates.xml file we created in the previous steps

A bit of business logic

To make the tutorial a bit more relevant I’m going to include Springs applicationContext.xml file which would generally include a web applications database/business logic beans.

In the WEB-INF/src folder create a new file called ‘applicationContext.xml’

Add the following:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
	<bean id="businessBean" class="com.annotations.business.BusinessLogicBeanImpl">
	</bean>
</beans>

Just define one business logic bean com.annotations.business.BusinessLogicBeanImpl which will code next.

The business logic bean

Go ahead and create and create a new java package under the path com.annotations.business

Add a new <<Interface>> into this class called BusinessLogicBean and add the following code:

package com.annotations.business;
 
/**
 * @author Eggsy - eggsy_at_eggsylife.co.uk
 */
public interface BusinessLogicBean
{
	public String processName(String name);
}

We’re defining a single business logic method that will handle the name the user has entered and do something with it

Create a new class in the same package called BusinessLogicBeanImpl and make it implement the BusinessLogicBean interface.

package com.annotations.business;
 
/**
 * @author Eggsy - eggsy_at_eggsylife.co.uk
 */
public class BusinessLogicBeanImpl implements BusinessLogicBean
{
	/* (non-Javadoc)
	 * @see com.annotations.business.BusinessLogicBean#processName(java.lang.String)
	 */
	public String processName(String name)
	{
		if( name.equals("admin"))
		{
			return "Hello admin welcome";
		}
		else
		{
			return "Hey you're not admin but Hi to " + name + " anyway!!";
		}
	}
}

I’ve defined a pretty useless business method but feel free to change this ;)

The Form command Object

On the form JSP file in the form we mentioned an attribute called commandName and we gave it a value of nameCommand. This basically tells Spring what object to use behind the form. We can now go ahead and create that object.

Create a new package called com.annotations.command and place a new class in it called NameCommand. Add the following code:

package com.annotations.command;
 
/**
 * @author Eggsy - eggsy_at_eggsylife.co.uk
 */
public class NameCommand
{
	private String name = null;
 
	/**
	 * @return the name
	 */
	public String getName()
	{
		return name;
	}
 
	/**
	 * @param name the name to set
	 */
	public void setName(String name)
	{
		this.name = name;
	}
}

Notice we have one class variable called name this maps to the name input field on our form

Finally…the annotated controller

If you remember in the servlet.xml file we stated that we would scan the com.annotations.controller package. Go ahead and create this package.

In the package create a new class called NameFormController

Just before the class defintion add the following annotations:

@Controller
@RequestMapping("/processName.page")

The annotations mean that this controller will map any URL’s matching processName.page

Next within the class add a variable that is our BusinessLogicBean. Add the lines:

@Autowired
protected BusinessLogicBean businessBean = null;

This introduces another annotation the @Autowired, this means Spring will automatically inject this object for us. Note the bean is given the name businessBean this identically matches our definition in the applicationContext file

Next we setup the form backing object which if you remember was the NameCommand this is done with a few more annotations like so:

@ModelAttribute("nameCommand")
public NameCommand getProductCommand()
{
    NameCommand nameCommand = new NameCommand();
    return nameCommand;
}

Again notice that tie we use an annotation of @ModelAttribute and give it a name of nameCommand which is used by the form on our JSP.

Next up is to add the annotated get method. This is the method that renders the view which should display the form.

@SuppressWarnings("unchecked")
@RequestMapping(method = RequestMethod.GET)
protected String showNameForm(ModelMap model) throws Exception
{	
	return "form.view";
}

Important to notice here is that we return “form.view” which matches the tiles definition we created earlier. Also note that we use the @RequestMapping method and we map this to the GET which is called to display the form

Finally we can go ahead and write the method that handles the form submit. Add the following to the class:

@RequestMapping(method = RequestMethod.POST)
protected String onSubmit( @ModelAttribute("nameCommand") NameCommand nameCommand,  ModelMap model )
{
	String formResult = businessBean.processName(nameCommand.getName());
	model.addAttribute("formResult", formResult);
	return "formResult.view";
}

This method is slightly more complex. As before we use the @RequestMapping annotation but this time we map it to the POST. In the parameters however we use the @ModelAttribute annotation again but this time it specifies that from the form being submitted we will have a populated nameCommand object. Using our business logic bean we process the name entered.

If you remember the formResult.jsp we simply output an item called $formResult, using our model object we add the formResult to the model so that the JSP is able to access this and then we simply return the formResult tiles view

The whole class should look like this:

package com.annotations.controller;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
import com.annotations.business.BusinessLogicBean;
import com.annotations.command.NameCommand;
 
 
/**
 * @author Eggsy - eggsy_at_eggsylife.co.uk
 */
@Controller
@RequestMapping("/processName.page")
public class NameFormController
{
    @Autowired
    protected BusinessLogicBean businessBean = null;
 
    @ModelAttribute("nameCommand")
    public NameCommand getProductCommand()
    {
        NameCommand nameCommand = new NameCommand();
	return nameCommand;
    }
 
    @SuppressWarnings("unchecked")
    @RequestMapping(method = RequestMethod.GET)
    protected String showNameForm(ModelMap model) throws Exception
    {	
        return "form.view";
    }
 
    @RequestMapping(method = RequestMethod.POST)
    protected String onSubmit( @ModelAttribute("nameCommand") NameCommand nameCommand,  ModelMap model )
    {
        String formResult = businessBean.processName(nameCommand.getName());
	model.addAttribute("formResult", formResult);
	return "formResult.view";
    }
}

Testing…

Phew that should be it – assuming you have setup your application the same as mine and have configured your server environment such as Tomcat if you visit http://localhost:8080/annotations/processName.page you should see the form. Try submitting the form and you should see the response as dictated by our business logic.

  1. admin
    February 21st, 2010 at 15:57 | #1

    Hi there,

    The class that the method belongs to should have two annotations above it. Firstly the @Controller annotation which identifies it to Spring as controller then below that there should be the @RequestMapping annotation which should define the path. Any time a GET request is made to that path the method will be hit.

    See the line:

    @Controller
    @RequestMapping("/processName.page")
    public class NameFormController

    Sp the path is the processName.page path.

    Hope this helps

  2. hendra
    February 21st, 2010 at 04:22 | #2
    @SuppressWarnings("unchecked")
    @RequestMapping(method = RequestMethod.GET)
    protected String showNameForm(ModelMap model) throws Exception
    {	
        return "form.view";
    }

    when the code will be executed ?, i mean there is no request mapping “path” on it. and who will be invoce it.

  3. admin
    January 11th, 2010 at 13:10 | #3

    Hi Adrian,

    Are you able to show me the controller? And then your templates.xml file?

    If those two tie up check that you have the following in your servlet.xml file:

    <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
        <property name="definitions">
            <list>
                 <value>/WEB-INF/tiles-defs/templates.xml</value>
            </list>
        </property>
    </bean>
     
    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
    </bean>

    The templates.xml file location will of course be specific to your project.

    If you would rather email me to sample code please feel free to drop me a message at:

    eggsy _at_ eggsylife.co.uk

  4. Adrian
    January 11th, 2010 at 13:02 | #4

    Hi, thanks for the article.
    I’m setting up an application that has all the same components: tiles, spring annotations. I’m using spring 3.0 with Tiles 2.1.4.
    However, I’m having a problem with the view resolver. The request URLs are mapped to the Controller methods correctly, which I can see from my logging, but the tile view name returned by the Controller doesn’t render the view. It seems to load the corresponding tile definition and interprets the first tile template path as a URL resource:

    No mapping found for HTTP request with URI [/Inventory/WEB-INF/jsps/common/main.jsp] in DispatcherServlet

    Do you have any thoughts on what could cause this? Maybe its a version conflict between Spring and Tiles?

    thanks

  1. No trackbacks yet.