Java Webprogrammierung mit Spring und Maven (Teil 1) (Permalink)

20. September 2012: Update auf Spring 3.1.2-RELEASE

Dieser Artikel führt knapp in die Webprogrammierung mit Java ein. Wir setzen dabei auf einen Model-View-Controller-Ansatz unterstützt durch das Spring-Framework, speziell das Web MVC Framework.

Dabei baut dieser Artikel auf den Grundlagenartikeln zu Maven auf. Die ersten beiden Artikel der sind hier verlinkt: Teil 1, Teil 2. Alle Artikel zum Thema Maven finden sich in der entsprechenden Kategorie.

Nachfolgend sieht man die Verzeichnisstruktur und die Dateien eines Maven-Projektes, welches eine simple Webapplikation auf Spring-Basis darstellt.

projekt                                             ( 1)
 + pom.xml                                          ( 2)
 + src                                              (  )
 |  + main                                          (  )
 |  |  + java                                       (  )
 |  |  |  + de/lusiardi/testprojekt/controller/     (  )
 |  |  |     + MainController.java                  ( 3)
 |  |  + webapp                                     ( 4)
 |  |     + META-INF                                (  )
 |  |     |  + context.xml                          ( 5)
 |  |     + WEB-INF                                 (  )
 |  |     |  + web.xml                              ( 6)
 |  |     |  + spring-servlet.xml                   ( 7)
 |  |     + views                                   ( 8)
 |  |     |  + view.jsp                             ( 9)
 |  |     + index.jsp                               (10)
 |  + test                                          (  )
 |     + java                                       (  )
 + target                                           (  )

Nun sollen die einzelnen Teile des Projektes beschrieben werden.

1) Wurzelverzeichnis des Projekts

Hier beginnt der ganze Spass und alles, was man zum bauen benötigt liegt in diesem Verzeichnis.

2) pom.xml

Die aus Teil 1 und Teil 2 bekannte Verwaltungsdatei für Maven. Die klassische POM für Abhängigkeiten und Build-Prozess.

<project 
    xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
            http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>de.lusiardi</groupId>
    <artifactId>testprojekt</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>testprojekt</name>

    <properties>
        <project.build.sourceEncoding>
            UTF-8
        </project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>3.1.2.RELEASE</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Wichtig sind hier lediglich die beiden Dependencies für spring-webmvc und javax.servlet-api. provided bedeutet in diesem Zusammenhang, dass diese Dependency nicht mit in das entstehende Artefakt gepackt werden soll, da sie vom Servlet Container bereit gestellt wird. Über das maven-compiler-plugin legt man die verwendeten Java-Versionen fest, da sonst Annotationen nicht unterstützt werden.

3) Controller Java Klasse

Das eingesetzte Spring-Framework Web MVC ermöglicht durch einfache Annotationen das Ausweisen von Controllern.

package de.lusiardi.testprojekt.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MainController {

    @RequestMapping("view")
    public ModelAndView getTest() {
        return new ModelAndView("view", "key", "value");
    }
}

In diesem Beispiel-Controller (ausgezeichnet durch die \@Controller Annotation) existiert ein einzelnes Mapping für Anfragen (\@RequestMapping Annotation). Die Funktion getTest wird für alle Anfragen an die URL

http://localhost:8080/testprojekt-1.0-SNAPSHOT/main/view.html

aufgerufen. Über die Rückgabe der ModelAndView-Instanz wird die View mit Namen view aufgerufen und das Modell an die View. Das Modell ist in diesem Fall ein String, der unter "key" zugreifbar ist.

4) Konfigurationen für Webapplikation

Webapplikationen werden in der Java-Welt über war-Dateien verteilt. In der Spezifikation ist die Struktur der Daten festgelegt. Der Inhalt des Verzeichnisses webapp wird in die war-Datei direkt eingefügt.

5) context.xml

Dies ist der Tomcat Context Descriptor und legt den ersten Teil der URL nach dem Server fest. Dieser muss eindeutig sein.

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/HelloMaven"/>

6) web.xml

In der Datei web.xml können einige grundlegende Einstellungen der Web-Applikation getätigt werden.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
    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">

    <display-name>Spring3MVC</display-name>

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

    <servlet>
        <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>*.html</url-pattern>
    </servlet-mapping>

</web-app>

In diesem Beispiel legen wir den Anzeigenamen (display-name) der Applikation fest. Die welcome-file-list gibt an welche Dateien verwendet werden sollen, wenn Anfragen direkt auf ein Verzeichnis gehen. Als nächstes wird ein servlet vom Spring-Typ DispatcherServlet und ein entsprechendes servlet-mapping auf alle html-Dateien.

7) spring-servlet.xml

Der Name der Konfigurationsdatei spring-servlet.xml ergibt sich aus dem Namen des Servlets in der web.xml. Es existiert also für jedes Servlet eine entsprechende Datei.

<?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/mvc 
         http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
       http://www.springframework.org/schema/context 
         http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />

    <context:component-scan base-package="de.lusiardi.testprojekt" />

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>

    <mvc:annotation-driven />

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

Durch die Definition eine Bean vom Spring-Typ ControllerClassNameHandlerMapping wird festgelegt, das per Konvention aus MainController der Pfad /main/ wird.

Über context:component-scan aktiviert man die Unterstützung für die verwendeten Annotationen im angegeben Package. Die ermöglicht in Kombination mit mvc:annotation-driven die Einführung des Controllers rein über Annotationen.

Die Bean viewResolver vom Typ InternalResourceViewResolver ermöglicht es, Views wie im Controller getan, einfach nur über den Namen anzusprechen. Hier sieht man die Möglichkeit, Beans mit speziellen Eigenschaften (Properties) zu versorgen. Prefix und Suffix kompletieren die Namen der Views und ergeben den Dateinamen.

8) Ordner für die Views

In diesem Ordner werden die Views gespeichert. Der Name des Ordners ist wie in der spring-servlet.xml (7) beim ViewResolver als Prefix definiert.

9) view.jsp

Views dienen zur tatsächlichen Darstellung des Models in Model-View-Controler. Hier sind die VIews in JSP geschrieben.

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <title>Lusiardi.de - Tutorial</title>
    </head>
    <body>
        <a href="../">${key}</a><br />
    </body>
</html>

Hier wird über \${key} auf das Model (den einzelnen String) zugegriffen, und dieser ausgegeben.

10) index.jsp

Die in der web.xml (6) festgelegte Welcome-Page

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <title>Lusiardi.de - Tutorial</title>
    </head>
    <body>
    <a href="main/view.html">Controller</a><br />
    </body>
</html>

Bauen

In diesem Fall ist das Ergebnis der Bemühungen keine JAR-Datei, sondern eine WAR-Datei. WAR steht für WebARchive. Aufgrund des in der pom.xml festegelegten packaging war, wird durch folgenden Aufruf die fertige WAR-Datei erzeugt.

mvn package

Dabei entsteht im target-Verzeichnis die Datei testprojekt-1.0-SNAPSHOT.war. Diese kann dann in einem Tomcat oder anderen Servlet-Container ausgeführt werden.

Résumé

Java und Webentwicklung haben höhere Einstiegshürden als andere Techniken. Das stimmt zweifelsfrei. Inzwischen kann aber über entsprechende Frameworks viel dieser Komplexität abgefangen werden, wenn man sich klar gemacht hat, was diese Frameworks exakt tun.

Dieser Artikel war lediglich eine kurze Einführung in dieses Thema und lässt auch vieles, was IDEs leisten können, bewusst aussen vor, um ein wenig Licht in diesen Bereich zu bringen.

Update 6. Juni 2018

Die Quellen zu diesem Artikel findet man jetzt unter https://gitea.lusiardi.de/jlusiardi/webbasics1. Maven 3.3 kann in einem Docker-Container mit folgendem Kommando zum Build benutzt werden:

docker run -it --rm -v "$(pwd)":/usr/src/mymaven
 -w /usr/src/mymaven maven:3.3-jdk-8 mvn clean install