Friday, September 23, 2011

web.xml servlet Understanding <url-pattern>/*</url-pattern>

Understanding the <url-pattern>/*</url-pattern>

Other Questions of similar pattern:
1) How to exclude from url-pattern in servlet mapping?
2) To exclude content from url-pattern

While developing web.xml in application, do take care of the <url-pattern>.
Try not to give a generic url-pattern ie., <url-pattern>/*</url-pattern>.The disadvantage of this URL Pattern is, any request coming to the server will fall in this URL PATTERN(except for those you have explicitly defined). Suppose browser is requesting a page which has images,css,etc then you will find page will load with the servlet response,while the images,css,js,etc are not getting loaded and it will be very difficult to find the reason for this type of behaviour.

The reason is as:-
Our browser requests in the following steps
Step1: The browser requests the page and gets back the response which contains all other path.
Step2: The browser again requests all the other path to the server and these path contains the images,css,etc

What happens in our problem is in step 2,the browser's request goes to the server and now the images,etc also falls in the <url-pattern >/*</url-pattern>,which redirects to a servlet and this is the problem. This is the reason why we don't get images and other files in our web page.

Let us solve this with the help of example:
web.xml

 TestUrlPattern
 
   ServletDefault
   com.test.ServletDefault
   
  
    ServletDefault
    /*
  
  
  abcd
  /abc.jsp
  
  
   abcd
    /abc.jsp
  


abc.jsp
<html>
<head>
<title>TestUrlPattern</title>
</head>
<body>
Sample text
<img src="Desert.jpg" >
</body>
</html>


Whenever a request comes as localhost:8080/TestApp/abc.jsp, the abc.jsp loads and images are not getting loaded. The images goes to the SevletDefault mapping. You can see this by printing any text in doGet or doPost method of ServletDefault class.
Reason is,all files other than abc.jsp will go to ServletDefault.

Solution for /* type pattern in web.xml

I found two approaches to solve this problem
Approach 1:

Make a common servlet which consumes all the files which have the pattern for images,css,javascript,etc
web.xml  (modified)

  TestUrlPattern
  
      CommonServlet
      com.test.CommonServlet
    
  
      Servlet
      com.test.Servlet
    
    
        Servlet
        /*
    
    
    abcd
    /abc.jsp
  
    
    
      abcd
        /abc.jsp
    
        
        CommonServlet
        /images/
    
    
        CommonServlet
        /stylesheet.css
    
    
        CommonServlet
        /javascript.js
      


Keep the images in the 'images' folder. For a new request to the servlet, you will find,all the images,css,js requests goes to CommonServlet. Write a CommonServlet which retuns back the file itself in the response.

CommonServlet.java

public class CommonServlet extends HttpServlet  {
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  ServletContext sc = getServletContext();
  String path=req.getRequestURI().substring(req.getContextPath().length()+1, req.getRequestURI().length());
     String filename = sc.getRealPath(path);

     // Get the MIME type of the image
     String mimeType = sc.getMimeType(filename);
     if (mimeType == null) {
         sc.log("Could not get MIME type of "+filename);
         resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
         return;
     }
     // Set content type
     resp.setContentType(mimeType);

     // Set content size
     File file = new File(filename);
     resp.setContentLength((int)file.length());

     // Open the file and output streams
     FileInputStream in = new FileInputStream(file);
     OutputStream out = resp.getOutputStream();

     // Copy the contents of the file to the output stream
     byte[] buf = new byte[1024];
     int count = 0;
     while ((count = in.read(buf)) >= 0) {
         out.write(buf, 0, count);
     }
     in.close();
     out.close();
 }
}

The above servlet write the contents of file in the response and our problem is solved.

Approach 2:

This approach sets the context in jboss server.xml file.
server.xml is found at Jboss_home\server\default\deploy\jboss-web.deployer path.
Open server.xml in edit mode
Add the context in server.xml.
Find text similar to the following code in server.xml
<Host name="localhost" autoDeploy="false" deployOnStartup="false" deployXML="false"configClass="org.jboss.web.tomcat.security.config.JBossContextConfig" >
Below the above code add the context as:



set docBase,path according to your path.This will solve your problem.

These were the two approaches which i found out for this problem. Please let me know if you know any more approach.

17 comments:

  1. Great Post!!!Thanks a lot for such post.
    :-)

    ReplyDelete
  2. I have almost the same problem but I want to avoid these solutions. But it look like to be the only one working.

    Thx for posting your solutions! It helps!

    ReplyDelete
  3. Finally I use another solution. I put a filter that redirect "/" page to my start serlvet.

    The filter:

    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;

    String pageName = req.getServletPath();

    if(pageName.equals("/")) {
    res.sendRedirect( req.getContextPath() + "/start" );
    } else {
    chain.doFilter(request, response);
    }

    web.xml:


    RootRedirectionFilter
    com.servlet.filter.RootRedirectionFilter




    RootRedirectionFilter
    /*



    com.servlet.GameLogin
    GameStart



    GameStart
    /start

    ReplyDelete
  4. very nice tutorial. another thing the readers would like to know is that a JSP can also be mapped to url.

    ReplyDelete
  5. hi i want to know once the servlet is created can we change the url pattern what we had mentioned while creating it. If yes how to do.

    ReplyDelete
    Replies
    1. I did not get your question properly..
      According to my understanding your question is to change the URL pattern of servlet. If that is the question, then definitely, we can change the Url pattern of any servlet any time. Just edit or create entry in web-xml for that servlet.

      Delete
  6. Why should this be so complex! What about performance?
    When the web server is very well capable of serving static files directly, you are reading the static content unnecessarily in java code and sending the same back.

    My WebContent folder has some static files and of-course the servlet is in a separate source folder.

    A very simple alternative which works.. change the url pattern from / or /* to something like /1/* or /1/

    MyServlet
    /1/

    This ensures that all such calls go to my Servlet
    http://localhost:8080/Servlet/1/*

    And static content in other folders get directly served by the web server
    http://localhost:8080/Servlet/Images/*

    Let me know what you think

    ReplyDelete
    Replies
    1. There are many cases, where the application is already running and change is URL is not affordable. In that case, you can use the above approach...

      Delete
  7. Hi Bipin,
    Why should this be so complex! What about performance?
    Performance impact can be determined only when you implement for some actual requirement.
    2. You are right in the sense that Web servers can handle static content well and support caching as well. Here we have shown only a demo application. But you might have requirement where you want to change the url of a image every time, there it will be useful to render static content through java code.
    Demo just explains /* and / pattern and does not mandate use of any approach in any form.

    ReplyDelete
  8. Thanks Vinkal,
    This was a very useful and very well written blog - it saved me a lot of time with troubleshooting. Karen.

    ReplyDelete
  9. Awesome, this topic is very useful for me, i got more information from this site

    ReplyDelete
  10. nice post.this post is very useful for us keep it up.

    ReplyDelete
  11. hi i got some problem like this exactly like this
    i'm using tomcat 8.0.0 and
    my URL is http://localhost:8084/SocMedPrototype
    I'm gonna create something like facebook profile so its become
    http://localhost:8084/SocMedPrototype/user/123123
    but then all link become http://localhost:8084/SocMedPrototype/user/123123/img/testImage
    :(
    anyone can help me?

    ReplyDelete
  12. "Nice and good article.. it is very useful for me to learn and understand easily.. thanks for sharing your valuable information and time.. please keep updating.php jobs in hyderabad.
    "

    ReplyDelete