Wenn man die grundlegende Funktionsweise von Spring MVC verstanden hat – ich empfehle an dieser Stelle die äußerst vorzügliche offizielle Dokumentation -, kommt man an den Punkt, an dem man auch Bilder oder Stylesheets in die Web-Applikation einbinden möchte. Dafür gibt es zwei Möglichkeiten.

Spezifizieren eines eigenen URL-Suffixes für Request-Mappings

Konzept

Alle Requests bzw. Aktionen, die von einem Controller verarbeitet werden sollen, werden auf ein bestimmtes Suffix gemappt.

Controller

@Controller
class MyController {
    @RequestMapping("/home.do")
    public void ModelAndView home() {
        return new ModelAndView("home");
    }

    @RequestMapping("/test.do")
    public void ModelAndView test() {
        return new ModelAndView("test");
    }
}

*-servlet.xml

<!-- ... Beans ... -->
<bean id="viewResolver"
      class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView" />
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>
<!-- ... noch mehr Beans ... -->

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	id="WebApp_ID" version="2.4"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <!-- andere Servlet-Definitionen ... ->
    <servlet>
          <servlet-name>dispatcher</servlet-name>
          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
          <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
          <servlet-name>dispatcher</servlet-name>
          <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

Konzept

Anfragen auf URLs der Form *.do werden von dem FrontController verarbeitet. Die URL /context/home.do wird auf die Methode MyController.home() gemappt. Diese liefert die View mit dem Namen home zurück. Die View wird durch den InternalResourceViewResolver unter /WEB-INF/jsp/home.jsp gesucht.

Alle Anfragen, die nicht auf *.do enden (z.B. /context/images/bild.jpg, werden von dem Default-Servlet des Containers verarbeitet. Dieser sucht nach der Datei /images/bild.jpg und liefert diese zurück.

Vorteil bei dieser Methode kann sein, dass man sofort sieht, welche URLs auf Methoden gemappt sind. Allerdings entspricht die URL nicht mehr dem REST-Prinzip.

DefaultServlet wird auf die zu nutzenden Dateiendungen gemappt

Hierbei wird dem Default-Servlet des Servlet-Containers explizit gesagt, welche Dateiendungen er handeln soll.

Controller

@Controller
class MyController {
    @RequestMapping("/home")
    public void ModelAndView home() {
        return new ModelAndView("home");
    }

    @RequestMapping("/test")
    public void ModelAndView test() {
        return new ModelAndView("test");
    }
}

*-servlet.xml

Siehe erstes Beispiel

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	id="WebApp_ID" version="2.4"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <!-- andere Servlet-Definitionen ... ->
    <!-- Beispiel für Tomcat -->
    <servlet>
          <servlet-name>defaultServlet</servlet-name>
          <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    </servlet>

    <!-- Beispiel für Jetty -->
    <servlet>
          <servlet-name>defaultServlet</servlet-name>
          <servlet-class>org.mortbay.jetty.servlet.DefaultServlet</servlet-class>
    </servlet>

    <servlet-mapping>
          <servlet-name>defaultServlet</servlet-name>
          <url-pattern>*.css</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
          <servlet-name>defaultServlet</servlet-name>
          <url-pattern>*.png</url-pattern>
    </servlet-mapping>

    <servlet>
          <servlet-name>dispatcher</servlet-name>
          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
          <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
          <servlet-name>dispatcher</servlet-name>
          <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

Konzept

Dem Servlet-Container wird explizit gesagt, dass der statische Content (in unserem Beispiel sind das PNGs und CSS-Dateien) von dem DefaultServlet verarbeitet und zurückgegeben wird. Jede andere Anfrage wird vom FrontController verarbeitet. Vorteil bei dieser Methode ist, dass sich so schöne URLs bauen lassen. Die URL /home wird z.B. auf die Methode MyController.home() gemappt.

Einer der Nachteile ist, dass jeder statische Content, der im Projekt verwendet wird, in die web.xml eingetragen werden muss – wenn z.B. auch noch GIFs oder JPEGs benutzt werden sollen. Außerdem muss die web.xml für jeden Servlet-Container manuell angepasst werden. In der J5EE-Spezifikation existiert keine Notwendigkeit eines Default-Servlets. Bei Jetty und Tomcat wird zwar automatisch der Servlet-Name default für das Default-Servlet registriert, allerdings kann sich das in Zukunft ändern.

Fazit

Wie man statischen Content ausliefert, ist eine Frage des Geschmacks. Ich persönlich finde die zweite Methode eleganter, da sich dadurch REST-konforme URLs schreiben lassen.

I am asking you for a donation.

You liked the content or this article has helped and reduced the amount of time you have struggled with this issue? Please donate a few bucks so I can keep going with solving challenges.