Mit Java ins Web: Eine Spring-MVC-Anwendung im Detail, Teil 1

Mit Spring MVC lassen sich in Kombination mit JavaScript dynamische und REST-konforme Webapplikationen mit Java umsetzen.

In Pocket speichern vorlesen Druckansicht 12 Kommentare lesen
Lesezeit: 22 Min.
Von
  • Jan Petzold
Inhaltsverzeichnis

Mit Spring MVC lassen sich in Kombination mit JavaScript dynamische und REST-konforme Webapplikationen mit Java umsetzen. Ein zweiteiliges Tutorial bietet einen Leitfaden zur Entwicklung einer Webanwendung mit Spring 3, JavaScript und einer Datenbank.

Spring ist in den letzten Jahren zu einem wichtigen Java-Framework geworden. Entstanden aus einer gewissen Frustration über bestehende Java-EE-Techniken (Java Enterprise Edition) und dem Wunsch nach einer leichteren Entkopplung von Softwarekomponenten bietet es heute viele vereinheitlichte Module an, die in vielen Softwareprojekten nützlich sein können. Für Webanwendungen sind neben dem Kern-Framework vor allem die Module Spring MVC und Spring Web Flow relevant.

Mit dem hier behandelten Spring MVC lassen sich in Kombination mit JavaScript dynamische und REST-konforme Webapplikationen mit Java umsetzen. Es bietet eine übersichtliche Model-View-Controller-Struktur und kann auf etablierte Techniken wie JPA (Java Persistence API) und JSP (Java Server Pages) zurückgreifen. Im Tutorial entsteht unter Eclipse eine Webanwendung mit Datenbankanbindung, die auf Spring 3 beruht und neben den üblichen CRUD-Methoden (Create, Read, Update, Delete) Hilfsfunktionen wie eine Suche mit automatischer Vervollständigung sowie eine Fehlerkorrektur einbindet.

Der Autor zeigt den Quelltext in den Artikeln jedoch nur auszugsweise. Sicht- und benutzbar ist die Anwendung unter citiesoftheworld.cloudfoundry.com. Der komplette Quelltext der Anwendung lässt sich als Eclipse-Projekt herunterladen.

Zwei wesentliche Funktionen von Spring (Abstraktion, Dependency Injection, aspektorientierte Programmierung) sind in der Fachliteratur umfänglich beschrieben. Erwähnenswert bleibt, dass sich Dependency Injection seit Version 2.5 auch im Java-Code über Annotationen setzen lässt. Dazu ein Kurz-Beispiel:

// Klasse CityService
@Service
public class CityService {
    // Hier folgen Felder und Methoden
}

// andere Klasse, bekommt Objekt der Klasse CityService injiziert
public class myClass {
    private CityService cityservice;
   
    @Autowired
    public void setCityService(cityService) {
        this.cityService = cityService;
    }
}

Im Wesentlichen entkoppelt Dependency Injection die Klassen einer Anwendung, sie lassen sich leichter wiederverwenden und testen. Generell gibt es unter den einzelnen Spring-Modulen wenig Abhängigkeiten, der Entwickler kann sich die Teile herausgreifen, die für seine Anwendung von Belang sind, und bekommt darüber hinaus nichts "aufgezwungen". Somit lässt sich Spring gut mit anderen Techniken aus dem Java-Umfeld kombinieren.

MVC besagt, dass in einer Anwendung jederzeit das Datenmodell von der Präsentationsschicht und der Ablaufsteuerung getrennt sein muss. Übersetzt auf typische Java-Webapplikationen bedeutet das, dass auf der (JSP-)Seite keinerlei Anwendungslogik stehen darf und die Daten zwischen Oberfläche (= View) und Datenbank (= Model) über einen sogenannten Controller übermittelt werden. Der Ansatz trennt die Schichten sauber, erleichtert Tests und vermeidet schwer zu pflegenden "Spaghetti-Code". Außerdem lässt sich die Arbeit im Team leichter aufteilen – der Datenbankspezialist kann sich mit der Datenbank und dem zugehörigen "Model" beschäftigen, während sich ein Frontend-Entwickler weitgehend auf seine "View" konzentriert. Spring führt zur Implementierung das zentrale DispatcherServlet ein, das in der Serverkonfiguration (web.xml) einzurichten ist:

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.
           DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/app/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/spring/*</url-pattern>
</servlet-mapping>

Das Servlet hat den Namen appServlet und reagiert auf alle eingehenden Requests unter /spring/. Dadurch lässt sich der MVC-Teil vom Rest der Applikation trennen. Darüber hinaus ist in der Konfiguration noch ein Package zu definieren, in dem Spring nach Controllern sucht:

<context:component-scan base-package="com.example.spring3cities" />

In der Anwendung findet der Leser den Controller im Package com.example.spring3cities. Sofern in einer Klasse die Annotation @Controller gesetzt ist, erkennt das Programm diese automatisch als Controller. Hier ein Beispiel:

@Controller
Public class CityController {
    @RequestMapping(value="/city", method=RequestMethod.GET)
    public String homeHandler(Model model) {
        String message = "Hello world!"
        model.addAttribute("myMessage", message);
        return "home";
    }   
}

Die Annotation @RequestMapping weist der URL eine Methode zu: Im Beispiel würde die Funktion homeHandler alle Aufrufe unterhalb des Verzeichnisses /city verarbeiten. Als HTTP-Requestmethode ist hier GET angegeben.  Lässt der Entwickler die Angabe weg, gilt die Funktion  für alle HTTP-Request-Methoden.

homeHandler liest die Variable model aus und liefert den String home zurück, was unter Spring automatisch dazu führt, dass das Programm die View home.jsp aufruft. model übergibt sozusagen die initial aufgerufene View und erhält zusätzlich das Attribut message. In der JSP wird zur Ausgabe der gelieferten Informationen einfach ein Platzhalter eingefügt:

<h1>${myMessage}</h1>

In der Überschrift steht anstelle des Platzhalters nun wie erwartet "Hello world!". Im Wesentlichen ist das die Umsetzung des MVC-Prinzips in Spring. Der Ansatz hat mehrere Vorteile: Zum einen lässt sich anhand der URL eindeutig nach Funktionen unterscheiden. Im Ergebnis entstehen automatisch REST-konforme Webanwendungen mit sauberen (suchmaschinenfreundlichen) URLs ohne weitere Konfiguration. Nicht definierte URLs werden ignoriert.

Das RequestMapping kann natürlich auch GET- und POST-Parameter aus der JSP-Seite enthalten. Der Controller setzt diese in eine sogenannte PathVariable:

@RequestMapping(value="/city/details/{cityId}", method=RequestMethod.POST)
public String getCityDetails(@PathVariable("cityid") int id) {
    // Variable    cityid enthält die ID aus der URL

Mit Spring Roo existiert darüber hinaus ein sich besonders für MVC-Anwendungen passender Generator zum Aufsetzen einer Spring-Anwendung. Roo eignet sich bisher vor allem für das Prototyping, setzt aber ein gutes Spring-Verständnis voraus, da der zu großen Teilen automatisch generierte Sourcecode nie unangepasst bleiben dürfte.