Java EE: Creating SEO Friendly URL in JSF Applications

Search Engine Optimization in Java EE or any other programming language starts from the basics like the URL, the page title and other metadata in the head section of the page. In this post I will discuss how to create an SEO friendly URL and process such URL when users of your application make requests. Let use an eCommerce like for example:

The URL above is very SEO friendly compared to say:

One URL says a lot about what the page is about even to humans whereas the other says practically nothing.

I created a simple web application Netbeans IDE 8.1 to demonstrate the two steps involved:

  1. We need to generate the SEO friendly URL at the time the product is been saved in the database. Which means your database table should have a column like ‘PRODUCT_SEO_URL’ or something like that to hold this URL
  2. We need to process the URL to extract the unique id of the product to be used in our query to retrieve other details about the product for display.

 The application created is a simple JSF application (Mojarra 2.2, with primefaces 5.0 for quick prototyping). It has a backing bean where I simulate the generation of the URL and a servlet that processes incoming GET requests:

Let’s start from the first xhtml page:


// index.xhtml

<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ""> <html xmlns="" xmlns:h="" xmlns:p=""> <h:head> <title>SEO Friendly URL</title> </h:head> <h:body> <center> <h1>Enter any text to get SEO friendly equivalent:</h1> <h:form id="seoUrlForm"> <h3>SEO Friendly: <span style="color: green;">#{seoURLController.seoUrl}</span></h3> <p:panelGrid columns="2"> <h:outputLabel value="Any Text"/> <p:inputText value="#{seoURLController.text}" style="width: 500px;"/> <h:outputLabel value=""/> <p:commandButton value="Convert to SEO Friendly" action="#{seoURLController.convert}" ajax="false"/> </p:panelGrid> </h:form> </center> </h:body> </html>

This page gives you a simple text field to enter any text and it will generate the SEO friendly equivalent


Now let's examine the backing bean



import; import javax.faces.view.ViewScoped; import javax.inject.Named;

/** *

  • @author Tunde Michael

*/ @Named(value = "seoURLController") @ViewScoped public class SEOURLController implements Serializable {

private String text;
private String seoUrl;
private String productId;

 * This method converts just about any text
 * to it's SEO friendly equivalent
public void convert() {
    if (text != null &amp;&amp; !text.isEmpty()) {
        // trim spaces at the edges, convert all to lowercase and
        // remove all non-alpha numeric characters
        String url = text.trim().toLowerCase().replaceAll("[^a-z0-9_\\s-]", ""); 
        // change all multiple white spaces to single white space
        url = url.replaceAll("[\\s-]+", " ");
        // replace all the single white spaces with a dash
        seoUrl = url.replaceAll("[\\s]", "-");
        // at this point we will save the product in the database 
        // with SEO friendly URL appended with the product ID at the end
        // Let's say the product ID is 12345
        Long productId = 12345L;
        seoUrl += "-" + productId; 
        System.out.println("SEO Friendly URL --&gt;  " + seoUrl);
    } else {
        seoUrl = "Please enter text to convert";

 * The pre-render view method to retrieve the 
 * product details from the database using the 
 * product ID
public void retrieveProductFromDatabase(){
    // retrieve product from the database here
    System.out.println("Product Retrieved using ID --&gt;  " + this.productId);


public String getText() {
    return text;

public void setText(String text) {
    this.text = text;

public String getSeoUrl() {
    return seoUrl;

public void setSeoUrl(String seoUrl) {
    this.seoUrl = seoUrl;

public String getProductId() {
    return productId;

public void setProductId(String productId) {
    this.productId = productId;


 This code above has method

public void convert();

 which generate the SEO friendly URL from the text enter by the user. The method uses regular expression and it's very self explanatory if you read the comments. 


The next step is processing requests from our users. This we will use a Servlet with URL mapping:

@WebServlet(name = "SeoUrlServlet", urlPatterns = {"/"})
public class SeoUrlServlet extends HttpServlet

Look at the value of the urlPatterns attribute, this means all non-jsf requests (requests without .xhtml, FacesServlet will handle jsf requests) will be passed through this servlet and we can then process the URI and forward to the appropriate JSF page without redirecting the browser thereby making the URL still look frindly. Let's see the full Servlet code:



import; import java.util.Arrays; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;

/** *

  • @author Tunde Michael */ @WebServlet(name = "SeoUrlServlet", urlPatterns = {"/"}) public class SeoUrlServlet extends HttpServlet {


    • Handles the HTTP GET method.

    • @param request servlet request

    • @param response servlet response

    • @throws ServletException if a servlet-specific error occurs

    • @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { String uri = request.getRequestURI(); String[] params = uri.split("/"); System.out.println("URI -- " + uri); System.out.println("Params -- " + Arrays.toString(params)); // to extract the product name from the uri. We expect the // product name to be the last part of the uri String productName = params[params.length - 1]; System.out.println("Product Name --> " + productName); // let's extract the product ID from the product name String productId = productName.substring(productName.lastIndexOf("-") + 1); System.out.println("PID --> " + productId); // It's good to check here if there is a valid product with this ID // and if not redirect to list of products. // if all goes well, let's render response here request.getRequestDispatcher("/product.xhtml?pid=" + productId) .forward(request, response);

      } catch (Exception e) { // Handle exceptions to give your users safe landing // expecially Array index out of bound exception }




The request dispatcher will forward the GET request to the product.xhtml page with the product ID extracted from the URl without informing the browser.  Let's see the product.xhtml page.


// product.xhtml

<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ""> <html xmlns="" xmlns:h="" xmlns:f=""> <h:head> <title>Product Detail Page</title> <f:metadata> <f:viewParam name="pid" value="#{seoURLController.productId}"/> <f:event type="preRenderView" listener="#{seoURLController.retrieveProductFromDatabase}"/> </f:metadata> </h:head> <h:body> <center> <h1>Product Detail Page</h1> <h1>Product ID: <h:outputText value="#{seoURLController.productId}"/> </h1> </center> </h:body> </html>

This page has a viewParam tag to extract the 'pid' coming from the request dispatcher and a preRenderView method 'retrieveProductFromDatabase' to simulate the retrieval of the product details which is what you would most likely do before the page is displayed.

I suggest you download the application from Github and diployed to have a better understanding of how this works. 

I tested the application on Glassfish 4.1. There is no datasource so everything should work fine.


You have a better idea how this can or should be done please lemme know. Contact Tunde Michael