Wednesday 29 August 2012

Spring MVC with Annotations Example

This post describes a simple Spring MVC application example with annotation configuration. This example is available from Github in the Spring-MVC-With-Annotations directory. Typically, a complete application's architecture includes several layers: MVC, Service, DAO, Persistence Layer.

Configuration

In our previous example, we still use a servlet-context.xml file. In this example, we get rid of it using the @EnableWebMvc annotation.

The web.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.jverstry.Configuration</param-value>
    </context-param>

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

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file></welcome-file>
    </welcome-file-list>

</web-app>
We do not set a default welcome file. It is delegated to our controller.

The Java configuration class:
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.jverstry")
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public ViewResolver getViewResolver() {

        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("WEB-INF/pages/");
        resolver.setSuffix(".jsp");

        return resolver;

    }

}
The @ComponentScan annotation tells Spring to scan the content of packages for Spring annotated classes.

JSP pages

We have two JSP pages in  the WEB-INF/pages/ directory.

index.jsp
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Welcome !!!</title>
</head>
<body>
  <h1>
    Welcome To Spring MVC With Annotations !!!
  </h1>
</body>
</html>
getTime.jsp 
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Get Time !!!</title>
    </head>
    <body>
        The time in milliseconds is: <c:out value="${TimeIs}" /> !
    </body>
</html>

Controller & Service

Our controller:
@Controller
public class MyController {

    private MyService myService;

    @Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }

    @RequestMapping(value = "/")
    public String home() {
        return "index";
    }

    @RequestMapping(value = "/getTime")
    public String helloWorld(Model model) {
        model.addAttribute("TimeIs", myService.getCurrentTimeInMilliseconds());
        return "getTime";
    }

}
The above, maps index.jsp to '/' user requests.

Our service and implementation:
public interface MyService {
    long getCurrentTimeInMilliseconds();
}

public class MyServiceImpl implements MyService {

    @Override
    public long getCurrentTimeInMilliseconds() {
        return System.currentTimeMillis();
    }

}

@Configuration
public class MyServicesConfiguration {

    private MyService myService = new MyServiceImpl();

    @Bean
    public MyService getMyService() {
        return myService;
    }

}

Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib-nodep</artifactId>
        <version>2.2</version>
        </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

Running The Example

After compiling the project, one can run it using the maven tomcat:run goal. Then, browse:

  http://localhost:8383/spring-mvc-with-annotations/getTime

It will display something similar to:

  The time in milliseconds is: 1346261454171 !

For the same example with Spring Security, click here • More Spring related posts here.

5 comments:

  1. Hi, I am finding it very good and latest spring mvc examples. But i have little confusion here. You are defining both viewresolver and service bean in WebConfig class, is it good to do this? should not we define them separately? As i have learned the context file in DispatcherServlet should have mvc components of your project and context file in ContextLoaderListener should have services and dao components of your project. Could you please clarify?

    ReplyDelete
    Replies
    1. I wrote my example this way to keep the code compact, but it is not mandatory. If you prefer to create a separate class annotated with @Configuration and define your beans there, that's fine too... It is up to you...

      Delete
  2. Do u have any curd example in Spring Framework?

    ReplyDelete
    Replies
    1. Yes, see: http://tshikatshikaaa.blogspot.com/2012/08/standalone-hibernate-jpa-in-memory.html

      Delete
  3. Hi,

    I am new to Spring and I was trying with your code in my sample application and while running i ran into this issue something like this:

    Could not autowire method nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type is defined: expected single matching bean but found 2:(MyServiceImpl, getMyService)

    In order to fix it I had to comment out the @bean from the MyServicesConfiguration. Dont know if you faced this issue or why I am facing this issue.

    @Configuration
    public class MyServicesConfiguration {

    private MyService myservice = new MyServiceImpl();

    //@Bean
    public MyService getMyService(){

    return myservice;
    }
    }

    ReplyDelete