Showing posts with label log4j and slf4J. Show all posts
Showing posts with label log4j and slf4J. Show all posts

Tuesday, December 13, 2011

Send Email in Spring 3 (Spring MVC) with Gmail

today i have prepared a sample application that demonstrate how to develop a web application to use Gmail server to send email with Spring MVC 3.

this application will display you an email submission form where you can type the email message body, email header and the receiver email address. once those fields are filled, you can press send email button to send the newly created email using your email account (this is configured in the application configuration files and  we are going to discuss it in few minutes)

i have used the Spring Framework inbuilt mail package for sending email rather than using any other third party module. the below mentioned technologies has been used to develop this application.some of the main/core technologies are mentioned as follows.


  • Spring MVC 3 and Spring Framework inbuilt mail package
  • Apache Maven (version 03)
  • SLF4J logging framework
  • JSTL tag libraries


the below screenshot shows your the project directory structure of this application



we will look at each file in detailed with its duty and the responsibility towards this application.


index.jsp

this is a simple HTML page (no any jsp tags or other java code pieces - even if this is named as jsp) with a simple anchor tag. it directs the user to the email sending form upon user click.

<html>
<body>
<h2> <a href="/email/emailForm">Load Email Form</a></h2>
</body>
</html>



after click the anchor tag it will make the /email/emailForm URL call. the URL call will redirects to the Spring MVC DispatcherServlet as mapped in the web.xml file.

web.xml file

<?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>Archetype Created Web Application</display-name>

    <context-param>
        <param-name>log4jConfigLocation</param-name><param-value>/resources/log4j.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>email</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

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


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

</web-app>


you can see that we have mapped all the user requests (URL requests) to the Spring MVC DispatcherServlet using web.xml file. In addition, we have used the web.xml file to do required configuration for the logging framework (either log4j or slf4j ). you can see that the dispatcher servlet name is email (as mentioned in the web.xml).


email-servlet.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"
       xmlns:p="http://www.springframework.org/schema/p"
       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">

    <!-- this will scan the @Component models defined in the given package (including sub packages) and it will automatically create instances.
         if you have used @Component annotation, it is not required to define the beans  in the XML configuration files -->
    <!-- Discover POJO @Components -->
    <!--<context:component-scan base-package="org.convey.registration" />-->

    <import resource="applicationContext.xml"/>

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


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

                <prop
                        key="/sendEmail">
                    emailController
                </prop>

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


    <bean id="emailController" class="org.convey.example.controller.EmailController"/>

</beans> 
  

it will find and call the relevant controller based on the relevant url mapping done inside the email-servlet.xml . it will find that the emailController bean id is responsible for handling the /emailForm url mapping. emailController bean id is referring to the EmailController class. then it will find the EmailController instance for delegating the user request to the relevant method.


EmailController

package org.convey.example.controller;

import org.convey.example.email.EmailSender;
import org.convey.example.model.EmailMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;


/**
 * $LastChangedDate:  $
 * $LastChangedBy:  $
 * $LastChangedRevision:  $
 */
@Controller
public class EmailController {

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("emailConfiguration.xml");
    EmailSender emailSender=(EmailSender)context.getBean("emailSenderBean");


    final static Logger logger = LoggerFactory.getLogger(EmailController.class);


    @RequestMapping(value="/emailForm",method= RequestMethod.GET)
    public ModelAndView displayEmailForm(Map<String, Object> map){

        logger.debug(" setting up the Email form ");

        ModelAndView view=new ModelAndView("EmailFormView");

        //setting up the  required parameter value in the request scope for CommandName parameter
        map.put("email", new EmailMessage());

        return view;

    }



    @RequestMapping(value="/sendEmail",method= RequestMethod.POST)
    public ModelAndView sendEmailUsingGmail(@ModelAttribute("email")EmailMessage email){


        logger.debug(" ********************* ready to send the email **********************");
        logger.debug(" receiver email address [{}]", email.getReceiverEmailAddress());
        logger.debug(" email subject [{}]", email.getSubject());
        logger.debug(" email body [{}]", email.getMessageBody());

        ModelAndView view=new ModelAndView("EmailView");

        view.addObject("emailAddress",email.getReceiverEmailAddress());
        emailSender.sendEmail(email);
        logger.debug(" ********************* email was sent **********************");

        return view;

    }


}


as you can see that in the EmailController , displayEmailForm() method is responsible for handling the /emailForm request. (that is obviously GET request)

displayEmailForm() will display the email sending form page (jsp view) to the user. EmailFormView is a JSP page and that contains the required html input fields for composing the email message. the viewResolver defined  in the emai-servlet.xml can resolve this logical view name (EmailFormView) to the actual physical view name(EmailFormView.jsp).  Inside this displayEmailForm method, an instance of EmailMessage is created (referred as email) and put it in the request scope. this instance will be used by the email sending form for populating the user input form data when the submission is made. (you can later see it in the CommandName attribute in form)

EmailFormView.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

<html>
<head><title>Email Form</title>
</head>
<body>

<form:form commandName="email" method="POST" action="sendEmail">

    <p>Email Form </p>
    <br/><br/>

    Receiver Email
    <form:input path="receiverEmailAddress"/>
    <br/><br/>

    Subject
    <form:input path="subject"/>
    <br/><br/>

    Message Body
    <form:input path="messageBody"/>
    <br/><br/>

    </br>
    <input type="submit" value="Send Email" />

</form:form>

</body>
</html>



CommandName attribute is referring to the instance of EmailMessage (created in displayEmailForm() and referred as email) for populating the form data inputs when the form is submitted. form will be submitted to the URL /sendEmail . the relevant controller method will be found and the submission request will be delegated to the relevant method. sendEmailUsingGmail() method available in the EmailController class is responsible for this submission  request. then it will compose the message and send the email with the Gmail server.


EmailSender.java
package org.convey.example.email;

import org.convey.example.model.EmailMessage;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;

/**
 * $LastChangedDate:  $
 * $LastChangedBy:  $
 * $LastChangedRevision:  $
 */

public class EmailSender {


    private MailSender mailSender;

    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }


    public void sendEmail(EmailMessage emailMessage){

        SimpleMailMessage message = new SimpleMailMessage();

        message.setTo(emailMessage.getReceiverEmailAddress());
        message.setSubject(emailMessage.getSubject());
        message.setText(emailMessage.getMessageBody());
        //sending the message
        mailSender.send(message);

    }


}

the EmailSender class is used to send the email with the provided EmailMessage object. this class uses the  email server settings provided in the emailConfiguration.xml  to send the email.

EmailMessage.java

package org.convey.example.model;

import org.springframework.stereotype.Component;

/**
 * $LastChangedDate:  $
 * $LastChangedBy:  $
 * $LastChangedRevision:  $
 */
@Component
public class EmailMessage {


    private String receiverEmailAddress;
    private String subject;
    private String messageBody;


    public void setMessageBody(String messageBody){

        this.messageBody=messageBody;
    }

    public String getMessageBody(){

        return this.messageBody;
    }

    public void setReceiverEmailAddress(String receiverEmailAddress){

        this.receiverEmailAddress=receiverEmailAddress;
    }

    public String getReceiverEmailAddress(){

        return this.receiverEmailAddress;
    }


    public void setSubject(String subject) {

        this.subject=subject;
    }

    public String getSubject(){

        return this.subject;
    }


}


EmailMessage class is used to represent the email message. it contains Message properties with public getters and setters.


emailConfiguration.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:p="http://www.springframework.org/schema/p"
       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 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="smtp.gmail.com" />
        <property name="port" value="587" />
        <property name="username" value="abanstest@gmail.com" />
        <property name="password" value="abanstest123" />

        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtp.auth">true</prop>
                <prop key="mail.smtp.starttls.enable">true</prop>
                <prop key="mail.smtp.debug">true</prop>
            </props>
        </property>
    </bean>

    <bean id="emailSenderBean" class="org.convey.example.email.EmailSender">
        <property name="mailSender" ref="mailSender" />
    </bean>
</beans>

this file contains the email server connection details that are required to make a connection with the email server.

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>

this is the logging framework (either log4j or slf4j) configuration file.


the source code is available in the following GIT repository.

git@github.com:chathurangat/spring-email.git

hope this will helpful for you
Chathuranga Tennakoon
chathuranga.t@gmail.com

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