Tuesday, December 7, 2010

Spring MVC Annotation based Helloworld Example with LOG4J logging support


Today we will look at how to write Spring MVC hello world application using Spring Annotations. This tutorial will be completely different from other available tutorials in the web because, I have tried to show how to externalize property values from the BeanFactory definition and how to place them in a separate standard files called properties files. In addition, I will be using apache log4j framework to make the required logs for this application. Therefore you will be having the chance to investigate more on these technologies throughout this article. The overall directory and the file structure of the project is as follows.


I have used the following technologies and frameworks to make this simple example.

Apache Maven as the building tool
Apache Log4J as the logging framework
Spring MVC framework
Apache Tomcat for running this Application
Intelli J IDEA as the Development IDE


you can see the content of the each file as below.

 
pom.xml 

<?xml version="1.0" encoding="UTF-8"?>
<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>SpringMVC</groupId>
    <artifactId>SpringMVC</artifactId>
    <packaging>war</packaging>
    <version>1.0</version>
    <name>SpringMVC</name>

    <repositories>
        <repository>
            <id>JBoss repository</id>
            <url>http://repository.jboss.com/maven2/</url>
        </repository>

    </repositories>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <org.springframework.version>3.0.5.RELEASE</org.springframework.version>
    </properties>

    <dependencies>
        <!-- spring dependency starts-->
        <!-- Spring Framework -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <!-- Spring MVC Framework -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <!-- spring dependency ends-->

        <!-- JSTL Dependencies start -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.1.2</version>
        </dependency>

        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <!-- JSTL Dependencies ends -->


        <!--Logging Dependencies Starts-->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <!--Logging Dependencies Ends-->

    </dependencies>


    <build>
        <plugins>

            <!-- Maven compiler plugin that says to use JDK 1.6 version for compiling the project -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>

                </configuration>

            </plugin>


            <!-- Maven WAR  plugin -->
            <plugin>

                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.0.2</version>

                <configuration>
                    <warSourceDirectory>src/main/webapps</warSourceDirectory>
                </configuration>

            </plugin>
        </plugins>
        <!-- Final project build name -->
        <finalName>SpringMVC</finalName>
    </build>

</project>


HelloWorldControlller.java

this is the main(core) controller of this simple web application. You can see that we have used annotations for request mappings and other required configurations. As you can see the developer.name and developer.email properties have been defined in a external property file and they are accessed in the controller using the special annotations dedicated for that. The property values will be injected to the relevant variables using the @Value annotation.


package org.convey.example.Controller;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
Author: Chathuranga Tennakoon
Email: chathuranga.t@gmail.com

 */

@Controller
@RequestMapping("/HelloWorld")
public class HelloWorldController {


    private static final Logger logger = Logger.getLogger(HelloWorldController.class);

    @Value("${developer.name}")
    private String developerName;

    @Value("${developer.email}")
    private String developerEmail;

    @RequestMapping("/hello")
    public ModelAndView helloWorldMethod(){

        logger.debug(" invoking the helloWorldMethod method ");

        ModelAndView model=new ModelAndView("SayHelloView");

        model.addObject("developer_name",developerName);
        model.addObject("developer_email",developerEmail);


        return model;

    }//helloWorldMethod

}//helloWorldController



messages.properties

this file is located inside the resources/properties/ directory. The content of this file is as follows.

#Sample Screen Message values
developer.name=chathuranga tennakoon
developer.email=chathuranga.t@gmail.com

 

 
web.xml

you will see that the Spring MVC Dispatcher servlet is mapped and configured inside the web.xml file.
In additon, the log4j configuration is also done inside the web.xml file.(furthermore you can define and configure Filters and Listeners inside the web.xml file if required.)

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

<display-name>Spring3-HelloWorld-Example</display-name>
<!-- LOG4J Configuration -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/resources/log4j.xml</param-value>
</context-param>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- Spring MVC Dispatcher Servlet Mapping start -->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring MVC Dispatcher Servlet Mapping ends -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>


hello-servlet.xml

this represents the Dispatcher servlet of your web application. As you can see in the web.xml , you have named the dispater servlet as hello. Therefore your dispatcher servlet will be named as hello-servlet.xml. The beans that are declared in this servlet will be initiated when the Dispatcher servlet loading time. All the declared beans will be created in the Spring bean container.

<?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.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">

<import resource="applicationContext.xml"/>

<bean id="handlerMappingC" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop
key="/HelloWorld/*">
HelloController
</prop>

</props>
</property>
</bean>

<bean id="HelloController" class="org.convey.example.Controller.HelloWorldController"/>

</beans>

SayHelloView.jsp

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

<html>
<body>
<h1>Spring MVC Hello World Annotation Example</h1>

<!-- JSTL Tag libraries are required for the EL(Expression Language) -->
<h5>developed by : ${developer_name}</h5>
<h5>Email : ${developer_email}</h5>

</body>
</html>



applicationContext.xml

<?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.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="org.convey.example.Controller" />
<!-- actual view is resolved with the prefix + resolverName + suffix . if the resolverName is sayHelloView, then the actual resolved view will be /WEB-INF/view/sayHelloView.jsp ( /WEB-INF/view/ + sayHelloView + .jsp ) -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver" >

<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>

<!-- the below bean is configured to define external property file for defining property values for the application -->
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- messages have been defined inside the resources/properties/messages.properties file -->
<value>classpath:properties/messages.properties</value>
</list>
</property>
</bean>

</beans>


log4j.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>

<appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%x] %c{1} %m%n" />
</layout>
</appender>

<appender name="FileAppender" class="org.apache.log4j.FileAppender">
<!-- the log file will be available inside the logs directory of the tomcat installation. the name of the log file is sample.log -->
<param name="File" value="../logs/sample.log"/>
<!-- the log will contains the log messages started from the INFO level..(info or less) -->
<param name="Threshold" value="INFO"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%x] %c{1} %m%n" />
</layout>
</appender>

<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="FileAppender" />
</root>

</log4j:configuration>


How to run the project?

After placing the all required files in the relevant locations, you can use maven building tool to build your application. The following command can be used in your terminal to build the web application.

mvn clean install

once the project is build, you will see the war file (SpringMVC.war) inside the directory called target in your project source location. You can deploy the SpringMVC.war file in the tomcat server and see the output. It will display as below.

Browse the following URL to see the output.

http://localhost:8080/SpringMVC/HelloWorld/hello




 
Please remember to check the logs directory of your tomcat server installation and see whether there is a file called sample.log. This file should contains the log records which were generated during the execution of this web application. In additon, check whether the console appenders. In order to check the console appenders, you can use the following command in your terminal.(i assume that you are using a linux operating system.)

tail -f logs/catalina.out



regards
Chathuranga Tennakoon







Monday, December 6, 2010

Maven 2 Repository delcaration in pom.xml

    the following repository declaration can be placed in your pom.xml file for downloading required dependencies when your application is built.
 
    <repositories>
 
         <repository>
          <id>maven2-repository.dev.java.net</id>
          <name>Java.net Repository for Maven</name>
          <url>http://download.java.net/maven/2/</url>
          <layout>default</layout>
        </repository>

      </repositories>

then it will search the given repository for downloading the the required dependencies when building your project.




hope this will help for you!

regards
Chathuranga Tennakoon
chathuranga.t@gmail.com



Servlet Life Cycle

As we know the conventional J2EE application consists of set of Servlet and JSP files. therefore it is good to get a proper understanding of the servlet and jsp including their role and lifecycle. today i am going to discuss the servlet life cycle and hope to discuss the JSP in the future post. therefore we will briefly look at the Lifecycle and the role of the servlet in this post.

The Responsibility of the Servlet

the major responsibility of the servlet is to take the client request and send back the response.that means the servlet will be responsible for implementing and the processing business logics. In traditional MVC based J2EE web applications, the servlet act as the Controller.

M (Model) :- contains of POJO classes/core java classes to represent real word entities.

V (View) :- contains a set of JSP pages to implement presentation logic for the user.

C (Controller) :- contains the servlets to implement and process business logics.


The lifecycle of the Servlet

the servlet lives in the servlet container. that means the life cycle of the servlet is handled by the servlet container.servlet container provide necessary services for the servlet from born to dead.Apache tomcat is one of the well known servlet/web container.

i will explain the life cycle of the servlet using the following example.

suppose user clicks the following URL in the web application.

http://localhost:8080/example/sampleServlet

1.) this request will initially come to the web container. then the web container will identify that the request is to invoke a servlet. Then the web container will create two seperate objects known as HttpServletRequest and HttpServletResponse Objects for that request (in this case the web container doesn't know the what the actual servlet is).

2.) after creating the HttpServletRequest and HtppServletResponse objects, the web container will figure out the actual servlet based on the request URL.then it will check whether the Servlet is initialized. if it is not initialized, the container will initialize the servlet first.(the servlet initialization process will bemethod parameters) discussed later)Assume that the servlet is initialized at the moment.the web container will invoke the service() method of the servlet by providing(as the HttpServletRequest and HttpServletResponse Objects created. finally the web container will create and allocate a seperate thread to serve for that particular request.


3.) the service() method will figure out which servlet method to invoke based on the HTTP request methods.(GET or POST). if it is HTTP GET request, then it is required to invoke doGet() method. if it is HTTP POST, then doPost() method should be implemented.The service method will invoke either doGet() or doPost() methods providing the HttpServletRequest and httpServletResponse objects gained.



The servlet initialization process

the servlet must be initialized before handing client requests (invoking service() method). the servlet initialization is done by the servlet container by invoking inti() method. the init method is called(or servlet initilaization is done) only once for the life time of the servlet.servlet intilaization process can be described as follows.

1.) web container loads and instantite( create the object of the servlet) the servlet class.

2.) the created object is still not a servlet object. it is just an object cretaed from the servlet class type.In order to become a servlet, it is required to grant the servlet priviledges for that object. it is done by invoking init() method on that object. init() method is called only once throughout the life time of the servlet.

3.) after completing the init() method, servlet is initialized. therefore it is possible to invoke service() method to handle client requests.it is recommneded the developers to not to override the init() method.but if you required you can override the init() method. in such case, make sure that  you have all the initialization logic(codes) for that servlet(eg:- database connection codes, other connection and resource handling codes)


destroy()

The servlet container invoke the destroy() method on the servlet object to make it eligible for garbage collection.after completing all the works with the servlet, we do not require the servlet object longer. at that time, the servlet container invoke the destroy() method on the servlet object for releasing all the resorces(de-allocating) allocated during the initialization process. the destroy() method is also called only once like the init() method.

hope this will helpful for you!



regards
Chathuranga Tennakoon
chathuranga.t@gmail.com