The flexibility offered by Spring Framework to pick third-party products is one of the core value propositions of Spring and Spring supports integration with third-party presentation frameworks. While Spring's presentation layer framework—Spring MVC, brings the maximum extent of flexibility and efficiency to the development of web applications, Spring lets you integrate most popular presentation frameworks.
Spring can be integrated with far too many of Java's web frameworks to be included in this chapter, and only the most popular ones, JSF and Struts, will be explained.
A JSF web application can be easily integrated with Spring by loading a Spring context file within web.xml
(through a context loader listener). Since JSF 1.2, Spring's SpringBeanFacesELResolver
object reads Spring beans as JSF managed beans. JSF only deals with the presentation tier and has a controller named FacesServlet
. All we need to do is register FacesServlet
in the application deployment descriptor or web.xml
(in this section, we use JavaConfig to register it) and map any request with the desired extension (.xhtml
here) to go through FacesServlet
.
First, we should include the JSF API and its implementation in the project dependencies:
<properties> <spring-framework-version>4.1.6.RELEASE</spring-framework-version> <mojarra-version>2.2.12</mojarra-version> </properties> ... <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-api</artifactId> <version>${mojarra-version}</version> </dependency> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-impl</artifactId> <version>${mojarra-version}</version> </dependency> ...
The dispatcher Servlet initializer is the location to register FacesServlet
. Notice that we set a mapping request to FacesServlet
here. Since we use JavaConfig to register settings, we register FacesServlet
in the AnnotationConfigDispchServletInit
class, as follows:
@Configuration @Order(2) public class AnnotationConfigDispchServletInit extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { AppConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "*.xhtml" }; } @Override protected Filter[] getServletFilters() { return new Filter[] { new CharacterEncodingFilter() }; } @Override public void onStartup(ServletContext servletContext) throws ServletException { // Use JSF view templates saved as *.xhtml, for use with // Facelets servletContext.setInitParameter("javax.faces.DEFAULT_SUFFIX", ".xhtml"); // Enable special Facelets debug output during development servletContext.setInitParameter("javax.faces.PROJECT_STAGE", "Development"); // Causes Facelets to refresh templates during development servletContext.setInitParameter("javax.faces.FACELETS_REFRESH_PERIOD", "1"); servletContext.setInitParameter("facelets.DEVELOPMENT", "true"); servletContext.setInitParameter("javax.faces.STATE_SAVING_METHOD", "server"); servletContext.setInitParameter( "javax.faces.PARTIAL_STATE_SAVING_METHOD", "true"); servletContext.addListener(com.sun.faces.config.ConfigureListener.class); ServletRegistration.Dynamic facesServlet = servletContext.addServlet("Faces Servlet", FacesServlet.class); facesServlet.setLoadOnStartup(1); facesServlet.addMapping("*.xhtml"); // Let the DispatcherServlet be registered super.onStartup(servletContext); } }
Another important setting is configuring the listener to read the faces-config
XML file. By default, it looks for faces-config.xml
under the WEB-INF
folder. By setting org.springframework.web.jsf.el.SpringBeanFacesELResolver
as ELResolver
, we access Spring POJOs as JSF beans. By registering DelegatingPhaseListenerMulticaster
, any Spring's bean that implements the PhaseListener
interface, JSF's phase events will be broadcasted to corresponding implemented methods of PhaseListener
in the Spring's bean.
Here is the faces-config.xml
file:
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd" version="2.2"> <application> <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver> </application> <lifecycle> <phase-listener>org.springframework.web.jsf.DelegatingPhaseListenerMulticaster</phase-listener> </lifecycle> </faces-config>
In JSF, we can define beans with a session, request, or application scope and the bean values retained within the specific scope. Setting the eager
flag to false
implies lazy initialization, which creates beans when the first request arrives, whereas true
implies creating the beans on startup. The code for the OrderBean
class is:
@ManagedBean(name = "orderBean", eager = true) @RequestScoped @Component public class OrderBean { private String orderName; private Integer orderId; @Autowired public OrderServiceorder Service; public String placeAnOrder(){ orderName=orderService.placeAnOrder(orderId); return "confirmation"; } public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } public Integer getOrderId() { return orderId; } public void setOrderId(Integer orderId) { this.orderId = orderId; } }
Also, these beans are available in the presentation layer to interact with the backend. On the first screen (order.xhtml
), we call the bean's method (placeAnOrder
):
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:body> <h3>input: JSF 2 and Spring Integration</h3> <h:form id="orderForm"> <h:outputLabel value="Enter order id:" /> <h:inputText value="#{orderBean.orderId}" /> <br/> <h:commandButton value="Submit" action="#{orderBean.placeAnOrder}"/> </h:form> </h:body> </html>
The method returns a confirmation as a string and specify navigation in the action
attribute means the next page is confirmation.xhtml
, which looks like this:
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:body> <h3>Confirmation of an order</h3> Product Name: #{orderBean.orderName} </h:body> </html>