• Link zu Xing
  • Link zu LinkedIn
  • Link zu X
  • Link zu Rss dieser Seite
  • Link zu GitHub
  • Newsletter
  • Kontaktieren Sie mich
Frank W. Rahn
  • Meine BlogbeiträgeZeigt meinen Blog an
  • RessourcenZeigt Ihnen eine Auswahl von Ressourcen
    • Franks aktueller IT-Werkzeugkasten
      • Diese Werkzeuge setze ich zur Zeit ein
    • Meine Präsentationen
      • Zeigt Ihnen meine Präsentationen
    • Weblinks
      • Meine Linksammlung
    • Buchtipps
      • Eine Liste von mir empfohlener Literatur
    • XML-Namespace
      • Zeigt meinem XML-Namespace
  • Franks aktueller IT-WerkzeugkastenDiese Werkzeuge setze ich zur Zeit ein
  • Meine PräsentationenZeigt Ihnen meine Präsentationen
  • WeblinksMeine Linksammlung
  • BuchtippsEine Liste von mir empfohlener Literatur
  • XML-NamespaceZeigt meinem XML-Namespace
  • Über mich …Die persönlichen Informationen über den Softwarearchitekt Frank Rahn
  • Click to open the search input field Click to open the search input field Suche
  • Menü Menü
Artikel, Beispiele und Vorträge

Spring mit einer einfachen Webanwendung (Tutorial)

Dieser Beitrag ist Teil einer (Tutorial-) Serie über die Einführung in das Spring Framework und beschreibt das Erstellen einer einfachen Webanwendung mit dem Spring Framework.

Inhaltsverzeichnis [anzeigen]

  • Die Struktur des Projektes
  • Die Literaturempfehlungen für dieses Beispiel
  • Das Erzeugen eines neuen Tomcat Servers
  • Das Anlegen des Projektes in Eclipse
  • Die Konfiguration der Webanwendung
    • Das Anpassen der Tomcat Installation
  • Die Masken (Oberfläche, View)
  • Die Steuerung (Controller)
  • Die Masken
  • Der Unit Test
  • Der Quellcode und Download des Beispiels
  • Die Maven Befehle
  • Update am 28.09.2012
  • Updates von 06.10.2012 bis zum 14.10.2012

Die Struktur des Projektes

In diesem Beispiel wird eine Webanwendung mit Spring Framework MVC erstellt. Die verwendeten Frameworks und Werkzeuge sind hier beschrieben. Es werden die folgenden Technologien des Spring Frameworks vorgestellt:

  • Das Anlegen eines Tomcat Servers in Eclipse.
  • Das Erstellen eines Web-Projektes in Eclipse.
  • Das Konfigurieren einer Webanwendung mit Spring MVC.
  • Das Erstellen von Masken (Oberflächen, View) und Steuerungen (Controller).
  • Die Fehlerbehandlung bei Spring MVC.
  • Der Datenaustausch über ein Model.
  • Das Testen von Controllern.

Im folgendem Bild ist die Projektstruktur dargestellt.

Die Projektstruktur in Eclipse

Die Projektstruktur in Eclipse (© Frank Rahn)

Die folgende Bibliotheken werden benötigt:

Die benötigten Bibliotheken (Dependencies)

Die benötigten Bibliotheken - Dependencies (© Frank Rahn)

Die Literaturempfehlungen für dieses Beispiel

  • Referenzdokumentation des Spring Framework’s
  • Spring 3: Framework für die Java-Entwicklung (*)

Das Erzeugen eines neuen Tomcat Servers

In diesem Beispiel nutze ich die Eclipse Web Tool Platform. Dazu muss in der Perspektive Java EE perspective in der View Servers ein Tomcat Server angelegt werden. Dieses ist in der folgenden Bildgalerie dargestellt.

Define a New Server (Tomcat-Server)
Define a New Server (Tomcat-Server)
New Server Runtime Environment (Tomcat-Server)
New Server Runtime Environment (Tomcat-Server)
Add and Remove (Tomcat-Server)
Add and Remove (Tomcat-Server)

Das Anlegen des Projektes in Eclipse

In der folgenden Bildgalerie ist das Anlegen und Konfigurieren des Projektes mit Web Support in Eclipse beschrieben.

New Project: Select a wizard (Dynamic Web-Project)
New Project: Select a wizard (Dynamic Web-Project)
New Project: Dynamic Web Project (Dynamic Web Project)
New Project: Dynamic Web Project (Dynamic Web Project)
New Project: Java (Dynamic Web Project)
New Project: Java (Dynamic Web Project)
New Project: Web Module (Dynamic Web Project)
New Project: Web Module (Dynamic Web Project)
New Project: Web Deployment Assembly (Dynamic Web Project)
New Project: Web Deployment Assembly (Dynamic Web Project)

Die Konfiguration der Webanwendung

Die Webanwendungen, die dem Java EE 6 Standard genügen, werden mit einem Web-Deployment-Descriptor web.xml konfiguriert. Diese Datei befinden sich im Verzeichnis src/web/WEB-INF. Im folgendem Listing wird der Inhalt dieser Datei gezeigt und beschrieben.

  • In der Zeile 3 wird das Attribut metadata-complete="true" gesetzt, dadurch berücksichtigt der Anwendungsserver keine Java EE Annotationen in diesem Web-Modul. Dieses hat unter anderem den Vorteil, dass der Anwendungsserver keinen Klassen-Scan durchführt. Dieser Scan lädt alle Klassen in den Classloader bevor die Anwendung gestartet wird. Dieses führt zu Problemen, wenn beim Anwendungsstart Klassen durch die Anwendung (Load-Time) instrumentiert werden sollen (z. B. durch AspectJ, einen JPA-Provider oder ähnlichem), da diese schon geladen sind und nicht mehr verändert werden können.
  • Ab der Zeile 27 wird ein Filter für das Setzen des Encodings konfiguriert. Falls ein Request ohne angegebenen Encoding empfangen wird, wird das Encoding auf UTF-8 gesetzt. Damit werden auch Sonderzeichen richtig dargestellt.
  • Ab der Zeile 44 wird für das Logging ein Listener konfiguriert. Er muss der erste Listener in der Liste sein. Er lädt die Konfigurationsdatei aus Zeile 17.
  • Ab der Zeile 52 wird ein Listener für das Laden der XML Konfiguration der fachlichen Spring Beans (fachliche Logik) konfiguriert. Er verwendet die Konfigurationsdatei aus Zeile 24.
  • Ab der Zeile 62 wird das zentrale Servlet des Spring Frameworks konfiguriert. Es dient als Verteiler (Dispatcher) der Request auf die einzelnen Controller.
<?xml version="1.0" encoding="UTF-8"?>

<web-app id="WebApp_ID" version="3.0" metadata-complete="true"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/javaee
            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd
    ">

    <description>Test Spring mit MVC Web Anwendung</description>
    display-name>test-spring-web</display-name>

    <context-param>
        <description>Der Parameter für das Logging</description>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath:log4j.xml</param-value>
    </context-param>
    <context-param>
        <description>
            Der Parameter für den ApplicationContext der fachlichen Logik
        </description>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:META-INF/spring/context-web.xml</param-value>
    </context-param>

    <filter>
        <description>Der Filter für das Encoding</description>
        <filter-name>encoding-filter</filter-name>
        <filter-class>
            org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <init-param>
            <description>Der Parameter für das Encoding</description>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding-filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <description>
            Der Listener für die Konfiguration des Logging
        </description>
        <listener-class>
            org.springframework.web.util.Log4jConfigListener
        </listener-class>
    </listener>
    <listener>
        <description>
            Der Listener für die Konfiguration des ApplicationContext
            der fachlichen Logik
        </description>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <description>Das zentrale Servlet</description>
        <servlet-name>spring</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

Das zentrale Servlet benötigt eine eigene Konfiguration. Der Name dieser XML Konfiguration verwendet den Servlet-Namen und den Postfix -servlet.xml. Der aus dieser Konfiguration entstehende ApplicationContext hat als Parent (Verschachtelung) den ApplicationContext von ContextLoaderListener mit den fachlichen Spring Beans. So können die Oberflächenelemente von der fachlichen Logik getrennt werden.

  • In der Zeile 40 wird ein Mapper zwischen URI und View definiert. Er macht aus der URI /index mit seiner Parameterisierung /WEB-INF/views/index.jsp.
  • In der Zeile 37 wird das Servlet angewiesen, alle Request ohne weiteren Pfad, an die View index zu leiten ohne einen Controller aufzurufen.
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd
    ">

    <description>
        Dieses ist die zentrale Konfiguration für das Spring-Servlet.
    </description>

    <!-- Enabling des AspectJ Support -->
    <aop:aspectj-autoproxy proxy-target-class="true" />

    <!-- Verwenden des Load-Time-Weaver -->
    <context:load-time-weaver aspectj-weaving="on" />

    <!-- Das Verwenden von allgemeinen Annotationen ermöglichen -->
    <context:annotation-config />

    <!-- Schalte die Annotation für MVC ein -->
    <mvc:annotation-driven />

    <!-- Die Definition für den Aufruf der Index-Seite -->
    <mvc:view-controller path="/" view-name="index" />

    <!-- Die Definition zum Mapping von Adressen auf Views -->
    <bean id="viewResolver" 
        class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:suffix=".jsp"
        p:prefix="/WEB-INF/views/"
        p:viewClass="org.springframework.web.servlet.view.JstlView" />

    <!-- Laden der Controllers -->
    <import resource="classpath:/de/rahn/web/application.xml" />

</beans>

Die folgende XML Konfiguration enthält die fachlichen Spring Beans.

  • In diesem Beispiel sind die fachlichen Komponenten aus dem Beispiel Spring mit JPA und Hibernate in den Zeilen 30 und 31 noch auskommentiert. Im nächsten Beispiel werden sie hinzugenommen.
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
    ">

    <description>
        Dieses ist die zentrale Konfiguration für die Anwendungen.
    </description>

    <!-- Enabling des AspectJ Support -->
    <aop:aspectj-autoproxy proxy-target-class="true" />

    <!-- Das Verwenden von allgemeinen Annotationen ermöglichen -->
    <context:annotation-config />

    <!-- Verwenden des Load-Time-Weaver -->
    <context:load-time-weaver aspectj-weaving="on" />

    <!-- Die projektspezifischen Konfigurationen laden -->
    <!--import resource="classpath:/META-INF/spring/db.xml" /-->
    <!--import resource="classpath:/de/rahn/services/drivers/drivers.xml" /-->

</beans>

Das Anpassen der Tomcat Installation

In den Konfiguration wurde das Load-Time-Weaving aktiviert. Dieses instrumentiert Klassen direkt zum Ladezeitpunkt. Dazu muss eine spezielle Tomcat-Konfiguration erstellt werden. Diese Konfiguration weist Tomcat an einen anderen ClassLoader für diese Webanwendung zu verwenden. Diese Datei befindet sich im Verzeichnis src/web/META-INF.

<?xml version="1.0" encoding="UTF-8"?>

<Context path="/test-spring-web" reloadable="true">
    <Loader 
        loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
    />
</Context>

Zusätzlich muss noch in das Verzeichnis ${TOMCAT_HOME}/lib die Bibliothek spring-instrument-tomcat-3.0.5.RELEASE.jar kopieren werden.

Die Masken (Oberfläche, View)

Die erste Seite (Startseite, Willkommensmaske) ist als Navigationsseite aufgebaut. Von hier aus können die einzelnen Beispiele angesprungen werden.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Willkommen | Frank W. Rahn</title>
    </head>
    <body>
        <h1>Willkommen</h1>
        <p>Folgende Seiten stehen zur Auswahl:</p>
        <ul>
            <li><a href="sample">Beispielseite</a></li>
            <li><a href="erzeugeFehler">Fehlerseite</a></li>
            <li><a href="info">Inhalt des ApplicationContext von Spring</a></li>
        </ul>
    </body>
</html>

Die folgende Beispielseite mit Zähler verwendet in Zeile 11 ein Attribut, das im Controller gesetzt wird.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Beispielseite | Frank W. Rahn</title>
    </head>
    <body>
        <h1>Beispielseite</h1>
        <p>Diese Seite wurde ${counter} mal aufgerufen.</p>
    </body>
</html>

Die folgende Fehlerseite wird aufgerufen, wenn ein Controller durch einen Fehler eine Ausnahme wirft.

  • In den Zeilen 12 und 13 werden zwei Attribute aus dem Controller in die Seite eingefügt.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Fehlerseite | Frank W. Rahn</title>
    </head>
    <body>
        <h1>Fehlerseite</h1>
        <p>Es ist leider ein Fehler aufgetreten.</p>
        <p>${message}</p>
        <pre>${stackTrace}</pre>
    </body>
</html>

Auf der folgenden Maske sollen die geladenen Spring Beans in allen ApplicationContext aufgelistet werden.

  • In der Zeile 2 wird die Verwendung der JavaServer Pages Standard Tag Library deklariert.
  • In der Zeile 12 bis 44 wird über die einzelnen ApplicationContext iteriert. Die ApplicationContext können verschachtelt sein.
  • In der Zeile 33 bis 39 wird über die Spring Beans eines ApplicationContext gelaufen.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>ApplicationContext | Frank W. Rahn</title>
    </head>
    <body>
        <h1>ApplicationContext</h1>
        <c:forEach var="appCtx" items="${appCtxs}">
        <fieldset>
            <legend>${appCtx.displayName}</legend>
            <table border="0" cellpadding="0" cellspacing="0" width="100%">
                <tr>
                    <th>Id</th>
                    <td>${appCtx.id}</td>
                </tr>
                <tr>
                    <th>Klasse</th>
                    <td>${appCtx.appCtxClass}</td>
                </tr>
            </table>
            <fieldset>
                <legend>Beans</legend>
                <table border="1" cellpadding="0" cellspacing="0" width="100%">
                    <tr>
                        <th>Klasse</th>
                        <th>Id</th>
                        <th>Alias</th>
                    </tr>
                    <c:forEach var="bean" items="${appCtx.beans}">
                    <tr>
                        <c:forEach var="value" items="${bean}">
                        <td>${value}</td>
                        </c:forEach>
                    </tr>
                    </c:forEach>
                </table>
            </fieldset>
        </fieldset>
        <p>&nbsp;</p>
        </c:forEach>
    </body>
</html>

Die Steuerung (Controller)

Die Webanwendung hat nur einen einzelnen Controller SampleController. Hier befindet sich eine Diskussion, die den Unterschied zwischen einem Controller und einer Spring Bean genauer beleuchtet.

  • In der Zeile 19 wird durch die Annotation @Controller der Controller als solcher deklariert.
  • Die Methode in der Zeile 31 wird aufgerufen, wenn ein die URL http://localhost:8080/test-spring-web/sample aufgerufen wird. Dort wird bei jedem Aufruf ein Zähler hochgezählt und der View über das Modell bereitgestellt.
  • In der Zeile 43 wird nur eine Ausnahme geworfen, um die Fehlerbehandlung in der Methode handleException(Exception exception) auszuführen.
  • In der Zeile 51 ist ein Handler für Ausnahmen definiert. Sobald dieser Controller eine Ausnahme wirft, wird sie hier verarbeitet.
/**
 * Ein beispielhafter Controller.
 * @author Frank W. Rahn
 */
@Controller
public class SampleController {

    private static final Logger logger = getLogger(SampleController.class);

    private int counter = 0;

    /**
     * Zeige die Beispielseite an.
     * @param model In diesem Modell werden die Daten abgelegt
     */
    @RequestMapping("/sample")
    public void sample(Model model) {
        logger.info("Die Methode SampleController.sample() wurde aufgerufen.");
        model.addAttribute("counter", ++counter);
    }

    /**
     * Erzeuge einen Fehler.
     */
    @RequestMapping("/erzeugeFehler")
    public void createError() {
        logger
            .info("Die Methode SampleController.createError() wurde aufgerufen.");
        throw new NullPointerException("Ein Fehler ist aufgetreten!");
    }

    /**
     * Mit dieser Methode werden die Fehler angezeigt.
     * @param exception die Ausnahme zum Fehler
     * @return die Kombination aus Anzeige (View) und Daten (Model)
     */
    @ExceptionHandler
    public ModelAndView handleException(Exception exception) {
        StringWriter writer = new StringWriter();
        exception.printStackTrace(new PrintWriter(writer));
        ModelAndView modelAndView = new ModelAndView("error");
        modelAndView.addObject("message", exception.getMessage());
        modelAndView.addObject("stackTrace", writer.toString());
        return modelAndView;
    }

}

In der folgenden Spring XML Konfiguration wird nur das Packages mit den Controllern berücksichtigt.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
    ">

    <description>
        Dieses ist die zentrale Konfiguration für die Web-Application.
    </description>

    <!-- Scanne das Package nach Spring Beans -->
    <context:component-scan base-package="de.rahn.web" />

</beans>

Der folgende Controller stellt die Information über die verschachtelten ApplicationContext zusammen.

  • In der Zeile 22 wird für alle Methoden in dieser Klasse die Basis-Aufruf-URI definiert.
  • Dazu ist zunächst in der Zeile 29 ein Model als eine innere Klasse definiert.
/**
 * Zeige Informationen über den {@link ApplicationContext}.
 * @author Frank W. Rahn
 */
@Controller
@RequestMapping("/info")
public class ApplicationContextInfoController {

    /**
     * Das Model für die Informationen über den {@link ApplicationContext}.
     * @author Frank W. Rahn
     */
    public static class AppCtx {

        /** Die Id des ApplicationContexts. */
        private String id;

        /** Die Name des ApplicationContexts. */
        private String displayName;

        /** Die Klasse des ApplicationContexts. */
        private String appCtxClass;

        /** Die Daten der Beans des ApplicationContexts. */
        private List<List<String>> beans;

        /**
         * Konstruktor.
         */
        public AppCtx(String id, String displayName) {
            super();

            setId(id);
            setDisplayName(displayName);
        }

        /**
         * @param bean Füge die Daten eines Beans hinzu
         */
        public void addBean(List<String> bean) {
            if (beans == null) {
                beans = new ArrayList<>();
            }
            beans.add(bean);
        }
...
  • In der Zeile 131 wird definiert, dass diese Funktion nur die HTTP-Methode GET unterstützt und in der Zeile 132 wird der Name des Models angegeben.
    @Autowired
    private WebApplicationContext applicationContext;

    /**
     * Ermittle die Informationen über die verschachtelte
     * {@link ApplicationContext}.
     * @return das Model
     */
    @RequestMapping(method = RequestMethod.GET)
    @ModelAttribute("appCtxs")
    public List<AppCtx> showApplicationContextInfo() {
        List<AppCtx> appCtxs = new ArrayList<>();
        ApplicationContext current = applicationContext;

        // Ermitteln der verschachtelten ApplicationContexte
        while (current != null) {
            AppCtx appCtx =
                new AppCtx(current.getId(), current.getDisplayName());
            appCtx.setAppCtxClass(current.getClass().getName());
            appCtxs.add(appCtx);

            // Ermittlung der geladenen Beans
            Map<String, List<String>> beans = new HashMap<>();
            for (String name : current.getBeanDefinitionNames()) {
                List<String> bean = new ArrayList<>();

                // Bean Class
                Class<?> type = current.getType(name);
                bean.add(type.getName());
                beans.put(type.getName(), bean);

                // Bean Id
                bean.add(name);

                // Bean Aliase
                String[] aliase = current.getAliases(name);
                if (aliase != null) {
                    StringBuilder builder = new StringBuilder();
                    for (String alias : aliase) {
                        builder.append(alias).append(' ');
                    }
                    bean.add(builder.toString());
                } else {
                    bean.add("&nbsp;");
                }
            }

            // Beans nach Klasse sortieren
            List<String> keys = new ArrayList<>(beans.keySet());
            Collections.sort(keys);

            for (String key : keys) {
                appCtx.addBean(beans.get(key));
            }

            // Nächster ApplicationContext
            current = current.getParent();
        }

        return appCtxs;
    }

}

Die Masken

In folgender Bildgalerie werden die Screenshots der Masken im Browser dargestellt.

Die Startseite dieses Beispiels
Die Startseite dieses Beispiels
Die Beispielseite mit Zähler - 1* aufgerufen
Die Beispielseite mit Zähler - 1* aufgerufen
Die Beispielseite - 2* aufgerufen
Die Beispielseite - 2* aufgerufen
Die Fehlerseite dieses Beispiels
Die Fehlerseite dieses Beispiels
Die ApplicationContexte einer einfachen Spring Webanwendung
Die ApplicationContexte einer einfachen Spring Webanwendung

Der Unit Test

Für den einfachen Controller fehlt noch ein JUnit Test. Jede der drei Methoden des Controllers bekommt einen Test.

/**
 * Test für den Controller.
 * @author Frank W. Rahn
 */
public class SampleControllerTest {

    private SampleController controller;

    @Before
    public void setUp() {
        controller = new SampleController();
    }

    /**
     * Test method for {@link SampleController#sample(Model)} .
     */
    @Test
    public void testSample() {
        Model model = new ExtendedModelMap();
        controller.sample(model);

        assertThat("Attribut counter im ModelMap", model.asMap(),
            hasEntry("counter", (Object) new Integer(1)));
    }

    /**
     * Test method for {@link SampleController#createError()} .
     */
    @Test(expected = NullPointerException.class)
    public void testCreateError() {
        controller.createError();
    }

    /**
     * Test method for {@link SampleController#handleException(Exception)} .
     */
    @SuppressWarnings("unchecked")
    @Test
    public void testHandleException() {
        Exception exception = new Exception("Test");
        exception.fillInStackTrace();

        ModelAndView modelAndView = controller.handleException(exception);
        assertThat("Keine Model & View zurückgeliefert", modelAndView,
            notNullValue());
        assertThat("Falscher View-Name", modelAndView.getViewName(),
            is("error"));

        Map<String, Object> model = modelAndView.getModel();
        assertThat("Meldung im Model", model,
            allOf(hasEntry("message", (Object) "Test"), hasKey("stackTrace")));
    }

}

Der Quellcode und Download des Beispiels

Quellcode ansehen bei GitHub:
Spring mit einer einfachen Webanwendung

Download einer ZIP-Datei von GitHub:
Spring mit einer einfachen Webanwendung

Die Maven Befehle

Eclipse Konfiguration neu erzeugen: $ mvn eclipse:clean eclipse:eclipse

Anwendung bauen: $ mvn clean install

Update am 28.09.2012

Es wurden folgende Änderungen an allen Projekten vorgenommen.

  1. Die Projekte wurden aus meinem lokalen Apache Subversion Repository in meine öffentlichen GitHub Repositories verschoben.
    • Projekt test-spring-simple
    • Projekt test-spring-jpa
    • Projekt test-spring-web
  2. Die folgenden typischen Anpassungen an Git wurden an allen Projekten durchgeführt.
    • .directory gelöscht
    • .gitignore hinzugefügt
    • README.md hinzugefügt
    • COPYRIGHT.md hinzugefügt
    • In jedem Repository wurde für jeden Beitrag der Serie ein Branch angelegt.
      • develop-spring-an-einem-einfachen-beispiel
      • develop-spring-mit-aop
      • develop-spring-mit-jpa-und-hibernate
      • develop-spring-mit-einer-einfachen-webanwendung
      • develop-spring-mit-einer-webanwendung-mit-jpa-und-validierung
      • develop-spring-security-mit-einer-webanwendung
      • develop-spring-mit-restful-webservice

Updates von 06.10.2012 bis zum 14.10.2012

Es wurden folgende Änderungen an allen Projekten vorgenommen.

  1. Aktualisierung des OpenJDK auf die Version 1.7.0.
  2. Aktualisierung der Entwicklungsumgebung Eclipse auf die Version 4.2.1.
    Die benötigten Plugins aus dem Eclipse Marketplace:
    • EGit – Git Team Provider, Version 2.1.0
    • GitHub Mylyn Connector, Version 2.0
    • Eclipse m2e – Maven support in Eclipse IDE
    • Spring IDE, Version 3.0.0.RELEASE
    • AspectJ Development Tools (AJDT), Version 2.2.0
    • Markdown Text Editor, Version 0.9.0
  3. Aktualisierung der Datei pom.xml:
    • Anpassungen an die OpenJDK Version
    • GitHub Einträge (SCM und URL) hinzugefügt
    • Aktualisierung der Libraries auf aktuellerer Versionen (z. B. Spring Version 3.1.2.RELEASE, Hibernate Version 4.1.7.Final, JUnit Version 4.10, mockito Version 1.9.0, …)
      Die genaueren Versionen bitte aus den jeweiligen pom.xml auf GitHub entnehmen.

Weitere Beiträge dieser Serie. [verstecken]

  • Einführung in das Spring Framework
    • Spring an einem einfachem Beispiel
    • Spring mit AOP
    • Spring mit JPA und Hibernate
    • Spring mit einer einfachen Webanwendung
    • Spring mit einer Webanwendung mit JPA und Validierung
    • Spring Security mit einer Webanwendung
    • Spring mit RESTful Webservice
    • Spring und Stored Procedures mit User-defined Types
  • Über
  • Letzte Artikel
Frank Rahn
Frank Rahn
Frank Rahn ist Softwarearchitekt. Er unterstützt bei der Konzeption von Softwarearchitekturen mit Java-Technologie. Folge Sie ihm auf Facebook oder Twitter.

Benötigen Sie Unterstützung? Kontaktieren Sie ihn.

Hat Ihnen dieser Beitrag gefallen? Wir würden uns über Ihren Kommentar freuen! Bitte verwenden Sie Ihren bürgerlichen Namen.
Frank Rahn
Letzte Artikel von Frank Rahn (Alle anzeigen)
  • Wer ist der optimale Java Bean Mapper? - Freitag, 22. September 2023
  • Spring Boot Webanwendung: Die ersten Schritte (Tutorial) - Montag, 28. März 2016
  • Mainframe-Zugriff via Java - Sonntag, 04. Mai 2014
2 Kommentare/von Frank Rahn
Schlagworte: Architektur, Cookies, DI, HTML, HTTP, IoC, Java, Java EE, Java SE, MVC, Open Source Software, POJO, Spring, URI, URL, XML
Eintrag teilen
  • Teilen auf X
  • Teilen auf WhatsApp
  • Teilen auf LinkedIn
  • Per E-Mail teilen
  • Teilen auf Xing
https://www.frank-rahn.de/wp-content/uploads/project-test-spring-web-view5.png 1280 2000 Frank Rahn /wp-content/uploads/logo.png Frank Rahn2011-09-01 22:07:512025-02-02 20:34:01Spring mit einer einfachen Webanwendung (Tutorial)
Das könnte Dich auch interessieren
Klassendiagramm dieses Beispiels Spring mit JPA und Hibernate (Tutorial)
Der Service der Fahrerverwaltung Spring mit einer Webanwendung mit JPA und Validierung (Tutorial)
Dieses Bild zeigt meinen IT-Werkzeugkasten Franks aktueller IT-Werkzeugkasten
Grobe Übersicht üder den Spring Framework Container Einführung in das Spring Framework
Das Linux-Maskottchen: Pinguin Tux Flash BIOS unter Linux (Howto)
Das Schaubild eines RESTful Webservices RESTful-Webservices (REST-API-Design)
2 Kommentare
  1. Gustav S.
    Gustav S. sagte:
    Freitag, 06. April 2012 um 16:41 Uhr

    Warum wird hier Load-Time-Weaving eingesetzt?

    Antworten
    • Frank Rahn
      Frank Rahn sagte:
      Sonntag, 08. April 2012 um 17:48 Uhr

      Spring setzt AOP-Proxies z. B. für die Behandlung von Annotationen, wie @Transactional, an Spring Beans ein. Dabei unterscheidet das Spring Framework drei Varianten (Siehe auch Spring mit AOP):

      Dynamic Proxy des JDK’s
      In diesem Fall müssen die Annotationen an Methoden des Beans stehen, die in Interfaces deklariert worden sind. Das Proxy implementiert ausschließlich die Methoden der Interfaces, die das Spring Bean implementiert und nur dort stehen die Erweiterungen zu Verfügung. Die Annotation an anderen Methoden werden ignoriert.

      Subclassing mit CGLIB
      In diesem Fall werden die Erweiterungen durch das Ableiten der Klasse des Spring Beans bereitgestellt. Dadurch können nur ableitbare Methoden berücksichtigt werden. Die Annotationen an private und final Methoden werden ignoriert.

      AspectJ
      In diesem Fall werden die Erweiterungen direkt in die kompilierte Klasse eingewoben (Weaving). Dieses kann zur Laufzeit (Load-Time) oder beim Builden (Compile-Time) geschehen. AspectJ berücksichtigt alle Methode der Spring Bean.

      Bei AOP mit AspectJ kann Spring bestimmte Annotation, wie z. B. @Transactional, auch an privaten Methoden unterstützen. Daher wird hier in diesem Beispiel das Load-Time-Weaving eingeführt. Gerade bei Transaktion, die möglichst klein bzw. kurz sein sollen, ist es sinnvoll diese Technik einzusetzen. Bei häufig angewendeten Aspekten hat AspectJ leichte Vorteile in der Performance.

      Antworten

Hinterlasse einen Kommentar

An der Diskussion beteiligen?
Hinterlasse uns deinen Kommentar!

Schreibe einen Kommentar Antwort abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Ihre E-Mail-Adresse wird nicht veröffentlicht. Ihr Kommentar wird verschlüsselt an meinen Server gesendet. Erforderliche Felder sind mit * markiert.

Weitere Informationen und Widerrufshinweise finden Sie in meiner Datenschutzerklärung.

Wollen Sie kein neuen Beiträge mehr verpassen?
Dann abonnieren Sie bitte meinen Newsletter.
Meinen Newsletter abonnieren

Themen

  • Wer ist der optimale Java Bean Mapper?
  • Einführung in das Spring Framework, Boot, Batch, Data, REST, Security, Web, …
  • Franks aktueller IT-Werkzeugkasten
  • Git, GitHub, EGit, …

Navigation

  • Buchtipps
  • Newsletter
  • Weblinks
Search Search

Werbung

  • JProfiler
Beliebt
  • Das Klassendiagramm für den Java Bean Mapper Test am Beispiel "ByHand"
    Wer ist der optimale Java Bean Mapper?Freitag, 22. September 2023 - 20:59 Uhr
  • Das offizielle Logo von EGit
    GitHub mit Eclipse (EGit)Freitag, 26. Oktober 2012 - 16:15 Uhr
  • Grobe Übersicht üder den Spring Framework Container
    Einführung in das Spring FrameworkSonntag, 01. Mai 2011 - 18:30 Uhr
  • Die Stored Procedure "searchPersons" mit User-defined Types (UDT)
    Spring und Stored Procedure mit User-defined Types (Tut...Freitag, 26. Oktober 2012 - 21:45 Uhr
  • Spring Boot Webanwendung
    Spring Boot Webanwendung: Die ersten Schritte (Tutorial...Montag, 28. März 2016 - 16:29 Uhr
Schlagworte
Annotations AOP Architektur Autorisierung Cookies CRUD DAO DI Git HTML HTTP IoC Java Java EE Java SE JPA JSR Linux MVC Open Source Software PDF POJO REST (RESTful) ROCA Self-contained Systems Serviceorientierte Shell Sicherheit (Security) SOAP Spring SQL SVN Test Toolchain URI URL URN User-defined Type Versionsverwaltung VPN Webservice WS-* WSDL XML XML-Schema

Blogarchiv

Links

Mastodon
Twitter
LinkedIn
Xing
GitHub

Lizenz

Creative Commons Lizenzvertrag Die Texte (nicht Bilder) von Frank Rahn stehen unter einer Creative Commons Namensnennung - Keine Bearbeitungen 4.0 Deutschland Lizenz.

Affiliate-Links

Die mit (*) gekennzeichnete Links sind sogenannte Affiliate-Links. Kommt über einen solchen Link ein Einkauf zustande, werde ich mit einer Provision beteiligt. Für Sie entstehen dabei keine Mehrkosten. Wo, wann und wie Sie ein Produkt kaufen, bleibt natürlich Ihnen überlassen.

Blogkategorien

Copyright © Frank W. Rahn
  • Impressum / HaftungsausschlussDie notwendigen gesetzlichen Angaben dieser Webseite von Frank Rahn
  • DatenschutzerklärungDie Datenschutzerklärung von Frank Rahn
  • NewsletterKeine neuen Beiträge mehr verpassen!
  • BildnachweisDer komplette Bildnachweis von Frank Rahn
Link to: Spring mit JPA und Hibernate (Tutorial) Link to: Spring mit JPA und Hibernate (Tutorial) Spring mit JPA und Hibernate (Tutorial)Klassendiagramm dieses Beispiels Link to: Spring mit einer Webanwendung mit JPA und Validierung (Tutorial) Link to: Spring mit einer Webanwendung mit JPA und Validierung (Tutorial) Der Service der FahrerverwaltungSpring mit einer Webanwendung mit JPA und Validierung (Tutorial)
Nach oben scrollen Nach oben scrollen Nach oben scrollen

Wir setzen auf unserer Webseite verschiedene Arten von Cookies ein, die auf Ihrem Gerät gespeichert werden. Einige dieser Cookies sind für die einwandfreie Funktion der Webseite notwendig, während andere Cookies Ihnen ein besseres Besuchererlebnis bieten.

DatenschutzerklärungImpressumAlle Cookies akzeptierenKeine Cookies akzeptierenIndividuelle Cookie-Einstellungen vornehmen

Cookie- und Datenschutzeinstellungen



Wie wir Cookies verwenden

Wir setzen auf unserer Webseite verschiedene Arten von Cookies ein, die auf Ihrem Gerät gespeichert werden.

Einige dieser Cookies sind für die einwandfreie Funktion der Webseite notwendig, während andere Cookies Ihnen ein besseres Besuchererlebnis bieten.

Klicken Sie links auf die verschiedenen Reitern, um mehr zu erfahren. Sie können auch einige Cookie-Einstellungen individuell anpassen. Beachten Sie, dass das Blockieren einiger Cookies die einwandfreie Funktion unserer Webseite beeinträchtigt.

Technisch notwendige Cookies

Diese Cookies sind unbedingt erforderlich, denn sie ermöglichen grundlegende Funktionen und sind für die einwandfreie Funktion der Webseite erforderlich.

Sie können diese Cookies jederzeit blockieren oder löschen, indem Sie Ihre Browsereinstellungen ändern und die Blockierung aller Cookies auf dieser Webseite erzwingen. Leider werden Sie dann immer wieder gefragt, ob Sie Cookies akzeptieren oder ablehnen wollen, wenn Sie unsere Webseite erneut besuchen.

Wir setzen die Cookies aviaPrivacyEssentialCookiesEnabled, aviaPrivacyMustOptInSetting, aviaPrivacyRefuseCookiesHideBar und aviaCookieConsent ein, um Ihre individuellen Cookie-Einstellungen zu speichern. Diese Informationen geben wir an keinen Drittanbietern weiter.

Diese Cookies haben eine Laufzeit von einem Jahr, dann müssen Sie die Einstellungen wiederholen.

Die VG WORT setzt das Sitzungscookie srp zur Messung von Zugriffen auf Texten, um die Kopierwahrscheinlichkeit des Textes zu erfassen. Damit partizipieren ich an den Ausschüttungen der VG WORT, welche die gesetzliche Vergütung für die Nutzungen urheberrechtlich geschützter Werke gemäß § 53 UrhG sicherstellen. Das Cookie wird dazu verwendet, um den Nutzer zu identifizieren und ggf. Daten mehrerer Aufrufe von Texten miteinander verknüpfen zu können.

Nach Angaben der VG WORT stellt das eingesetzte Verfahren sicher, dass einzelne Nutzer oder ihr Leseverhalten nicht ermittelbar sind, wenn die Anzahl der Textaufrufe gezählt wird. Alle von der VG Wort erfassten Daten werden sofort sicher verschlüsselt. Der Einsatz des Zählpixels wurde durch das Bayerische Landesamt für Datenschutzaufsicht begutachtet und als datenschutzkonform bewertet.

Datenschutzerklärung der VG WORT

Marketing-Cookies

Die Marketing-Cookies werden von Drittanbietern oder Publishern, wie z. B. Google Analytics, verwendet, um personalisierte Werbung anzuzeigen. Sie tun dies, indem sie Besucher über Webseiten hinweg verfolgen (Tracking).

Wir setzen keine Marketing-Cookies ein.

Datenschutzbestimmungen

Sie können unsere Cookies und Datenschutzeinstellungen im Detail in unserer Datenschutzerklärung nachlesen.

Cookie-Einstellungen übernehmenKeine Cookies akzeptieren
Nachrichtenleiste öffnen Nachrichtenleiste öffnen Nachrichtenleiste öffnen