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

facelets, hyperlink, jsf

Solution

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>

Problem

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.

Original source

Related problems