Why does <h:link> change destination extension from .html to .xhtml?
Asked Answered
P

1

6

I'm using JSF 2.1 and I'm experiencing some problems with the <h:link> tag. I'm trying to have the link's outcome point from my XHTML file to a plain HTML file. However, when I run my web application, the .html extension in link's generated URL is automatically converted to a .xhtml extension.

Here is my Facelet file:

<h:body>
    <h:form>        
        <h:link value="animation" outcome="#{contentForm.ccAnimationLink}"/>            
    </h:form>
<h:body>

Here is my contentForm bean:

package my.app.content;

import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;

@ManagedBean
@RequestScoped
public class ContentForm implements Serializable {
    private static final long serialVersionUID = -8463354828156798513L; 
    private String ccAnimationLink = "";    

    @PostConstruct
    public void init() {        
        ccAnimationLink = "/content/cc/CC_animation/story.html";        
    }

    public String getCcAnimationLink() {
        return ccAnimationLink;
    }

    public void setCcAnimationLink(String ccAnimationLink) {
        this.ccAnimationLink = ccAnimationLink;
    }
}

Now, when I run this application, I get the following error:

Unable to find matching navigation case from view ID '/content/modifiedcc.xhtml' for outcome '/content/cc/CC_animation/story.html'

I made sure that I had the URL correct, so I created a story.xhtml file in that location as well. With that file there it runs without errors.

If I pull the source for the generated page, I can see that the <h:link> was correctly changed to an "a href" tag, as follows:

<a href="/MyWebApp/content/cc/CC_animation/story.xhtml">animation</a>

For some reason though the URL changes from story.html, like I have it in my bean, to story.xhtml.

How can I make sure that it stays as story.html and not change it to xhtml?

Here is my web.xml file as well:

  <display-name>MyWebApp</display-name>
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>
  <welcome-file-list>
    <welcome-file>jsf/login/login.xhtml</welcome-file>
  </welcome-file-list>
  <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>
</web-app>

I tried adding the following to the web.xml, this didn't make a difference:

  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>

I'm sure this has a very simple solution which I'm just missing right now. Help would be highly appreciated. I hope the question is clear.

Padraig answered 1/12, 2013 at 8:7 Comment(4)
Is the file name story.html or story.xhtml?Connote
@peeskillet - I want it to link to story.html, but my jsf is addament to link it to story.xhtml. I created an empty story.xhtml file just so that I don't get errors, so that I can pull the source from the browser. In a perfect world there shouldn't be a story.xhtml file.Padraig
I'm not sure if this will work or not, but try adding another <servlet-mapping> element, mapping to url pettern .*htmlConnote
@peeskillet - I tride that as well, didn't make a difference. I've added that to my question above.Padraig
M
6

JSF 2.0+ has introduced <h:link> component that takes a navigation case outcome in its outcome attribute and autogenerates the right URL on its own. This is why you had the error without adding yet another mapping for the faces servlet: just reread the error. It is useful for creation of inter-JSF application navigation.

Alternatively, there has always been a <h:outputLink> component that takes an URL in its value attribute instead. It is useful for creation of navigation external to a JSF application.

Be sure to read the classics from BalusC on the issue: When should I use h:outputLink instead of h:commandLink?.

That said, consider the following components:

<h:link outcome="/destination" value="link" />
<h:outputLink value="/destination.html">
    outputLink
</h:outputLink>

The former component will translate its outcome into an actual URL, by appending a faces servlet mapping, while the latter one will leave its value as-is.

So, your problem will be solved by using the following component:

<h:outputLink value="#{contentForm.ccAnimationLink}">
    Animation
</h:outputLink>
Magician answered 1/12, 2013 at 9:30 Comment(3)
Thank you! You are my new favorite person! I would've given you an up vote on your answer, but apparently my reputation is too low to know what a good answer is :PPadraig
You're welcome! And thank you. One final piece of advice is to leave only one mapping for the faces servlet, *.xhtml, and remove the rest altogether.Magician
You can also just use <a href="#{contentForm.ccAnimationLink}">.Hackett

© 2022 - 2024 — McMap. All rights reserved.