Maven, Spring MVC, Eclipse example

Here’s a quick tutorial on how to make Maven, Spring MVC, log4j co-exist happily.

First off we need to create a Maven Project in Eclipse. Our POM is straight forward and looks like this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.dimitrisli.springMVC</groupId>
  <artifactId>mavenSpringMVC</artifactId>
  <version>1.0</version>
  <packaging>war</packaging>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>3.1.0.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
    	<groupId>log4j</groupId>
    	<artifactId>log4j</artifactId>
    	<version>1.2.16</version>
    </dependency>
  </dependencies>
  	<build>
		<finalName>MavenSpringMVC</finalName>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
  	<properties>
  		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  	</properties>
</project>

Note how the spring-webmvc dependency is enough to bring all the other main Spring dependencies along due to the dependency hierarchy that Maven is taking care of gracefully and silently behind the scenes.

Since we are building a webapp we would need the webapp/WEB-INF structure which we host in /src/main/.

The web.xml would look like this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.dimitrisli.springMVC</groupId>
  <artifactId>mavenSpringMVC</artifactId>
  <version>1.0</version>
  <packaging>war</packaging>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>3.1.0.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
    	<groupId>log4j</groupId>
    	<artifactId>log4j</artifactId>
    	<version>1.2.16</version>
    </dependency>
  </dependencies>
  	<build>
		<finalName>MavenSpringMVC</finalName>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
  	<properties>
  		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  	</properties>
</project>

A few things to notice:

  • We define as the sole servlet of our application Spring’s DispatcherServlet that delegates requests to controllers accordingly.
  • We define Spring’s ContextLoaderListener  as a listener in the web.xml to initialize Spring on webapp startup.
  • The defined context-param needs to have to have as name: <servletNameWeGaveToTheServletDispatcher>-servlet.xml otherwise it will throw an error during runtime load-up.

The view of the response is built up internally using Spring’s InternalResourceViewResolver that is dynamically add a prefix and suffix:

<?xml version="1.0" encoding="UTF-8"?>
<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"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<context:component-scan base-package="com.dimitrisli.springmvc" />

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

</beans>

Finally the Controller looks like this:

package com.dimitrisli.springmvc;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@RequestMapping("/something.do")
@Controller
public class MyController {

	private static final Logger logger = Logger.getLogger(MyController.class);
	@RequestMapping(method = RequestMethod.GET)
	public String method(ModelMap modelMap){
		modelMap.addAttribute("msg","Hello world");
		return "test";
	}
}

The Spring annotations @Controller and @RequestMapping are defining the fact that the POJO is a Controller and where the request should be forwarded to respectively.

After we mvn package the war file should be ready for deployment waiting for us in Maven’s target dir. Making use of Eclipse’s WTP we can deploy the application inside the familiar place of Eclipse. To do so all we need is the Servers view where we need to create a new Tomcat server pointing to our Maven war file.

After starting-up the application pointing a browser session to the http://localhost:8080/mavenSpringMVC/something.do should go through the controller and give us back the hello world output.

The source code can be found in this Github repository.

Advertisements

Spring MVC, Spring Scheduling, Maven example

This is an example showcasing Spring’s scheduling capabilities sitting on top on a Spring MVC Maven project.

First the POM looks like this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.dimitrisli.springmvc</groupId>
  <artifactId>SpringMVCScheduler</artifactId>
  <packaging>war</packaging>
  <version>1.0</version>
  <build>
  	<finalName>SpringMVCScheduler</finalName>
  	<plugins>
  		<plugin>
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-compiler-plugin</artifactId>
  			<version>2.3.2</version>
  			<configuration>
  				<source>1.6</source>
  				<target>1.6</target>
  				<encoding>${project.build.sourceEncoding}</encoding>
  			</configuration>
  		</plugin>
  	</plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>3.1.0.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
  		<groupId>javax.servlet</groupId>
  		<artifactId>servlet-api</artifactId>
  		<version>2.5</version>
  		<scope>provided</scope>
  	</dependency>
  	<dependency>
  		<groupId>javax.servlet.jsp</groupId>
  		<artifactId>jsp-api</artifactId>
  		<version>2.2</version>
  		<scope>provided</scope>
  	</dependency>
  </dependencies>
  <properties>
  	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
</project>

Notice that the spring-webmvc dependency is enough to bring along all the other Spring jars that are necessary thanks to the dependency hierarchy that Maven is taking care off behind the scenes so gracefully.

The web.xml of the web app looks like this:

<!--?xml version="1.0" encoding="UTF-8"?-->

		spring
		org.springframework.web.servlet.DispatcherServlet
		1

		spring
		/

		log4jConfigLocation
		/WEB-INF/log4j.properties

		org.springframework.web.util.Log4jConfigListener

		contextConfigLocation
		/WEB-INF/application-context.xml

		org.springframework.web.context.ContextLoaderListener

A few things to notice:

  • The sole Servlet we need to define is Spring’s DispatcherServlet that we map to any incoming url pattern
  • Spring’s ContextLoaderListener is defined in the web.xml and is initialising the container similar to the ApplicationContext or the old deprecated XMLFactoryBean (it was giving too much unnecessary power).
  • If we want Log4j to be initialised, up and running when the Spring app is starting up we can define Spring’s helper Log4jConfigListener 
  • With the context-param element we can explicitly specify the main config file of the Spring context.

This application context looks like this:

<?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"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	   		http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
	   		http://www.springframework.org/schema/context
	   		http://www.springframework.org/schema/context/spring-context-3.1.xsd
			http://www.springframework.org/schema/mvc
			http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">

	<!-- Scans the classpath under the base-package for annotated components -->
	<context:component-scan base-package="com.dimitrisli.springmvc.controller" />

	<!-- Scheduling config -->
	<import resource="scheduling-context.xml" />

</beans>

whereas the autoloaded spring-servlet.xml based on the DispatcherServlet‘s servlet-name we define in web.xml that defines how the view url resolves:


<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	   		http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

	<!-- Declare a view resolver -->
		<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/jsp/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>

</beans>

The scheduler context looks like this:

<?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:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	   		http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
	   		http://www.springframework.org/schema/task
			http://www.springframework.org/schema/task/spring-task-3.1.xsd">

	<!-- Spring's scheduling support -->
	<task:scheduled-tasks scheduler="taskScheduler">
		<!-- task:scheduled ref="fixedDelayService" method="performService" fixed-delay="5000"/-->
		<!-- task:scheduled ref="fixedRateService" method="performService" fixed-rate="5000"/-->
    	<task:scheduled ref="cronService" method="performService" cron="*/5 * * * * ?"/>
	</task:scheduled-tasks>

	<!-- The bean that does the actual work -->
	<bean id="fixedDelayService" class="com.dimitrisli.springmvc.scheduling.FixedDelayServiceImpl" />
	<bean id="fixedRateService" class="com.dimitrisli.springmvc.scheduling.FixedRateServiceImpl" />
	<bean id="cronService" class="com.dimitrisli.springmvc.scheduling.CronServiceImpl" />

	<!-- Defines a ThreadPoolTaskScheduler instance with configurable pool size. -->
	<task:scheduler id="taskScheduler" pool-size="1"/>

</beans>

Things to consider here:

  • Spring’s namespaces and namely the task namespace, is allowing us to define the scheduler and its scheduled tasks.
  • Each one of the scheduled tasks is a bean we define specifying the method we would like to execute once the scheduler kick-starts the job
  • We showcase 3 different scheduled tasks Spring provides fixed-delay, fixed-rate and the cron-way.

The code can be found in this Github repository.