Eine Anleitung zum Front Controller-Muster in Java

1. Übersicht

In diesem Tutorial werden wir uns eingehender mit dem Front-Controller- Muster befassen , das Teil der Unternehmensmuster ist, wie sie in Martin Fowlers Buch „Muster der Architektur von Unternehmensanwendungen“ definiert sind.

Front Controller ist definiert als "ein Controller, der alle Anforderungen für eine Website verarbeitet". Es steht vor einer Webanwendung und delegiert Anforderungen an nachfolgende Ressourcen. Es bietet auch eine Schnittstelle zu allgemeinen Verhaltensweisen wie Sicherheit, Internationalisierung und der Präsentation bestimmter Ansichten für bestimmte Benutzer.

Dadurch kann eine Anwendung ihr Verhalten zur Laufzeit ändern. Darüber hinaus hilft es beim Lesen und Verwalten einer Anwendung, indem Code-Duplikationen verhindert werden.

Der Front Controller konsolidiert die gesamte Anforderungsbearbeitung, indem er Anforderungen über ein einziges Handlerobjekt kanalisiert.

2. Wie funktioniert es?

Das Front-Controller-Muster besteht hauptsächlich aus zwei Teilen. Eine einzelne Dispatching-Steuerung und eine Befehlshierarchie. Die folgende UML zeigt Klassenbeziehungen einer generischen Front Controller-Implementierung:

Dieser einzelne Controller sendet Anforderungen an Befehle, um das mit einer Anforderung verbundene Verhalten auszulösen.

Um die Implementierung zu demonstrieren, implementieren wir den Controller in ein FrontControllerServlet und Befehle als Klassen, die von einem abstrakten FrontCommand geerbt wurden .

3. Setup

3.1. Maven-Abhängigkeiten

Zuerst richten wir ein neues Maven WAR- Projekt mit javax.servlet-api ein:

 javax.servlet javax.servlet-api 4.0.0-b01 provided  

sowie Jetty-Maven-Plugin :

 org.eclipse.jetty jetty-maven-plugin 9.4.0.M1   /front-controller   

3.2. Modell

Als nächstes werden wir einen definieren Modellklasse und ein Modell Repository . Wir werden die folgende Buchklasse als unser Modell verwenden:

public class Book { private String author; private String title; private Double price; // standard constructors, getters and setters }

Dies ist das Repository. Sie können den Quellcode für eine konkrete Implementierung nachschlagen oder selbst bereitstellen:

public interface Bookshelf { default void init() { add(new Book("Wilson, Robert Anton & Shea, Robert", "Illuminati", 9.99)); add(new Book("Fowler, Martin", "Patterns of Enterprise Application Architecture", 27.88)); } Bookshelf getInstance();  boolean add(E book); Book findByTitle(String title); }

3.3. FrontControllerServlet

Die Implementierung des Servlets selbst ist ziemlich einfach. Wir extrahieren den Befehlsnamen aus einer Anforderung, erstellen dynamisch eine neue Instanz einer Befehlsklasse und führen sie aus.

Auf diese Weise können wir neue Befehle hinzufügen, ohne die Codebasis unseres Front Controllers zu ändern .

Eine andere Möglichkeit besteht darin, das Servlet mithilfe einer statischen, bedingten Logik zu implementieren. Dies hat den Vorteil einer Fehlerprüfung zur Kompilierungszeit:

public class FrontControllerServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { FrontCommand command = getCommand(request); command.init(getServletContext(), request, response); command.process(); } private FrontCommand getCommand(HttpServletRequest request) { try { Class type = Class.forName(String.format( "com.baeldung.enterprise.patterns.front." + "controller.commands.%sCommand", request.getParameter("command"))); return (FrontCommand) type .asSubclass(FrontCommand.class) .newInstance(); } catch (Exception e) { return new UnknownCommand(); } } }

3.4. FrontCommand

Implementieren wir eine abstrakte Klasse namens FrontCommand , die das allen Befehlen gemeinsame Verhalten enthält.

Diese Klasse hat Zugriff auf den ServletContext und seine Anforderungs- und Antwortobjekte . Darüber hinaus wird die Auflösung der Ansicht behandelt:

public abstract class FrontCommand { protected ServletContext context; protected HttpServletRequest request; protected HttpServletResponse response; public void init( ServletContext servletContext, HttpServletRequest servletRequest, HttpServletResponse servletResponse) { this.context = servletContext; this.request = servletRequest; this.response = servletResponse; } public abstract void process() throws ServletException, IOException; protected void forward(String target) throws ServletException, IOException { target = String.format("/WEB-INF/jsp/%s.jsp", target); RequestDispatcher dispatcher = context.getRequestDispatcher(target); dispatcher.forward(request, response); } }

Eine konkrete Implementierung dieses abstrakten FrontCommand wäre ein SearchCommand . Dies schließt bedingte Logik für Fälle ein, in denen ein Buch gefunden wurde oder wenn ein Buch fehlt:

public class SearchCommand extends FrontCommand { @Override public void process() throws ServletException, IOException { Book book = new BookshelfImpl().getInstance() .findByTitle(request.getParameter("title")); if (book != null) { request.setAttribute("book", book); forward("book-found"); } else { forward("book-notfound"); } } }

Wenn die Anwendung ausgeführt wird, können wir diesen Befehl erreichen, indem wir unseren Browser auf // localhost: 8080 / front-controller /? Command = Search & title = pattern zeigen.

Der SearchCommand wird in zwei Ansichten aufgelöst. Die zweite Ansicht kann mit der folgenden Anforderung // localhost getestet werden: 8080 / front-controller /? Command = Search & title = any-title.

Um unser Szenario abzurunden, implementieren wir einen zweiten Befehl, der in allen Fällen als Fallback ausgelöst wird. Eine Befehlsanforderung ist dem Servlet unbekannt:

public class UnknownCommand extends FrontCommand { @Override public void process() throws ServletException, IOException { forward("unknown"); } }

Diese Ansicht ist unter // localhost: 8080 / front-controller /? Command = Order & title = any-title oder durch vollständiges Auslassen der URL- Parameter erreichbar.

4. Bereitstellung

Da wir uns entschieden haben, ein WAR-Dateiprojekt zu erstellen , benötigen wir einen Webbereitstellungsdeskriptor. Mit dieser web.xml können wir unsere Webanwendung in jedem Servlet-Container ausführen:

   front-controller  com.baeldung.enterprise.patterns.front.controller.FrontControllerServlet    front-controller /  

Als letzten Schritt führen wir 'mvn install jetty: run' aus und überprüfen unsere Ansichten in einem Browser.

5. Schlussfolgerung

Wie wir bisher gesehen haben, sollten wir jetzt mit dem Front Controller-Muster und seiner Implementierung als Servlet- und Befehlshierarchie vertraut sein.

Wie immer finden Sie die Quellen auf GitHub.