For the sample I am creating (see http://code.google.com/p/gridshore – Training Overview), I am using a combination of jquery and spring-mvc. I like the @controller stuff and the other annotations, therefore I want to explain some of the features I have learned to use so far. In a previous post I already introduced the jquery stuff, now I am going to focus on the spring controllers and the configuration.

First some context of what I am trying to do. I want to create a web application using jsp’s spring-mvc and of course some tag libraries. Since I am experimenting with jquery, some of the pages might look a bit strange. I will not mention that to much in this blog item, just so you now. To create a web application you need some standard files like web.xml, spring-servlet.xml, some property files for resource bundles and that is about it. As for the maven 2 dependencies, I only have spring-mvc (2.5), jstl (1.1.2) and taglibs.standard (1.1.2).

Let’s start with the configuration of the web.xml, we need to tell which spring configuration files to load and which url patterns to map to spring.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:spring-servlet.xml,
        classpath:validation-config.xml,
        classpath:business-config.xml,
        classpath:dataaccess-config.xml
    </param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>namespace</param-name>
        <param-value>/classes/spring-servlet</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>*.view</url-pattern>
</servlet-mapping>

The most important spring config file for the web part is spring-servlet.xml, as you can see we map al *.view urls to the spring dispatcher servlet. To show you how short this can be, check the complete source of this configuration 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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
http://www.spring.../beans http://www.../spring-beans-2.5.xsd
http://www.spring.../context http://www.spring.../context/spring-context-2.5.xsd">

    <context:component-scan base-package="nl.gridshore.samples.training.web"/>

    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames" value="exceptions,labels,messages"/>
    </bean>

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

Check the version of the schema’s, 2.5, and the namespaces we use, context and the standard beans. To enable the @Controller annotation we use the context:component-scan element. We load the resource bundles and we set the InternalResourceViewResolver that uses the view name returned by the controller to determine the jsp page to load. An example, we return the string "employees" then we load the jsp : /WEB-INF/jsp/employees.jsp. That is all the "xml" configuration we need to do. Let’s move to the controllers.

To indicate a class is actually a controller, we annotate it with "org.springframework.stereotype.Controller", now the configured component scan can find and initialize the controller. For now I see two different type of controllers. One that handles multiple GET requests and one that is more Form/Put based. Let’s have a look at one that handles the GET requests first. The following piece of code shows the EmployeeController class.

@Controller
public class EmployeeController {
    private EmployeeService employeeService;
    private TrainingService trainingService;

    @Autowired
    public EmployeeController(EmployeeService employeeService, TrainingService trainingService) {
        this.employeeService = employeeService;
        this.trainingService = trainingService;
    }

    @RequestMapping("/employees.view")
    public ModelMap employeesHandler() {
        return new ModelMap("employeesList",employeeService.obtainAllEmployees());
    }

    @RequestMapping("/employee.view")
    public ModelMap employeeHandler(@RequestParam("employeeId") Long employeeId) {
        return new ModelMap(employeeService.obtainEmployeeById(employeeId));
    }

    @RequestMapping("/showplannedtraining.view")
    public ModelMap showTrainingPlanForEmployeeHandler(@RequestParam("employeeId") Long employeeId) {
        ModelMap map = new ModelMap(employeeService.obtainEmployeeById(employeeId));
        map.addAttribute("trainingList",trainingService.obtainAllTrainings());
        return map;
    }
}

As you can see we just use one annotation on class level, the @Controller. The next annotation is pretty obvious, @Autowired. This one is used by the spring framework to insert the asked objects of type EmployeeService and TrainingService. Now the new stuff starts. The first method "employeesHandler", the name itself is not important, is annotated with the "RequestMapping" attribute. Here we specify that this method should be called as a response to the url "employees.view". The return parameter for this method is the ModelMap, a special class that is easy to read from in the jsp. In this method we put a list of employees in the map.

In the next method we introduce the next annotation, we now respond to the url "employee.view" and we read a parameter from the request.

... employeeHandler (@RequestParam("employeeId") Long employeeId)

... employeeHandler (@RequestParam(value="employeeId", required=false) Long employeeId)

The first example is the default way of doing, the parameter is required, in the second line I have given the example for a non required parameter. More on this later when handling a POST request. In these methods there is no explicit return string, so the url is used to determine the jsp to go to. In the example of employees.view, we go to employees.jsp.

We move on to another class, now we will have a look at a form handling class. This Controller is used to prepare the view with the form (a GET request) and to handle the submit of the form (a POST request).

@Controller
@RequestMapping("/editproject.view")
@SessionAttributes("project")
public class EditProjectController {
    private static final String REDIRECT_PROJECTS_VIEW = "redirect:projects.view";
    private static final String VIEW_NAME_FORM = "projectForm";
    private static final String SESSION_OBJECT_NAME = "project";

    private ProjectService projectService;

    @Autowired
    public EditProjectController(ProjectService projectService) {
        this.projectService = projectService;
    }

    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@RequestParam("projectId") long projectId, ModelMap modelMap) {
        Project project = projectService.obtainProjectById(projectId);
        modelMap.addAttribute(project);
        return VIEW_NAME_FORM;
    }

    @RequestMapping(method = RequestMethod.POST)
    public String processFormSubmit(
            @RequestParam(value = ControllerConstants.REQUEST_PARAM_CANCEL, 
                                      required = false) String cancel,
            @ModelAttribute(SESSION_OBJECT_NAME)Project project, 
                                       BindingResult bindingResult, 
                                       SessionStatus status) {
        String returnValue;
        if (ControllerConstants.REQUEST_PARAM_CANCEL_VALUE.equals(cancel)) {
            returnValue = REDIRECT_PROJECTS_VIEW;
        } else if (bindingResult.hasErrors()) {
            returnValue = VIEW_NAME_FORM;
        } else {
            projectService.storeProject(project);
            status.setComplete();
            returnValue = REDIRECT_PROJECTS_VIEW;
        }
        return returnValue;
    }
}

In this controller some things have changed, we now have more annotations at class level. This controller is meant to handle only one url, it does handle a GET as well as a POST request. At class level we now have the "RequestMapping" annotation. We also use the special "SessionAttributes" annotation. Here we tell the springframework to put the form backing object (or command object like we call it in spring) on the session using the specified name. We move on to the next annotation "RequestMapping", this time we do not map the url, but we use the method. In the GET request we look-up the project by using the provided projectId and in the POST request there is some code to handle the CANCEL action. If the submit was successful, we clean-up the session with the methods "setComplete()". The final remark for this class is about return values, in this case they are all strings, these strings are used by the framework to determine the jsp to go to. If you want to do something different, like go to a page and supply an object to present on that page, you can also return a ModelAndView object. The framework will use this to present the right jsp to the visitor. Check the following code to see the example how you can use it.

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView processSubmit(
            @RequestParam("employeeId") Long employeeId,
            @RequestParam("trainingsessionId") Long trainingsessionId
            ) {
        Employee employee = employeeService.addTrainingSessionToPlanningOfEmployee(
            employeeId,trainingsessionId);
        return new ModelAndView("employee","employee",employee);
    }

In this code we use provided employeeId and trainingSessionId (without using a form and binding result) to add a TrainingPlanning object to the employee. To be able to return to the employee screen provided the employee instance to the view with name employee.

These are the findings I have done so far. I am having some problems with validation together with internationalization, more on that later. I do like the way of using annotations, still I am not sure whether this is realy the way to go. You can a lot of freedom, therefore you need to think about a lot of things yourself. Using interfaces and parent classes is more obvious to others and does offer you more guidance. A tough choice, for now I’ll continue with the annotations, jut to learn more about it.

Hope this articles was useful, please leave a comment if you could use this info for your own projects. More info can be found in the reference manual of the springframework, you can also use the samples provided with the springframework 2.5.1 download.

Powered by Qumana

Using annottions in springframework
Tagged on:         

6 thoughts on “Using annottions in springframework

  • December 29, 2008 at 3:06 pm
    Permalink

    “still I am not sure whether this is realy the way to go”

    Well it is the way to go and the old way is being deprecated in Spring 3.0.

    http://rossenstoyanchev.org/blog/category/spring-mvc/

    A good articles on the topic is:
    http://www.infoq.com/articles/spring-2.5-ii-spring-mvc

    Even better is the slides from his presentation at Spring One 2008. They really help clarify things. I hope he puts them up on the web. Here you’re doing what he’s talking about and just adapting the annotations to the old style controllers. Works for backwards compatibility, but it’s not the best approach going forward.

    Think of the @Controller as a MultiActionController with methods for the different associated methods. Combine it with the convention over configuration stuff like ControllerClassNameHandlerMapping and you get more restful URLs …/employee/show, …/employee/edit, …/employee/find which correspond to methods on an EmployeeController. I’ve definitely come around to his way of thinking. I’ll admit I was on the fence myself before I understood the new approach.

    Paul Sundling
    http://www.gamerleague.com

  • October 30, 2008 at 9:22 pm
    Permalink

    You saved my life! I spent all the day long trying to put the SpringMvc to work. Now it is just running well with the SessionAttribute…
    Thanks for sharing this knowledge.

  • June 8, 2008 at 8:16 am
    Permalink

    Check page 352 of the reference manual (2.5.1) section “13.12.3. Mapping requests with @RequestMapping”. You can add parameters to your method of type ServletRequest (or PortletRequest). There is also a special class from the springframework called WebRequest. I must admit I have not used it before, but is seems pretty easy.

    good luck

  • June 8, 2008 at 6:23 am
    Permalink

    Hi
    How can I retreive the web request in the controler? let say I have the controller defined like this:
    @Controller
    @RequestMapping(“/*.hmtl”)
    public class MyController{}

    So I want to retrieve home.hml from the controller in case that ressource was required.

    Thanks

  • April 12, 2008 at 9:23 am
    Permalink

    I think you can (If I understand you correct). You can find more information in the reference documentation of the springmodules project. The annotation looks like this:

    @Validator(PersonValidator.class)

    You can do more advanced validations with this class. The easy validations on field level are done using other annotations. Check out the code, mainly the domain objects. There you can find examples like this:

    @NotNull
    @Length(min = 3, max = 50 )
    private String name;

  • April 11, 2008 at 11:32 pm
    Permalink

    Great post on using Spring with annotations! Is it possible to declare a validation class with annotations?

Comments are closed.