Gradle – Spring 4 MVC Hello World Example – Annotation

gradle-spring-logo

In this tutorial, we will take the previous Gradle + Spring MVC XML example, rewrite it to support @JavaConfig annotation configuration, no more XML files.

P.S This example will works in Servlet 3.0+ container only, like Tomcat 7 or Jetty 9.

Technologies used :

  1. Gradle 2.0
  2. Spring 4.1.6.RELEASE
  3. Tomcat 7 or Jetty 9
  4. Eclipse 4.4
  5. JDK 1.7
  6. Logback 1.1.3
  7. Boostrap 3

1. Project Structure

Download the project source code and review the project folder structure :

spring4-mvc-gradle-project-anno

P.S No more XML files like web.xml or Spring XML configuration files.

2. Gradle

2.1 Review the build.gradle file, this should be self-explanatory.

build.gradle

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'eclipse-wtp'
//apply plugin: 'jetty' //too old, Jetty 6, use gretty plugin
apply plugin: 'org.akhikhl.gretty'

// JDK 7
sourceCompatibility = 1.7
targetCompatibility = 1.7

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    compile 'ch.qos.logback:logback-classic:1.1.3'
    compile 'org.springframework:spring-webmvc:4.1.6.RELEASE'
    compile 'javax.servlet:jstl:1.2'
	
    //include in compile only, exclude in the war
    providedCompile 'javax.servlet:servlet-api:2.5'
}

//Gretty Embedded Jetty
buildscript {
  repositories {
    jcenter()
  }

  dependencies {
    classpath 'org.akhikhl.gretty:gretty:+'
  }
}

// Don't use Jetty8, even it's a servlet 3.0+ container, 
// but not support non-jar WebApplicationInitializer scanning.
// It will cause "No Spring WebApplicationInitializer types detected on classpath"
gretty {
  port = 8080
  contextPath = 'spring4'
  servletContainer = 'jetty9' //tomcat7 or tomcat8
}

//For Eclipse IDE only
eclipse {

  wtp {
    component {
      
      //define context path, default to project folder name
      contextPath = 'spring4'
      
    }
    
  }
}

2.2 Make this project supports Eclipse IDE. Now, you can import the project into Eclipse IDE.


your-project$ gradle eclipse

3. Spring @Configuration

Spring @Configuration and its XML equivalent.

3.1 Spring annotation configuration to scan the service classes.

SpringRootConfig.java

package com.mkyong.helloworld.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({ "com.mkyong.helloworld.service" })
public class SpringRootConfig {
}

XML equivalent.

spring-core-config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	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.mkyong.helloworld.service" />

</beans>

3.2 Extends abstract class WebMvcConfigurerAdapter.

SpringWebConfig.java

package com.mkyong.helloworld.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
 
@EnableWebMvc //<mvc:annotation-driven />
@Configuration
@ComponentScan({ "com.mkyong.helloworld.web" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
 
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**")
                        .addResourceLocations("/resources/");
	}
	
	@Bean
	public InternalResourceViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver 
                         = new InternalResourceViewResolver();
		viewResolver.setViewClass(JstlView.class);
		viewResolver.setPrefix("/WEB-INF/views/jsp/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}
 
}

XML equivalent.

spring-web-config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd ">
 
	<context:component-scan base-package="com.mkyong.helloworld.web" />
 
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
		<property name="prefix" value="/WEB-INF/views/jsp/" />
		<property name="suffix" value=".jsp" />
	</bean>
 
	<mvc:resources mapping="/resources/**" location="/resources/" />
	 
	<mvc:annotation-driven />
 
</beans>

4. Servlet 3.0+ Container

Create a ServletInitializer class, Servlet 3.0+ container will pick up this class and run it automatically. This is the replacement class for web.xml


package com.mkyong.helloworld.servlet3;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.mkyong.helloworld.config.SpringRootConfig;
import com.mkyong.helloworld.config.SpringWebConfig;

public class MyWebInitializer extends
		AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { SpringRootConfig.class };
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return new Class[] { SpringWebConfig.class };
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}

}

XML equivalent.

web.xml

<web-app 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"
	version="2.5">

	<display-name>Gradle + Spring MVC Hello World</display-name>
	<description>Spring MVC web application</description>

	<!-- For web context -->
	<servlet>
		<servlet-name>hello-dispatcher</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring-mvc-config.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>hello-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

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

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring-core-config.xml</param-value>
	</context-param>

</web-app>
Note
There is no change in the Spring controller, logback and JSP files, so, the source code will not repeat here, please refer to the previous Gradle + Spring MVC XML example for complete source code.

5. Demo

5.1 To run this project. Issues gradle jettyRun to start the embedded Jetty container.

Terminal

your-project$ gradle jettyRun

21:56:34 INFO  Jetty 9.2.10.v20150310 started and listening on port 8080
21:56:34 INFO  spring4 runs at:
21:56:34 INFO    http://localhost:8080/spring4
Press any key to stop the server.
> Building 87% > :jettyRun

5.2 http://localhost:8080/spring4/

spring-4-mvc-gradle-demo1

5.3 http://localhost:8080/spring4/hello/mkyong.com

spring4-mvc-gradle-demo2

Download Source Code

References

  1. Wikipedia – Java servlet
  2. Spring Web MVC References
  3. Gradle – EclipseWtp
  4. Gradle – Eclipse Plugin
  5. Gradle – Jetty Plugin
  6. Gradle – Gretty plugin
  7. Gradle – Gretty configuration

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

avatar
11 Comment threads
9 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
11 Comment authors
joshua kimNevinJuan Carlos PuertoErnesto RieraAnurag Recent comment authors
newest oldest most voted
Ernesto Riera
Guest
Ernesto Riera

Only a small observation. On web.xml equivalanet instead of:

/WEB-INF/spring-mvc-config.xml

should be:

/WEB-INF/spring-web-config.xml

Great post !!

joshua kim
Guest
joshua kim

Hi mkyoung
I hava some question like no web.xml like this erreo page ” /404″
how can i settings custom error page with out web.xml

Juan Carlos Puerto
Guest
Juan Carlos Puerto

Hi, thanks for the tutorial!

The original tutorial worked fine for me, however I’m having a weird problem when running jettyRun.

Starts the server but it stops right away. Some of the output is this:

22:43:37 INFO Jetty 9.2.15.v20160210 started and listening on port 8080
22:43:37 INFO spring4 runs at:
22:43:37 INFO http://localhost:8080/spring4
Press any key to stop the server.
22:43:37 INFO Destroying Spring FrameworkServlet ‘dispatcher’

BUILD SUCCESSFUL

Any ideas on what’s going on? Thank you again!

Nevin
Guest
Nevin

I have the same problem , did you get it fixed ?

Anurag
Guest
Anurag

getting this error when doing gradle jettyRun

No mapping found for HTTP request with URI [/spring4/] in DispatcherServlet with name ‘hello-dispatcher’

Mike
Guest
Mike

Hi,
Tried this with Java 8 & worked fine, but no ‘test’ is created under ‘src’. Any suggestion?

trackback
Spring 4 MVC Ajax Hello World Example

[…] Gradle – Spring 4 MVC hello world annotation […]

trackback
Spring MVC Tutorial

[…] Gradle – Spring 4 MVC Hello World Example (@JavaConfig + Servlet 3) […]

emre ça?lar
Guest
emre ça?lar

Hello,

I am trying your source code with IntelliJ 14, Tomcat 7, Java 1.7

I can access localhost:8080 and I can see your main page without problem.

However, when I enter url http://localhost:8080/spring4/hello/emreI am gettingHTTP status 404 with the following warning on IntelliJ console.

I even tried other projects with different version but all same.

I can open the default page but not others (localhost:8080/hello/.. etc)

any idea?

thanks

A?u 18, 2015 12:01:42 AM org.springframework.web.servlet.PageNotFound noHandlerFound

WARNING: No mapping found for HTTP request with URI [/spring4/hello/emre] in DispatcherServlet with name ‘dispatcher’

RazieL
Guest
RazieL

Instead of those two classes: MyWebInitializer, ServletInitializer and SpringWebConfig i have just:

@Configuration
@EnableWebMvc
public class ServerConfiguration extends WebMvcAutoConfiguration{

}

@ComponentScan
@EnableAutoConfiguration
public class WebAppInit extends SpringBootServletInitializer {

@Override
public SpringApplicationBuilder configure(SpringApplicationBuilder sab) {
return sab.sources(WebAppInit.class);
}

public static void main(String[] args) {
SpringApplication.run(WebAppInit.class, args);
}
}

and Controller class. In src/main/resources application.properieties i have this:

spring.view.prefix: /WEB-INF/view/
spring.view.suffix: .jsp

and it works – had the same problem like u before.

emre ça?lar
Guest
emre ça?lar

Thanks for your reply.You have a application.properties file under resource but i could not see that you use it in code am i wrong?And as i see, you have just 2 configuration files which are ServerConfiguration and WebAppInit that is all? Thanks again .

trackback
Spring 3 MVC hello world example – Annotation

[…] Spring 4 MVC Try this Spring 4 MVC hello world example – Annotation. […]

Rov
Guest
Rov

Same for me, on Windows 7 Professional with gradle 2.4 I get directory listing @disqus_ki1gGlNvDG:disqus please let me know if you find the solution. I have tried official spring gradle bake and it opens the web page with tomcat when deployed as war, but the project presented in this tutorial seem not to render the web page. Is this a problem with Jetty or the project build with gradle?

mkyong
Guest
mkyong

Sorry, my mistake, article is updated, please try again.

— Reason —
The official Gradle Jetty plugin is outdated (Jetty 6), not a Servlet 3.0+ web container, that why it’s unable to detect the WebInitializer class.

— Solution —
Use third party Gradle Jetty plugin – Gretty – https://github.com/akhikhl/gretty

Rov
Guest
Rov

Thank you very much for reply.

Daniel Barton
Guest
Daniel Barton

Hello,

Thank you for another great tutorial. However, after I downloaded the source code and attempted to run the example I navigated to localhost:8080/spring4/. I was not able to view the main page. Instead, the page I got contains the following text :

Directory: /spring4/

WEB-INF/ 102 bytes Jun 2, 2015 7:11:04 AM
resources/ 102 bytes Jun 2, 2015 7:10:43 AM

My initial thought would be that the initializer is not properly configured, but I am not sure due to the fact that I am new to the spring framework. Any ideas?

mkyong
Guest
mkyong

Look like your web server is enabled the directory browsing, weird..

May I know how you run the web app? Using gradle jettyRun ?

Daniel Barton
Guest
Daniel Barton

Yes, grade jettyRun is exactly how I ran the server. I followed the same procedure (download project, gradle eclipse, then gradle jettyRun) with your xml example and the server works fine. However, this annotation example is still doing the directory browsing.

mkyong
Guest
mkyong

Thanks for highlighted this problem, article is updated with Gretty plugin, please try again. The official Gradle Jetty plugin is too old, unable to scan the WebInitializer class.

Daniel Barton
Guest
Daniel Barton

Thanks for the quick response, works great now!