10

I'm trying to follow the pattern at Design Patterns web based applications. It all works fine part from when it comes to maping "root" URLs.

I'd like to put all requests through the "Front Controller" so I've put

<servlet-mapping>
    <servlet-name>ControllerServlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

in the web.xml. Stepping through with Netbeans shows the request coming in, and the Action working OK, but then the line

request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);

ALSO gets caught by the controller, it goes to the Action again and it all fails.

I can make it work by not going from the URL root e.g.

  <servlet-mapping>
        <servlet-name>ControllerServlet</servlet-name>
        <url-pattern>/pages/*</url-pattern>
    </servlet-mapping>

But that isn't what I want. Is there any way to make it work with "root" URLs?

Community
  • 1
  • 1
Mark
  • 1,754
  • 3
  • 26
  • 43

4 Answers4

8

The /* URL pattern covers everything, also the forwarded JSP files and static resources like CSS/JS/images. You don't want to have that on a front controller servlet.

Keep your controller servlet on a more specific URL pattern like /pages/*. You can achieve the functional requirement of getting rid of "/pages" in the URL by grouping the static resources in a common folder like /resources and creating a Filter which is mapped on /* and does the following job in the doFilter() method:

HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());

if (path.startsWith("/resources/")) {
    // Just let container's default servlet do its job.
    chain.doFilter(request, response);
} else {
    // Delegate to your front controller.
    request.getRequestDispatcher("/pages" + path).forward(request, response);
}

A forwarded JSP resource will by default not match this filter, so it will properly be picked up by the container's own JspServlet.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks for the replies, it looks complex so it's going to take me a while to get to filters, for now I'll just leave everything in /pages/ – Mark Jan 18 '12 at 19:06
  • You can match extensionless requests with path.match("^.*\\/[^\\.]*$") and forward that to your front controller. – Ring Feb 05 '14 at 18:09
  • 1
    @user2418306: removing the context path prefix from the URI. – BalusC Jan 23 '16 at 15:14
3

Why do we need to map each and every URL. In case you need to map all the URL, you might need skip URL in the filter.

   <filter>
    <display-name>SessionFilter</display-name>
    <filter-name>SessionFilter</filter-name>
    <filter-class>com.colabcom.goshare.app.base.filter.SessionFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>sessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

In Your Filter,

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String url = request.getServletPath();
        boolean allowedRequest = Utility.filterURL(url, avoidUrls);
        if(allowedRequest){
            chain.doFilter(request, response);
        }else{
            //Main Filter Code           
        }

Utility Class to filter your URL:

 public static boolean filterURL(String str, List<String> avoidURLList) {
    boolean exist = false;

    if(avoidURLList == null){
        return exist;
    }
    for (int i = 0; i < avoidURLList.size(); i++) {
        if (str.contains(avoidURLList.get(i))) {
            exist = true;
            break;
        }
    }
    return exist;
}

Else you can map specific URL in your web.xml like

<filter-mapping>
    <filter-name>sessionFilter</filter-name>
    <url-pattern>*.action</url-pattern>
  </filter-mapping>
Sanjay Kumar
  • 1,474
  • 14
  • 22
  • Thanks for the replies, it looks complex so it's going to take me a while to get to filters, for now I'll just leave everything in /pages/ – Mark Jan 18 '12 at 19:06
0

You can extend the DefaultServlet of your web server.The extended servlet will be your front controller. In the doGET or doPOST method forward your static pages to the super class. DefaultServlet is the servlet that is mapped to url "/" by default. I have used it with jetty server but it can be implemented in tomcat as well.

public class FrontController extends DefaultServlet {

@Override
public void init() throws UnavailableException {
    super.init();
}

@Override
protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {

    String uri = request.getRequestURI();

    /*
     * if request is trying to access inside /static then use the default
     * servlet. YOU CAN USE YOUR OWN BUSINESS LOGIC TO FORWARD REQUESTS 
     * TO DEFAULTSERVLET
     */
    if (uri.startsWith("/static/")) {

        super.doGet(request, response);
        return;
    } else {

        // else use your custom action handlers
    }
}

}

In the above code samples I have forwarded all the requests starting with /static/ to the default servlet to process. In this way you can map the FrontController to "/" level .

<servlet>
<description></description>
<display-name>FrontController</display-name>
<servlet-name>FrontController</servlet-name>
<servlet-class>FrontController</servlet-class>

<servlet-mapping>
<servlet-name>FrontController</servlet-name>
<url-pattern>/</url-pattern>

Partha Pal
  • 300
  • 1
  • 5
  • Does this bind your solution to a specific container? In other words, once I write this code into my application am I then stuck with Tomcat or Jetty or whatever from then on, until I later have to come back and change this code? – Ring Feb 05 '14 at 17:05
0

the /* url pattern matches all servlets, jsp and static content in your application.

Whay you would need is to define a *.jsp pattern to allow Tomcat use the default jsp servlet:

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
</servlet-mapping>
Gabriel Belingueres
  • 2,945
  • 1
  • 24
  • 32