Search code examples
model-view-controllerspringmyfacesgeronimo

Can Spring MVC and MyFaces work together?


I have a question. A have a trivial application. I want to use Spring MVC and in the JSP page use some facelets (if say I it well). But I'm unable to do it. I'm using Geronimo. In the Geronimo there is the MyFaces JSF implementation. I don't now, how shall I write proper faces-config.xml, or what is missing. When I'm opening the page in browser, the Geronimo throws IllegalStateEcxeption: No Factories configured for this Application. This happens if the faces-initialization does not work at all.

I have created a controler in the application:

@Controller
public class BasicController {
    @RequestMapping("/")
    public ModelAndView index() {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("main");
        return mv;
    }

    @ModelAttribute("appVersion")
    public String getVersion() {
        return Version.VERSION + " (" + Version.BUILD_TIME + ")";
    }
}

I have declared dispatcher servlet and faces servlet in web.xml:

<servlet>
    <servlet-name>sd</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>sd</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
<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>*.jsp</url-pattern>
</servlet-mapping>
<listener>
    <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
</listener>

I have configured dispatcher servlet in WEB-INF/sd-servlet.xml:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/pages/" />
    <property name="suffix" value=".jsp" />
</bean>
<context:component-scan base-package="eu.barbucha.trackAnniversaries.webLayer"/>
<mvc:annotation-driven/>
<mvc:resources location="/files/" mapping="/files/**"/>

My faces-config.xml contains just one daclaration:

<faces-config>
    <application>
        <el-resolver>
            org.springframework.web.jsf.el.SpringBeanFacesELResolver
        </el-resolver>
    </application>
</faces-config>

And finally I have written a JSP page:

<?xml version='1.0' encoding='utf-8'?>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <title>Title</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <link rel="stylesheet" href="files/basic.css" media="all"/>
</head>
<body>
    <p>Example <h:outputText value="text"/>.</p>
    <hr/>
    <i>${appVersion}</i>
</body>
</html>

Solution

  • Yes, they really can. But there are several mistakes in above mentioned configuration.

    1. The file is WEB-INF/pages/main.jsp, but the JSF servlet must be mapped to *.jsf and the suffix in the view resolver must be the same: .jsf. MyFaces changes the suffix automatically.
    2. Then it does not work yet. You get IllegalStateException, that there is not any application context. The proper configuration of Spring consists of two files. First is the application context and the second configuration file for dispatcher servlet. If you just create an empty application context file, the entire Geronimo container may freeze.

    You shall write configuration in two files. Both of them you put into WEB-INF directory. First is 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:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
        <context:annotation-config />
        <context:component-scan base-package="eu.barbucha.trackAnniversaries.webLayer"/>
    </beans>
    

    And the second is configuration for servlet called sd, also sd-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:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
        <!-- The name I've choosen SD = Spring Dispatcher (Servlet) -->
        <context:component-scan base-package="eu.barbucha.trackAnniversaries.webLayer"/>
        <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
            <property name="prefix" value="/WEB-INF/pages/" />
            <property name="suffix" value=".jsf" />
        </bean>
        <mvc:annotation-driven/>
        <mvc:resources location="/files/" mapping="/files/**"/>
    </beans>
    

    Used solution (with JSP) is JSF 1.2 compatible. If you want to use facelet instead JSP, you need to use JSF 2.0 compatible implementation, e.g. MyFaces 2.0.