Customize FacesServlet <url-pattern> to get rid of .xhtml extension
Asked Answered
C

3

12

I have Login.xhtml and Home.xhtml. I configured the url pattern in web.xml as follows

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

<welcome-file-list>
  <welcome-file>Login.xhtml</welcome-file>
</welcome-file-list>

When I run the whole project, the login page URL is like this http://localhost:8080/fran/Login.xhtml , here fran is my project name..

However, I would like it to be http://localhost:8080/fran/Login/ instead of http://localhost:8080/fran/Login.xhtml.

How can I achieve this? Is it possible to customize the <url-pattern> for every page to get rid of the .xhtml extension?

Conley answered 29/8, 2013 at 10:21 Comment(4)
take a look at ocpsoft.org/prettyfaces , look at the 2. Create pretty-config.xml example in the main pageGulosity
@Gulosity ..ya that ocpsoft.org/prettyfaces is a good choice.. In pretty faces is it require to configure Pretty filter in web.xmlConley
OmniFaces FacesViews offers a zero-configuration way of getting rid of .xhtml extension. It's been used at among others showcase.omnifaces.org and zeef.com.Scharf
@BalusC..Thanks for your answer..which is very easier to configure...and the documentation which is plotted there was fantastic.. anybody can understand it... i am so happy to use this plugin...thanks for suggestions..Conley
S
16

If your sole reason is to get rid of the .xhtml extension, then there are various ways depending on the JSF version you're using.

Faces 4.0

Just add the following context parameter to web.xml:

<context-param>
    <param-name>jakarta.faces.AUTOMATIC_EXTENSIONLESS_MAPPING</param-name>
    <param-value>true</param-value>
</context-param>

JSF 2.3+

JSF 2.3 offers a new API to collect all views: the ViewHandler#getViews(). Combine this with ServletRegistration#addMapping() in a ServletContextListener as below.

@FacesConfig
@WebListener
public class ApplicationConfig implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent event) {
        addExtensionLessMappings(event.getServletContext(), FacesContext.getCurrentInstance());
    }

    private void addExtensionLessMappings(ServletContext servletContext, FacesContext facesContext) {
        servletContext
            .getServletRegistrations().values().stream()
            .filter(servlet -> servlet.getClassName().equals(FacesServlet.class.getName()))
            .findAny()
            .ifPresent(facesServlet -> facesContext
                .getApplication()
                .getViewHandler()
                .getViews(facesContext, "/", ViewVisitOption.RETURN_AS_MINIMAL_IMPLICIT_OUTCOME)
                .forEach(view -> facesServlet.addMapping(view))
        );
    }
}

Effectively, this is an oneliner. Source: Arjan Tijms' Blog and The Definitive Guide to JSF.

If you're using MyFaces as JSF 2.3 implementation, then this can be transparently activated by solely the following web.xml context parameter:

<context-param>
    <param-name>org.apache.myfaces.AUTOMATIC_EXTENSIONLESS_MAPPING</param-name>
    <param-value>true</param-value>
</context-param>

Mojarra does not have an equivalent yet.

JSF 2.2-

Use OmniFaces FacesViews. It offers a zero-configuration way to achieve that by placing the view files in /WEB-INF/faces-views/ folder. Otherwise, if you intend to not modify your project structure and want to keep your view files at the usual place and still benefit of extensionless URLs, then it's a matter of adding the following context parameter:

<context-param>
    <param-name>org.omnifaces.FACES_VIEWS_SCAN_PATHS</param-name>
    <param-value>/*.xhtml</param-value>
</context-param>

In case you don't want to use OmniFaces, but rather want to homegrow your own, just look at source code of OmniFaces. It's open source under Apache 2.0 License. It's only not an oneliner.

Scharf answered 30/8, 2013 at 16:41 Comment(1)
FacesContext.getCurrentInstance() returns null for me.Referent
G
3

Take a look at prettyfaces: Pretty URLs for JavaServer Faces ,

Look at the 2. Create pretty-config.xml example in the main page

And take a look at the Chapter 2. Get Started

Gulosity answered 30/8, 2013 at 8:0 Comment(2)
ya.. that's right.. my question, Is it require to configure Pretty filter in web.xml .. In step 2(as you mentioned) is only for pretty-config.xmlconfiguration,Is this part only alone..?Conley
@Gulosity thanks for pointing out prettyfaces -- it looks like it will solve the problem I have which is making the URLs more user friendlyInvoke
G
0

Just a little complement to mr. @balusc excelent answer about MyFaces on JSF 2.3... (Edit: not really a complement as one can not complement what's complete, but just a workaround for tomcat/tomee users to deal with this tomcat bug).

Using MyFaces 2.3.6, I received a Exception talking about servlet specification and ServletContextListener:

java.lang.UnsupportedOperationException: Section 4.4 of the Servlet 3.0 specification does not permit this method to be called from a ServletContextListener that was not defined in web.xml, a web-fragment.xml file nor annotated with @WebListener

Following the stack i saw this line:

at org.apache.myfaces.webapp.StartupServletContextListener.contextInitialized(StartupServletContextListener.java:103)

And after adding that listener to web.xml all worked fine:

<listener>
    <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
</listener>
Garnierite answered 27/12, 2020 at 4:13 Comment(2)
This happens only when you're using Tomcat instead of a normal JEE server and this is actually a bug in Tomcat itself.Scharf
Impressive! I was using TomEE 8.0.5. indeed. I checked. MyFaces has the correct web-fragment, with this exact Listener. Really a tomcat bug. Thank you, sir.Sosthena

© 2022 - 2024 — McMap. All rights reserved.