Writing Servlets the J2EE 6 / Servlet 3.0 way

In the past whenever you wrote a Servlet you had a lot of work to do. First you wrote your servlet, then you had to add configuration for that servlet into web.xml so that your application would use it.

For simple applications this was fine but the more servlets you wrote the harder it became as web.xml started to become large and unwieldy.

Now with J2EE 6 you got the ability to add annotations to your servlets. No more do you need to add anything to web.xml as the container scans the classpath for any servlet that’s annotated with @WebServlet getting the required configuration from there.

This also has the benefit that you can write libraries of servlets. Those servlets get deployed automatically and you don’t have to worry about duplicating the config.

Both Tomcat 7 and TomEE 1.5.1 support the J2EE 6 Web Profile as standard. I’m not certain of other containers as I’ve only tested this on those two.

Writing a Servlet the old way

First you wrote a Servlet:

package org.myapp;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {

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

    @Override
    protected void doPost( HttpServletRequest request,
                           HttpServletResponse response )
            throws ServletException,
                   IOException
    {
        processRequest( request, response );
    }

    protected void processRequest( HttpServletRequest request,
                                   HttpServletResponse response )
            throws ServletException,
                   IOException
    {
        response.getWriter().println( "Hello World!" );
    }
}

Then you added the config into web.xml:

<servlet>
  <servlet-name>My Servlet</servlet-name>
  <servlet-class>org.myapp.MyServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>MyServlet</servlet-name>
  <url-pattern>/myservlet/*</url-pattern>
</servlet-mapping>

Now imaging doing that dozens of times… yes it becomes unmanageable. It’s because of this for the rise of other web frameworks. Well not the sole reason but one thing other frameworks try to do is to make it simpler and more maintainable – this way it isn’t.

Writing a Servlet the new way

In J2EE 6 it’s now simpler. All you need to do is to annotate the Servlet itself with the @WebServlet annotation:

package org.myapp;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet( "name="MyServlet", urlPatterns = "/myservlet/*" )
public class MyServlet extends HttpServlet {

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

    @Override
    protected void doPost( HttpServletRequest request,
                           HttpServletResponse response )
            throws ServletException,
                   IOException
    {
        processRequest( request, response );
    }

    protected void processRequest( HttpServletRequest request,
                                   HttpServletResponse response )
            throws ServletException,
                   IOException
    {
        response.getWriter().println( "Hello World!" );
    }
}

Thats it. Nothing goes into web.xml. When the container deploys the application it sees the @WebServlet annotation and uses that configuration to deploy the servlet.

What about servlets with multiple url mappings you may ask?

Well the urlPatterns property in the annotation is actually an array. In the example above I’ve used shorthand where javac will allow a single value to be written without an array but it’s possible to add multiple patterns easily:

@WebServlet( "name="MyServlet", urlPatterns = {
  "/myservlet/*", "/myotherservlet"
} )

Other parameters

The annotation includes additional parameters which map to the elements you would have put into web.xml originally.

 boolean asyncSupported
Declares whether the servlet supports asynchronous operation mode.
 java.lang.String description
The description of the servlet
 java.lang.String displayName
The display name of the servlet
WebInitParam[] initParams
The init parameters of the servlet
 java.lang.String largeIcon
The large-icon of the servlet
 int loadOnStartup
The load-on-startup order of the servlet
 java.lang.String name
The name of the servlet
 java.lang.String smallIcon
The small-icon of the servlet
 java.lang.String[] urlPatterns
The URL patterns of the servlet
 java.lang.String[] value
The URL patterns of the servlet

The more useful ones here are:

  • loadOnStartup – set this to 1 and your servlet is loaded when the webapp is. Leave this out and the servlet gets loaded when it’s first requested.
  • initParams – this is an array of @WebInitParam annotations containing the servlet’s initial parameters.

Although it might seem strange to have initParameters in an annotation when you could do it in code but it is beneficial in that:

  • You keep the configuration in a single place
  • Your Servlet might inherit from another one. Placing configuration on the deployed servlet can then be passed on to the super class.

ServletContextListener’s

ServletContextListener‘s can also be annotated with the @WebListener annotation. This is useful if you are deploying a framework which must perform actions when the application is deployed or destroyed.

In the past you had to declare each one in web.xml with something like the following:

<listener>
  <listener-class>net.sf.ehcache.constructs.web.ShutdownListener</listener-class>
</listener>

Now you can simply use:

package org.myapp;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class MyServletContextListener implements ServletContextListener {

    public void contextInitialised( ServletContextEvent sce ) {
        // do something here
    }

    public void contextDestroyed( ServletContextEvent sce ) {
        // do something here
    }
}

The really useful thing here is that no more would you forget to declare the listener if you included your framework in a new application.

If your framework needs to cleanup on shutdown for example, now it will automatically get called whenever it’s in the classpath of your application.

Filter’s

Filters can also be declared with the @WebFilter annotation.

package org.myapp;

import javax.servlet.Filter;
import javax.servlet.annotation.WebFilter;

@WebFilter( filterName = "MyFilter", urlPatterns = "/*" )
public class MyFilter
implements Filter
{
    // implementation goes here
}

The stub above declares a filter which runs against all requests to the application. Like servlets urlPatterns is an array of url patterns although you can also use servletNames instead which declares the servlets this filter is to run against.

The only downside I can see with this is that you cannot determine the order that filters run – in web.xml they run in the order they are declared. This can be a problem for some applications but for most this is enough.

That’s all for now about Servlet 3.0. There’s a couple of topics not covered, like security & multipart upload support but those will be covered by separate articles.

About these ads

3 thoughts on “Writing Servlets the J2EE 6 / Servlet 3.0 way

  1. Stephan Stäheli says:

    Great migration cookbook, thanks a lot.

    You mentioned security: Do you have experience with servlet 3.0 and form-login? I didn’t find any examples in the whole wide web but in a tutorial I read something that this would not be possible to do with annotations, when using form login a deployment descriptor is mandatory.

    Did you ever migrate a secure servlet to 3.0?

    Stephan

    • petermount1 says:

      I did manage a form login, I just had a form which went to a settler and then used the new login methods, passing authentication to the container – tomcat in this case.

      It worked pretty well. Even got Tomcat’s SSO to work so the auth module was a separate webapp. In that instance once authenticated it then redirected back to the original resource.

      I have to say servlet 3.0 is way better than the earlier api’s.

  2. Paul says:

    is it possible to map the url to a method ? a bit like @RequestMapping in spring ?
    @WebServlet(“/my”)
    class MyServlet extends HttpServlet {

    /** handle create */
    @XAnnotation(value = “/create”)
    public String create() {

    }

    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 1,770 other followers

%d bloggers like this: