Faces Navigation not really working in JSF2

Joergi picture Joergi · Mar 21, 2012 · Viewed 11.2k times · Source

I'm using JSF 2.0

this is my faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is not required if you don't need any extra configuration. -->
<faces-config version="2.0" 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">

    <navigation-rule>
        <from-view-id>/pages/test/test.html</from-view-id>
        <navigation-case>
            <from-outcome>write</from-outcome>
            <to-view-id>/pages/test/test-write.html</to-view-id>
        </navigation-case>

    </navigation-rule>

</faces-config>

The TestController.java

@ManagedBean(name="testController")
@SessionScoped
public class TestController implements Serializable {

    private static final long serialVersionUID = -3244711761400747261L; 

    public String test() {


        return "write?faces-redirect=true";
}

in my test.xhtml file

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    template="/WEB-INF/templates/default.xhtml">
    <ui:define name="content">
            <h:form>
                    <h:commandButton action="#{testController.test()}" value="test" />  
            </h:form>
    </ui:define>

</ui:composition>

and this is my web.xml

<web-app 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-app_3_0.xsd"
    version="3.0">
    <display-name>Bachelor Demo</display-name>      

    <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>*.html</url-pattern>
    </servlet-mapping>
</web-app>

What am I missing?

Answer

BalusC picture BalusC · Mar 21, 2012

The view IDs should not contain the FacesServlet mapping. It should represent the physical file path/name. Change .html to .xhtml. You should also remove ?faces-redirect=true and instead add a <redirect /> to the <navigation-case>.

<navigation-rule>
    <from-view-id>/pages/test/test.xhtml</from-view-id>
    <navigation-case>
        <from-outcome>write</from-outcome>
        <to-view-id>/pages/test/test-write.xhtml</to-view-id>
        <redirect />
    </navigation-case>
</navigation-rule>

By the way, this is the old JSF 1.x style. Are you aware of the new JSF2 implicit navigation? You could just return "/pages/test/test-write.xhtml?faces-redirect=true".

public String test() {
    return "/pages/test/test-write.xhtml?faces-redirect=true";
}

No need for bloated XML navigation cases anymore.

Further, if your action method is really not doing anything else, then you can also just put exactly that return value in the action attribute instead.

<h:commandButton ... action="/pages/test/test-write.xhtml?faces-redirect=true" />

Even more, if it's plain page-to-page navigation, rather use <h:link> instead. It's more SEO friendly as searchbots don't index POST forms:

<h:link ... outcome="/pages/test/test-write.xhtml" />