Nicht immer genuegt es, wenn man ein Servlets auf andere Pfade oder Patterns mappt, manchmal möchte man bereits auf den Context Root ein Servlet mappen. Der übliche Work-Around sieht so aus, dass man bspw. in einer „index.jsp“ einen redirect auf eine tatsächlich einem Servlet zugeordnete URL (über den Pfad oder Datei Extension) macht, das könnte so aussehen:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:redirect url="/myServlet"/>

Das ist aber nicht immer praktikabel – nun soll es darum gehen ein Servlet direkt auf den „/“ Pfad zu mappen – dafür gibt es mehrere Möglichkeiten:

  1. Das Default Servlet ersetzen, dazu wird auf den Root Pfad „/“ in der web.xml ein Mapping angelegt:
    <servlet-mapping>
    <servlet-name>myServlet</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
  2. Ab Servlet Spezifikation kann auch ein Servlet in der welcome-file-list in der web.xml gemappt werden:
    <welcome-file-list>
    <welcome-file>myServlet</welcome-file>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

Im folgenden beschreibe ich die Vor- und Nachteile der verschiedenen Ansätze, und welche Erfahrungen ich mit verschiedenen Web Containern dabei gemacht habe.Das Default Servlet wird in der Regel zur Auslieferung von statischen Ressourcen (z.B. Bilder, CSS Dateien) und dem Directory Listing verwendet. Ersetzt man das Default Servlet des Web Containers nun durch ein eigenes, muss man sich ggf. selber um die zusätzlichen Aufgaben kümmern, oder die statischen Inhalte über einen anderen Pfad ausliefern, z.B. „static“ und diesen auf das Default Servlet mappen:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

Da inzwischen wirklich überall Servlet 2.4 konforme Webcontainer im Einsatz sein dürften, ist der Web über ein Servlet als Welcome-File praktischer: Das vom Container bereitgestellte Default Servlet kommt weiterhin für die restlichen Ressourcen zum Einsatz, an der Struktur des Projektes muss nichts geändert werden. Die zugehörige Konfiguration in der web.xml für ein Spring Dispatcher Servlet könnte z.B. so aussehen:

<servlet>
<description>Spring Dispatcher Servlet</description>
<servlet-name>myServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>myServlet</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

Das funktioniert soweit in Tomcat und Glassfish auch – allerdings nicht in Jetty. Und Jetty verwende ich sehr gerne zum lokalen Testen, z.B. über das Jetty Maven Plugin. Zu dem Fehler von Jetty gibt es auch einen Bug in der Jetty Bug Datenbank (936), offenbar sind die Jetty Entwickler der Auffassung, dass die Spezifikation in diesem Punkt „stupid“ sei, man weigert sich da auch in dem Codehaus Jetty 6.1.x das Defaultverhalten der Spezifikation gemäss anzupassen.
Um das Verhalten zu korrigieren, muss man das Jetty Default Servlet anders konfigurieren – damit bekommt das Projekt eine Jetty Abhängigkeit, die in meinen Augen nicht gewünscht ist, vor allem nicht, wenn Jetty lediglich zur Entwicklung eingesetzt wird.

Jetty ist nun zu Eclipse umgezogen und mit Jetty 7 ändert sich das Problem ein wenig: Jetty 7 akzeptiert nun im Default auch Servlets für ein Welcome-File-Mapping – jedoch findet vorher noch eine Prüfung statt, ob die Datei existiert. Existiert sie nicht, wird ein 404 HTTP Fehler erzeugt. Natürlich kann man dies über Konfiguration des Default Servlets ändern – aber dann hat man wieder die Jetty Abhängigkeit im Projekt. Hier hilft ein kleiner Trick: Man legt einfach eine leere Datei, z.B. index.html, an, gibt diese (zusätzlich) in der Welcome-File-List an, und mappt diesen Pfad auch noch auf das entsprechende Servlet. Diese Lösung funktioniert mit allen von mir getesteten Containern. Also kommt zusätzlich in die web.xml:

<!-- for stupid jetty -->
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>

Für das Maven Plugin von Jetty 7 hat sich der Artefakt Name geändert, und auch der Default Context ist „/“ statt des Artefakt Namens – so sieht der Eintrag im POM daher aus:

<plugin>
  <groupId>org.mortbay.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>7.2.1.v20101111</version>
    <configuration>
      <webAppConfig>
        <contextPath>/${artifactId}</contextPath>
      </webAppConfig>
    </configuration>
</plugin>

Nun noch die Konfiguration für Spring 3 Controller, die auf den Root Path gemappt werden sollen. Ich verwende hier die Spring Annotationen für @Controller und @RequestMapping. Das Problem hier: Jetty ruft „natürlich“ die „index.html“ auf – auch hierfür muss der Controller dann ein Mapping haben. Die Lösung dafür ist ein Pattern zu verwenden, was Spring erlaubt:

@Controller
public class SampleController
{
   @RequestMapping(value = "*", method = RequestMethod.GET)
   public ModelAndView rootPathHandler()
   {
       //...
       return new ModelAndView("sample");
   }
}