Auf dem Weg zum Action-based Standard

MVC 1.0 Tutorial: Einführung in das aktionsbasierte Java Webframework

Sven Kölpin

© Shutterstock / Alexander Supertramp

Die MVC-1.0-Spezifikation (aka JSR 371) hatte es bisher nicht gerade einfach. Ursprünglich war sie als Teil von Java EE 8 geplant, um eine leichtgewichtige Alternative zum komponentenbasierten JSF-Framework zu bieten. Im Zuge der von Oracle geplanten Neuausrichtung der Java-Enterprise-Plattform auf Cloud-Computing wurde die Spezifikation aber wieder entfernt.

Anstatt MVC 1.0 komplett zu verwerfen, übernahm Ivar Grimstad das Projekt und agiert seitdem mit der Unterstützung von Christian Kaltepoth unabhängig von Oracle als Specification Lead. Langfristig soll die Spezifikation an das EE4J-Projekt übertragen werden und so wieder Teil des gesamten „Standards“ werden. Voraussetzung dafür ist aber laut Grimstad, dass MVC 1.0 zuvor einen finalen Releasestatus erreicht. Das soll in Q2 2018 der Fall sein.

Warum überhaupt MVC 1.0?

MVC 1.0 ermöglicht die Entwicklung Action-basierter Webanwendungen. Im Gegensatz zu komponentenbasierten Webframeworks wie JSF, bei denen Webtechnologien wie HTML und JavaScript sowie Interaktionen mit HTTP weitestgehend vom Entwickler versteckt sind, wird bei Action-basierten Frameworks vergleichsweise wenig abstrahiert. Vielmehr finden sich Entwickler in der klassischen, Request- und Response-basierten Webentwicklung wieder.

Der Vorteil des Action-basierten Ansatzes liegt vor allem in der Leichtgewichtigkeit und Flexibilität. Durch die geringe Abstraktion sind diese Art von Webframeworks zumeist weniger komplex als komponentenbasierte Ansätze wie JSF. Zudem lassen sich beim Action-basierten Vorgehen beliebige architektonische und technische Ansätze kombinieren, weil die Frameworks in der Regel flexibel sind und nur wenig vorschreiben. Der Preis der geringen Abstraktion liegt aber im Umkehrschluss darin, dass Entwickler sich wieder vermehrt mit Webtechnologien auseinandersetzen müssen. Zudem kann der programmatische Aufwand höher sein, als bei komponentenbasierten Webframeworks.

Action-basierte Ansätze eignen sich auch bei der Entwicklung von Single Page Applications (SPAs). Schließlich wird hier ein Großteil der Anwendung erst auf dem Client gerendert. Die Aufgaben des serverseitigen Webframeworks sind also eher überschaubar. Leichtgewichtige und flexible Frameworks wie MVC 1.0 passen deshalb besonders gut zu SPAs.

W-JAX 2018 Java-Dossier für Software-Architekten

Kostenlos: 40+ Seiten Java-Wissen von Experten

Sie finden Artikel zu Enterprise Java, Software-Architektur, Agilität, Java 11, Deep Learning und Docker von Experten wie Kai Tödter (Siemens), Arne Limburg (Open Knowledge), Manfred Steyer (SOFTWAREarchitekt.at) und vielen weiteren.

MVC 1.0

Im Gegensatz zu manch anderer Spezifikation ist die von MVC 1.0 nicht sehr umfangreich. Die rein technische Beschreibung des Frameworks ist auf nur knapp über 30 Seiten zusammengefasst. Das hat zwei Gründe: Zum einen ist das Featureset von MVC 1.0 klein, das Framework muss sich schließlich um vergleichsweise wenige Dinge kümmern. Zum anderen basiert MVC 1.0 zum Großteil auf den bestehenden Standards JAX-RS, CDI und Bean Validation. Die Spezifikation ist also hauptsächlich eine Kombination aus etablierten Technologien und benötigt deshalb nur wenige neue Interfaces und Annotationen. Die Grundlage für MVC 1.0 bildet JAX-RS. Genau wie bei JAX-RS steht auch bei MVC 1.0 die HTTP-Kommunikation im Vordergrund. Ein Großteil der Interfaces und Annotationen kann hier deshalb einfach wiederverwendet werden. Wie bei allen neueren EE-APIs ist zudem der CDI-Standard zwingende Voraussetzung für die Verwendung von MVC 1.0. CDI wird beispielsweise für die Integration der Model-Schicht verwendet. Der Bean-Validation-Standard kommt bei der serverseitigen Validierung zum Einsatz.

Controller

Das Herzstück in MVC 1.0 bilden die Controller. Hier werden HTTP-Anfragen entgegengenommen, Parameter validiert, Model-Manipulationen initiiert und schlussendlich das Rendern einer Antwort veranlasst. Technisch gesehen ist ein Controller nichts weiter als eine JAX-RS-Ressourcenmethode, die mit der MVC-1.0-spezifischen Annotation @Controller versehen ist. Diese Annotation kann sowohl an Klassen als auch an einzelne Methoden geschrieben werden. Letzteres erlaubt die Erstellung von hybriden Controllern, die sowohl Controller-Methoden als auch herkömmliche JAX-RS-Ressourcen beinhalten (Listing 1).

@Path("/")
public class HelloController {

  @Controller
  @GET
  @Path("view")
  public String getIndexView() {
    //MVC Controller method. 
    //Returns path to view & sends HTML.
    return "index.jsp";
  }

  @GET
  @Path("data")
  @Produces(MediaType.APPLICATION_JSON)
  public Response getJsonData() {
    //JAX-RS method. Sends JSON.
    return Response.ok(…).build();
  }
}

Der Rückgabewert einer Controller-Methode wird als Pfad zu einer View-Datei interpretiert und standardmäßig relativ zum /WEB-INF/views/ Ordner aufgelöst. Es gibt insgesamt drei verschiedene Möglichkeiten, den Rückgabewert einer Controller-Methode zu definieren (Listing 2).

@Controller
@Path("/")
public class HelloController {

  @GET
  @Path("void")
  @View("hello.jsp")
  public void helloVoid() {
  }

  @GET
  @Path("string")
  public String helloString() {
    return "hello.jsp";
  }

  @GET
  @Path("response")
  public Response helloResponse() {
    return Response.status(Response.Status.OK)
      .entity("hello.jsp")
      .build();
  }
}

Wie eingangs erwähnt, ist CDI ein zwingender Bestandteil von MVC 1.0. Jede Controller-Klasse muss deshalb CDI-managed sein. Die Lebensdauer von Controllern ist standardmäßig „per request“ (CDI-@RequestScoped), es können aber auch andere CDI-Scopes verwendet werden (z. B. @SessionScoped-Controller für statusvolle Anwendungen).

Model

Controller sind dafür verantwortlich, die Views und Datenmodelle (Models) zu kombinieren, um das Rendern dynamischer Webanwendungen zu ermöglichen. MVC 1.0 unterstützt zwei Arten von Models: CDI-@Named-Beans und das MVC-1.0-eigene Models-Interface.

CDI-@Named-Beans können, wie es beispielsweise auch in JSF möglich ist, dazu verwendet werden, Daten in den jeweiligen Views zur Verfügung zu stellen. Dazu lassen sich beliebige CDI-@Named-Beans in einen Controller injizieren und von dort aus manipulieren (Listing 3). Voraussetzung für diese Art von Models ist allerdings, dass die jeweilig verwendete View-Engine @Named-Beans unterstützt (z.B. JSP oder Facelets).

@Named
@SessionScoped
public class GreetingBean {
  private String message;

  //getter + setter...
}

@Controller
@Path("hello")
public class HelloController {
  @Inject
  private GreetingBean greeting;
  @GET
  public String hello() {
    //Can be used as "greetingBean.message" in a view
    greeting.setMessage("Hello there!");
    return "hello.jsp";
  }
}

Auch das Models-Interface lässt sich dazu verwenden, Daten an den View zu übermitteln. Dieses spezielle Interface, das eine Art von String-Object-Map repräsentiert, kann ebenfalls mithilfe von CDI in einen Controller injiziert und dort manipuliert werden (Listing 4).

@Controller
@Path("hello")
public class HelloController {
  @Inject
  private Models models;

  @GET
  public String hello() {
    //Can be used as "greeting.message" in a view
    models.put("greeting", new Greeting("Hello there!"));
    return "hello.jsp";
  }
}

Laut der MVC-1.0-Spezifikation sind View Engines nicht dazu verpflichtet, CDI-@Named-Beans zu unterstützen. Trotzdem ist deren Verwendung, sofern möglich, der des Models-Interface vorzuziehen. CDI-Beans sind durch die verschiedenen Scopes (z. B. @Request-Scoped, @SessionScoped) viel flexibler und führen außerdem zu einer klaren Trennung der Model- und Controller-Schicht.

View

In MVC 1.0 ist nicht festgelegt, welche Templating Engine zum Rendern des dynamischen HTML auf Basis der Models verwendet wird. Standardmäßig müssen jedoch JSP und die aus JSF bekannte Templating Engine Facelets zur Verfügung stehen. Listing 5 zeigt, wie in den Views auf die Daten des Models zugegriffen werden kann. Als Templating Engine kommt in diesem Beispiel JSP zum Einsatz.

<!DOCTYPE html>
<html>
<head>
  <title>Hello</title>
</head>
<body>
  <!-- Access Models-Interface -->
  <h1>${greeting.message}</h1>
  <!-- Access CDI-@Named-Bean -->
  <h1>${greetingBean.message}</h1>
</body>
</html>

Formularbehandlung und Validierung

Mit der @FormParam-Annotation, die Teil des JAXRS-Standards ist, lassen sich im Request übermittelte Parameter eines Formulars extrahieren. Zudem ist es möglich, mithilfe der @BeanParam-Annotation mehrere Parameter in einer Klasse zusammenzufassen. Für die Validierung der Request-Parameter wird der Bean-Validation-Standard in Kombination mit der MVC 1.0 spezifischen @MvcBinding-Annotation und dem BindingResult-Interface verwendet (Listing 6).

public class FormDataBean {
  @MvcBinding
  @FormParam("age")
  @Min(18)
  private long age;
  //getter + setter...
}
@Controller
@Path("form")
public class FormController {
  @Inject
  private BindingResult br;

  @POST
  public Response formPost(@Valid @BeanParam FormDataBean form) {
    if (br.isFailed()) {
      return Response.status(BAD_REQUEST)
        .entity("error.jsp").build();
    }
    return Response.status(OK).entity("index.jsp").build();
  }
}

Für Felder, die mit der @MvcBinding-Annotation versehen sind, werden etwaige Validierungsfehler in einer für den Request gültigen Instanz des BindingResult-Interface hinterlegt. Dieses kann mit CDI in einen Controller injiziert und für die Fehlerbehandlung verwendet werden. Validierungsfehler, die nicht durch die @MvcBinding-Annotation gemappt sind, enden in einer ConstraintViolationException. Diese kann, wie bereits aus JAX-RS bekannt, global mithilfe eines ExceptionMappers behandelt werden.

Redirects und ein neuer Scope

MVC 1.0 unterstützt von Haus aus Mechanismen, um Redirects zu initiieren und zu behandeln. Mithilfe von Redirects können Anfragen an eine Ressource zu einer anderen weitergeleitet werden. Beispielsweise lässt sich so das Post/Redirect/Get-Pattern umsetzen, das beim Log-in-Prozess (z. B. Umleiten vom LoginController zum HomeController) oder nach dem Absenden eines Formulars (Vermeidung von erneuten Submits) verwendet werden kann.

Um einen Redirect zu initiieren, muss der zurückgegebene Pfad eines Controllers mit dem Präfix redirect: beginnen (Listing 7). MVC 1.0 liefert zudem einen neuen CDI-Scope mit dem Namen @RedirectScoped. CDI-Beans, die damit annotiert sind, speichern Daten für genau einen Redirect und sind somit ein wenig mächtiger als @RequestScoped-Beans.

Security und Internationalisierung

MVC 1.0 bietet Mechanismen, um Attacken wie Crosssite Request Forgery (CSRF) und Cross-site Scripting (XSS) zu verhindern. Allerdings müssen diese erst aktiviert bzw. die APIs explizit verwendet werden. Eine MVC-1.0-Anwendung ist also nicht automatisch gegen CSRF- und XSS-Angriffe geschützt.

Für mehrsprachige Anwendungen gibt es in MVC 1.0 die Möglichkeit, den Ländercode (Locale) aus einem Request zu extrahieren. Dazu kann mithilfe von CDI das MvcContext-Interface in einen Controller injiziert werden. Das ermöglicht unter anderem den Zugriff auf das Locale-Object des aktuellen Request. So lassen sich Übersetzungen oder Zahlen- und Datumsformate dynamisch anpassen (Listing 8). Die zu verwendende Locale wird ohne weiteres aus dem Accept-Language-Header extrahiert, der im Normalfall vom Browser mitgesendet wird.

Fazit

Mit MVC 1.0 wurde das Rad keineswegs neu erfunden. Spring MVC ist beispielsweise seit Jahren mit ähnlichem Funktionsumfang der große Vertreter Action-basierter MVC-Frameworks im Java-Umfeld. Trotzdem hat MVC 1.0 durchaus eine Daseinsberechtigung – es fehlt in EE schließlich eine leichtgewichtige Alternative zu JSF, die im Zeitalter von Microservices und Single Page Applications dringend notwenig ist.

Die Spezifikation von MVC 1.0 ist zwar sehr schlank, liefert aber dennoch alle wichtigen Features, die es für die Entwicklung mit Action-basierten Frameworks braucht. Zudem ist die Einstiegshürde, nicht zuletzt durch die strikte Verwendung bestehender EE-Standards, vergleichsweise gering.

Geschrieben von
Sven Kölpin
Sven Kölpin
Sven Kölpin ist Enterprise Developer bei der open knowledge GmbH in Oldenburg. Sein Schwerpunkt liegt auf der Entwicklung webbasierter Enterprise-Lösungen mittels Java EE.
Kommentare

Hinterlasse einen Kommentar

3 Kommentare auf "MVC 1.0 Tutorial: Einführung in das aktionsbasierte Java Webframework"

avatar
400
  Subscribe  
Benachrichtige mich zu:
Marco Ebbinghaus
Gast

„Voraussetzung dafür ist aber laut Grimstad, dass MVC 1.0 zuvor einen finalen Releasestatus erreicht. Das soll in Q2 2018 der Fall sein.“ Also ist der Artikel alt oder ist es die falsche Jahreszahl?

Berthold Frank
Gast

Den Artikel habe ich bereits in der Septemberausgabe des Java Magazin gelesen. Demnach dürfte er ein paar Wochen alt sein, also nicht „so richtig alt“.

Interessanter ist aber, dass der Releasestatus laut der MVC-Webseite inzwischen erreicht wurde:
https://www.mvc-spec.org/news/2018/09/24/proposed-final-draft.html

Referat vorbereiten
Gast

ich habe auch den Beitrag in Java Magazin erstmal gelesen!