Sunday, April 22, 2012

How to integrate JSF2.0 with Spring 3.0 Framework

Steps:

1. Create the Maven Project "JSF" with
groupId: com.jsf.app
artifactId: jsf
package: war
and add following dependencies in pom.xml

 <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.jsf.app</groupId>  
      <artifactId>jsf</artifactId>  
      <version>0.0.1-SNAPSHOT</version>  
      <packaging>war</packaging>  
      <name>jsf</name>  
      <url>http://maven.apache.org</url>  
      <properties>  
           <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
           <org.springframework.bom.version>3.1.0.RELEASE</org.springframework.bom.version>  
      </properties>  
      <dependencies>  
           <dependency>  
                <groupId>junit</groupId>  
                <artifactId>junit</artifactId>  
                <version>3.8.1</version>  
                <scope>test</scope>  
           </dependency>  
           <!-- Logging Dependencies -->            
           <dependency>  
                <groupId>log4j</groupId>  
                <artifactId>log4j</artifactId>  
                <version>1.2.14</version>  
           </dependency>  
           <!-- http://download.java.net/maven/2 -->  
           <dependency>  
                <groupId>com.sun.faces</groupId>  
                <artifactId>jsf-api</artifactId>  
                <version>2.1.0-b03</version>  
           </dependency>  
           <dependency>  
                <groupId>com.sun.faces</groupId>  
                <artifactId>jsf-impl</artifactId>  
                <version>2.1.0-b03</version>  
           </dependency>  
           <!-- http://repo1.maven.org/maven -->  
           <dependency>  
                <groupId>javax.servlet</groupId>  
                <artifactId>jstl</artifactId>  
                <version>1.2</version>  
           </dependency>  
           <dependency>  
                <groupId>javax.servlet</groupId>  
                <artifactId>servlet-api</artifactId>  
                <version>2.5</version>  
           </dependency>  
           <dependency>  
                <groupId>javax.servlet.jsp</groupId>  
                <artifactId>jsp-api</artifactId>  
                <version>2.1</version>  
           </dependency>  
           <dependency>  
                <groupId>com.sun.el</groupId>  
                <artifactId>el-ri</artifactId>  
                <version>1.0</version>  
           </dependency>  
           <!-- Spring Related Dependency -->       
           <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-core</artifactId>  
                <version>${org.springframework.bom.version}</version>  
           </dependency>  
           <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-web</artifactId>  
                <version>${org.springframework.bom.version}</version>  
           </dependency>  
      </dependencies>  
 </project>  

2. Create the directory structure like:
jsf
-src
--main
---java
-----com
-------jsf
--------app
----------managedbean
-------------UserBean.java
----------service
-------------UserService.java
-------------impl
---------------UserServiceImpl.java
---resources
----applicationContext.xml
----log4j.xml
----messages.properties
---webapp
-----pages
-------jsfspring.xhtml
-----WEB-INF
--------faces-config.xml
--------web.xml
--test
--pom.xml

3. In web.xml file add these settings.
 <?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>JavaServerFaces&Spring</display-name>  
      <listener>  
           <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
      </listener>  
      <listener>  
           <listener-class>  
                org.springframework.web.context.request.RequestContextListener</listener-class>  
      </listener>  
      <listener>  
           <listener-class>com.sun.faces.config.ConfigureListener</listener-class>  
      </listener>  
      <context-param>  
           <param-name>javax.faces.PROJECT_STAGE</param-name>  
           <param-value>Development</param-value>  
      </context-param>  
      <context-param>  
           <param-name>contextConfigLocation</param-name>  
           <param-value>classpath:/applicationContext.xml</param-value>  
      </context-param>  
      <context-param>  
           <param-name>javax.faces.CONFIG-FILES</param-name>  
           <param-value>WEB-INF/faces-config.xml</param-value>  
      </context-param>  
      <context-param>  
           <param-name>com.sun.faces.expressionFactory</param-name>  
           <param-value>com.sun.el.ExpressionFactoryImpl</param-value>  
      </context-param>  
      <servlet>  
           <servlet-name>Faces Servlet</servlet-name>  
           <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>  
           <load-on-startup>1</load-on-startup>  
      </servlet>  
      <servlet-mapping>  
           <servlet-name>Faces Servlet</servlet-name>  
           <url-pattern>/faces/*</url-pattern>  
      </servlet-mapping>  
      <servlet-mapping>  
           <servlet-name>Faces Servlet</servlet-name>  
           <url-pattern>*.jsf</url-pattern>  
      </servlet-mapping>  
      <servlet-mapping>  
           <servlet-name>Faces Servlet</servlet-name>  
           <url-pattern>*.faces</url-pattern>  
      </servlet-mapping>  
      <servlet-mapping>  
           <servlet-name>Faces Servlet</servlet-name>  
           <url-pattern>*.xhtml</url-pattern>  
      </servlet-mapping>  
      <welcome-file-list>  
           <welcome-file>pages/jsfspring.xhtml</welcome-file>  
      </welcome-file-list>  
 </web-app>  

4.Create new JSF bean name as UserBean as shown below in com.jsf.app.managedbean package

 package com.jsf.app.managedbean;  
 import java.util.logging.Logger;  
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.beans.factory.annotation.Qualifier;  
 import org.springframework.stereotype.Component;  
 import com.jsf.app.service.UserService;  
 @Component("userBean") 
 @Scope("session") 
 public class UserBean {  
      private static final Logger logger = Logger.getLogger(UserBean.class  
                .getName());  
      @Autowired  
      @Qualifier("userService")  
      public UserService userService;  
      public String getPrintMsgFromSpring() {  
           logger.info("Invoking UserService");  
           return userService.getMessage();  
      }  
 }  

5. Next create Spring Interface and Implementation in com.jsf.app.service and com.jsf.app.service.impl package respectively:
 package com.jsf.app.service;  
 public interface UserService {  
      public String getMessage();  
 }  


 package com.jsf.app.service.impl;  
 import org.springframework.stereotype.Service;  
 import com.jsf.app.service.UserService;  
 @Service("userService")  
 public class UserServiceImpl implements UserService {  
      private String name = "Voila!";  
      public String getName() {  
           return name;  
      }  
      public void setName(String name) {  
           this.name = name;  
      }  
      @Override  
      public String getMessage() {  
           return "JSF - Spring Integrtion " + name;  
      }  
 }  

6. Now Create Faces-Config.xml with following information in WEB-INF folder:
 <?xml version="1.0" encoding="UTF-8"?>  
 <faces-config 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-facesconfig_2_0.xsd"  
      version="2.0">  
      <application>  
           <locale-config>  
                <default-locale>en</default-locale>  
           </locale-config>  
           <resource-bundle>  
                <base-name>messages</base-name>  
                <var>msg</var>  
           </resource-bundle>  
           <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>  
      </application>  
 </faces-config>  

7. Also Create the applicationContext.xml in resources folder:
 <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="com.jsf.app.managedbean,com.jsf.app.service" />  
 </beans>  

8. Now create the jsf page in the webapp/pages/ folder as shown below:
 <?xml version="1.0" encoding="UTF-8"?>  
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"   
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html">  
 <h:body>  
      <h1>JSF 2.0 + Spring Example</h1>  
            #{userBean.printMsgFromSpring}  
   </h:body>  
 </html>  

9. Finally add the Log4j.xml file for logging purpose inside the resources folder as shown in below:
 <?xml version="1.0" encoding="UTF-8"?>  
 <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >  
 <log4j:configuration>  
      <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">  
           <param name="Target" value="System.out" />  
           <layout class="org.apache.log4j.PatternLayout">  
                <!-- <param name="ConversionPattern" value="[%d{ISO8601}] %-5p [%c] %m %n" />     -->  
                <param name="ConversionPattern" value="%-5p [%c] %m %n" />  
           </layout>  
      </appender>       
      <appender name="STDERR" class="org.apache.log4j.ConsoleAppender">  
           <param name="Target" value="System.err" />  
           <layout class="org.apache.log4j.PatternLayout">  
                <param name="ConversionPattern" value="[%d{ISO8601}] %-5p [%c] %m %n" />  
           </layout>  
           <filter class="org.apache.log4j.varia.LevelRangeFilter">  
                <param name="LevelMin" value="ERROR" />  
                <param name="LevelMax" value="FATAL" />  
           </filter>  
      </appender>  
      <appender name="ROLLING_FILE" class="org.apache.log4j.RollingFileAppender">  
           <!-- param name="File" value="c:/logs/miis30.log" /-->  
           <param name="File" value="jsf.log" />  
           <param name="Append" value="true" />  
           <param name="MaxFileSize" value="5120KB" />  
           <param name="MaxBackupIndex" value="5" />  
           <layout class="org.apache.log4j.PatternLayout">  
                <param name="ConversionPattern" value="[%d{ISO8601}] %-5p %m%n" />  
           </layout>  
      </appender>  
      <root>  
           <level value="ERROR" />  
           <appender-ref ref="STDERR" />  
      </root>    
      <root>  
           <level value="DEBUG" />  
           <appender-ref ref="STDOUT" />  
      </root>   
 </log4j:configuration>  

10. Finally to run the application, right click the project->maven->maven clean,
again right click project->maven->maven install, this will create the war file.
Take a war file and deploy in the tomcat server and run the server as:
 http://localhost:8088/jsf/pages/jsfspring.xhtml  

4 comments:

  1. Prabin:
    Couple of question, the component annotation is resoled by spring ok?, so wich scope can been defined in such a bean?, and the view is resolved by jsf so with the proper configuration it's can be complement with facelet, that's correct?
    Regard and thanks
    Javier

    ReplyDelete
    Replies
    1. The org.springframework.web.jsf.el.SpringBeanFacesELResolver will help annotate spring context manage bean to be used in JSF + Spring application. By default, Spring framework create Singleton scope bean, so make sure when writing web application, annotate either request or session, otherwise multiple user will use same bean.

      Delete
  2. Thanks men, it helps me!
    Question, when I build the maven project the STS not create the web.xml file, and in your tutorial I can´t see it neither. I thought that this file is necessary in the structure of a web project. thanks.

    ReplyDelete
  3. Thanks a lot!! It really helped me. I had been trying to get it working for past few days. This is just what I was looking for.

    ReplyDelete