Basic JSF and spring integration
The Following steps outline how to build a simple dynamic webproject that integrates JSF and spring web context.
Step1: Create jsf2.0 faceted project, select the mojorra library as mentioned in previous posting
Step2: Best not to get into all the hard work manually handling all those transitive dependencies . So download the maven eclipse integration plugin into your eclipse IDE
Step 3: Once eclipse restarts, right click on your simple web project, and use the convert>convert to mavenprojectto above project. This will create a basic pom.xml file in the root of your project.
Step 4: Add the essential spring dependencies into the pom like this. I have included JSF2, Spring 3 and JSR-330 (DI) for the @inject annotation, and tomcars dependencies.
projectxmlns="
modelVersion4.0.0</modelVersion
groupIdjsf-spring</groupId
artifactIdjsf-spring</artifactId
version0.0.1-SNAPSHOT</version
descriptionsample jsf integration with spring framework </description
build
sourceDirectorysrc</sourceDirectory
plugins
plugin
artifactIdmaven-compiler-plugin</artifactId
version3.1</version
configuration
source1.6</source
target1.6</target
</configuration
</plugin
</plugins
</build
dependencies
dependency
groupIdorg.springframework</groupId
artifactIdspring-core</artifactId
version3.2.4.RELEASE</version
</dependency
dependency
groupIdorg.springframework</groupId
artifactIdspring-web</artifactId
version3.2.4.RELEASE</version
</dependency
<!-- JSR-330 -->
dependency
groupIdjavax.inject</groupId
artifactIdjavax.inject</artifactId
version1</version
</dependency
<!-- JSF -->
dependency
groupIdcom.sun.faces</groupId
artifactIdjsf-api</artifactId
version2.2.0</version
</dependency
dependency
groupIdcom.sun.faces</groupId
artifactIdjsf-impl</artifactId
version2.2.0</version
</dependency
dependency
groupIdjavax.servlet</groupId
artifactIdjstl</artifactId
version1.2</version
</dependency
dependency
groupIdjavax.servlet</groupId
artifactIdjavax.servlet-api</artifactId
version3.0.1</version
</dependency
dependency
groupIdjavax.servlet.jsp</groupId
artifactIdjavax.servlet.jsp-api</artifactId
version2.2.1</version
</dependency
<!-- EL -->
dependency
groupIdorg.glassfish.web</groupId
artifactIdel-impl</artifactId
version2.2</version
</dependency
<!--Tomcat 6 needs this -->
dependency
groupIdcom.sun.el</groupId
artifactIdel-ri</artifactId
version1.0</version
</dependency
</dependencies
</project
Step 5: Edit the faces-config.xml file to add the spring jsf resolver
<?xmlversion="1.0"encoding="UTF-8"?>
faces-config
xmlns="
xmlns:xsi="
xsi:schemaLocation="
version="2.2"
application
el-resolver
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver
</application
</faces-config
Step6: Edit your web.xml to add the spring listeners, so that your web.xml looks something like this
<?xmlversion="1.0"encoding="UTF-8"?>
web-appxmlns:xsi="
display-namejsf-spring</display-name
<!-- Spring Context Configuration' s Path definition -->
context-param
param-namecontextConfigLocation</param-name
param-value
/WEB-INF/applicationContext.xml
</param-value
</context-param
<!-- Change to "Production" when you are ready to deploy -->
context-param
param-namejavax.faces.PROJECT_STAGE</param-name
param-valueDevelopment</param-value
</context-param
servlet
servlet-nameFaces Servlet</servlet-name
servlet-classjavax.faces.webapp.FacesServlet</servlet-class
load-on-startup1</load-on-startup
</servlet
servlet-mapping
servlet-nameFaces Servlet</servlet-name
url-pattern*.xhtml</url-pattern
</servlet-mapping
context-param
descriptionState saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description
param-namejavax.faces.STATE_SAVING_METHOD</param-name
param-valueclient</param-value
</context-param
context-param
param-namejavax.servlet.jsp.jstl.fmt.localizationContext</param-name
param-valueresources.application</param-value
</context-param
listener
listener-classcom.sun.faces.config.ConfigureListener</listener-class
</listener
<!-- Add Support for Spring -->
listener
listener-class
org.springframework.web.context.ContextLoaderListener
</listener-class
</listener
listener
listener-class
org.springframework.web.context.request.RequestContextListener
</listener-class
</listener
</web-app
Step 7: By default the maven dependencies are not automatically picked up in the WAR packajing. So ensure the project picks up the maven dependencies do the following
if you are running the project as dynamic web project on a server within eclipse, then you should open the project properties (right click > properties) and select "Deployment Assembly". There click "add", select "build path entries", and choose "maven dependencies". This will instruct WTP to send the maven dependencies to the server dir.
Leave the deployment assembly configlooking like this
Step 8: Add spring web context xml file mirroring the name as per the web.xml configuration you use. With spring you can have many metameta data file not just one.
applicationContext.xml in WEB-INF directory
beansxmlns="
xmlns:xsi="
xmlns:context="
xsi:schemaLocation="
<!-- look for annotation based components -->
context:component-scanbase-package="com.softwood"/>
beanid="sampleBo"class="com.softwood.sample.bo.impl.SampleBoImpl"</bean
</beans
In this example I shall be using annotations and java config in spring as well as traditional xml config.
The first example uses an bean expressed as meta data in the <bean> tag the traditional way. The context:component-scantag asks the spring runtime to parse the base package directory (you can do filters on this etc see the spring annotation sections in the user guide) looking for spring annotations on your classes.
Step 9 : First Example. This next step covers more than way to hook jsf into spring. First I create an interface for the Spring business object (Bo) like this
(a)– interface definition
package com.softwood.sample.bo;
publicinterfaceSampleBo {
public String getMessage();
}
(b)– bus object implementation
In the first example the bean is expressed in the applicationContext.xml and is parsed at load time. The first implementation is a plain POJO – see declaration in step 8 above.
packagecom.softwood.sample.bo.impl;
importcom.softwood.sample.bo.SampleBo;
//standard spring bean implementing logic
publicclassSampleBoImplimplementsSampleBo {
public String getMessage() {
}
}
(c)– declare JSF backing bean in faces-config.xml
<?xmlversion="1.0"encoding="UTF-8"?>
faces-config
xmlns="
xmlns:xsi="
xsi:schemaLocation="
version="2.2"
application
el-resolver
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver
</application
managed-bean
managed-bean-namesampleBean</managed-bean-name
managed-bean-classcom.softwood.sample.jsfbean.SampleBean</managed-bean-class
managed-bean-scopesession</managed-bean-scope
managed-property
property-namesampleBo</property-name
value#{sampleBo}</value
</managed-property
</managed-bean
</faces-config
(d)– declare Sample bean
packagecom.softwood.sample.jsfbean;
importcom.softwood.sample.bo.SampleBo;
//standard JSF backing bean but uses spring DI to get the business object
publicclassSampleBeanimplementsjava.io.Serializable {
//later inject in faces-config.xml
SampleBosampleBo;
publicvoidsetSampleBo(SampleBosampleBo) {
this.sampleBo = sampleBo;
}
publicSampleBogetSampleBo() {
returnthis.sampleBo;
}
public String printMsgFromSpring() {
returnsampleBo.getMessage();
}
}
(e)Add the facelet driver web page
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"
"
htmlxmlns="
xmlns:h="
h:body
h1JSF 2.0 + Spring Example</h1
#{sampleBean.printMsgFromSpring()}
</h:body
</html
(f)Run up the application and goto the web page and you should a response like below
Your first working sample of JSF and spring DI injection into jsf bean. However this is not quite ideal as you have two runtime contexts to work in, and JSF backing one and spring one, which is less that ideal
The following other examples end up showing how this can be consolidated and drop the jsf backing beans and just the spring container for holding the backing state for JSF.
Step 10: Other examples showing different approaches
I tried a couple of other approaches to make sure each worked.
My example project has ended up looking something like this in the project explorer, with one Sample#BoImpl per approach so you can see each option /attempt readily
We have done the first example – mixed mode jsf and spring contexts working.
Example 2: jsf backing bean expressed as spring component using annotations. The sample2bean is defined as Spring @Component, and given session scope. It continues to use spring DI to get a reference to the same sampleBo bean as used in the step 9 above.
packagecom.softwood.sample.jsfbean;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.context.annotation.Scope;
importorg.springframework.stereotype.Component;
importcom.softwood.sample.bo.SampleBo;
//declares jsf bean as spring component in the spring container
@Component ("sample2Bean")
@Scope("session")
public class Sample2Bean {
@Autowired //injects spring service using spring DI
SampleBo sample2Bo;
public void setSampleBo(SampleBosampleBo) {
this.sample2Bo = sampleBo;
}
publicSampleBogetSampleBo() {
return this.sample2Bo;
}
public String printMsgFromSpring() {
return sample2Bo.getMessage();
}
}
And business object declared a spring service now within the spring container
packagecom.softwood.sample.bo.impl;
importorg.springframework.stereotype.Service;
importcom.softwood.sample.bo.SampleBo;
//standard spring bean implementing logic
@Service ("sample2Bo")
public class Sample2BoImpl implements SampleBo {
public String getMessage() {
return "spring @annotation: JSF 2 + Spring Integration";
}
}
And xhtml – which uses the EL to lookup the backing bean from spring container
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"
"
htmlxmlns="
xmlns:h="
h:body
h1JSF 2.0 + Spring Example</h1
#{sample2Bean.printMsgFromSpring()}
</h:body
</html
What this shows is that you can store the jsf bean as a component in the spring container
I did a variant of 2, sample2refService where the xhtml directly looks up a Bo declared as a spring @Service as well which works !
Example 3. Using standard JSR 330 annotations. This example just replaces the spring @component and @Autowired annotations with the JSR 330 standard DI equivalents
packagecom.softwood.sample.jsfbean;
importjavax.inject.Inject;
importjavax.inject.Named;
importorg.springframework.context.annotation.Scope;
importcom.softwood.sample.bo.SampleBo;
@Named ("sample3Bean")
@Scope("session") //need this, JSR-330 in Spring context is singleton by default
public class Sample3Bean implements java.io.Serializable {
@Inject
SampleBo sample3Bo;
public void setSampleBo(SampleBosampleBo) {
this.sample3Bo = sampleBo;
}
publicSampleBogetSampleBo() {
return this.sample3Bo;
}
public String printMsgFromSpring() {
return sample3Bo.getMessage();
}
}
And the Bo expressed using @Named
packagecom.softwood.sample.bo.impl;
importjavax.inject.Named;
importcom.softwood.sample.bo.SampleBo;
//standard spring bean implementing logic
@Named ("sample3Bo")
public class Sample3BoImpl implements SampleBo {
public String getMessage() {
return "javax @Named annotation: JSF 2 + Spring Integration";
}
}
Which shows the following in the browser
Example 4 : This example drops the jsf like backing bean approach and directly looks up the spring service business object. Here the business object is declared using JSR-330 @Named annotation
packagecom.softwood.sample.bo.impl;
importjavax.inject.Named;
importorg.springframework.context.annotation.Scope;
importcom.softwood.sample.bo.SampleBo;
//standard JSR-330 implementing logic
@Named ("sample4Bo")
@Scope("session") //need this, JSR-330 in Spring context is singleton by default
public class Sample4BoImpl implements SampleBo {
public String getMessage() {
return "direct reference spring Bo - javax @Named annotation: JSF 2 + Spring Integration";
}
}
With xhtml file doing EL lookup for the Bo directly
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"
"
htmlxmlns="
xmlns:h="
h:body
h1JSF 2.0 + Spring Example</h1
#{sample4Bo.getMessage()}
</h:body
</html
Example 5 : looking up a spring controller
In this example we declare the Bo as spring controller
packagecom.softwood.sample.bo.impl;
importorg.springframework.stereotype.Controller;
importcom.softwood.sample.bo.SampleBo;
//standard spring bean implementing logic
@Controller ("sample5Controller")
public class Sample5BoImpl implements SampleBo {
public String getMessage() {
return "spring controller @annotation: JSF 2 + Spring Integration";
}
}
With xhtml like this
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"
"
htmlxmlns="
xmlns:h="
h:body
h1JSF 2.0 + Spring Example</h1
#{sample5Controller.getMessage()}
</h:body
</html
Which renders this in the browser
This pattern is essentially the same pattern now that grails would use where the web page invokes a controller, which can itself be injected with a service using standard grails DI.