Guide du modèle de contrôleur frontal en Java

Guide du modèle de contrôleur frontal en Java

1. Vue d'ensemble

Dans ce tutoriel, nous allons approfondir lesFront ControllerPattern, une partie desEnterprise Patterns telle que définie dans le livre deMartin Fowler“Patterns of Enterprise Application Architecture”.

Front Controller est défini comme «un contrôleur qui gère toutes les demandes pour un site Web». Il se place devant une application Web et délègue les demandes aux ressources suivantes. Il fournit également une interface aux comportements courants tels que la sécurité, l'internationalisation et la présentation de vues particulières à certains utilisateurs.

Cela permet à une application de modifier son comportement lors de l'exécution. En outre, il est utile de lire et de gérer une application en empêchant la duplication de code.

Le contrôleur frontal consolide toute la gestion des demandes en canalisant les demandes via un seul objet gestionnaire.

2. Comment ça marche?

LeFront Controller Pattern est principalement divisé en deux parties. Un seul contrôleur de répartition et une hiérarchie de commandes. L'UML suivant décrit les relations de classe d'une implémentation générique de contrôleur frontal:

front-controller

Ce contrôleur unique distribue des requêtes aux commandes afin de déclencher le comportement associé à une requête.

Pour démontrer son implémentation, nous allons implémenter le contrôleur dans unFrontControllerServlet et des commandes en tant que classes héritées d'un abstraitFrontCommand.

3. Installer

3.1. Dépendances Maven

Tout d'abord, nous allons configurer un nouveau projetMaven WAR avecjavax.servlet-api inclus:


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

ainsi quejetty-maven-plugin:


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

3.2. Modèle

Ensuite, nous allons définir une classeModel et un modèleRepository. Nous utiliserons la classeBook suivante comme modèle:

public class Book {
    private String author;
    private String title;
    private Double price;

    // standard constructors, getters and setters
}

Ce sera le référentiel, vous pouvez rechercher le code source pour une implémentation concrète ou en fournir un vous-même:

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

L'implémentation du Servlet lui-même est assez simple. Nous extrayons le nom de la commande d'une requête, créons dynamiquement une nouvelle instance d'une classe de commande et l'exécutons.

Cela nous permet d'ajouter de nouvelles commandes sans changer une base de code de nosFront Controller.

Une autre option consiste à implémenter le Servlet à l'aide d'une logique conditionnelle statique. Cela présente l’avantage de vérifier les erreurs au moment de la compilation:

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.example.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

Implémentons une classe abstraite appeléeFrontCommand, qui contient le comportement commun à toutes les commandes.

Cette classe a accès auxServletContext et à ses objets de requête et de réponse. En outre, il gère la résolution de la vue:

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);
    }
}

Une implémentation concrète de ceFrontCommand abstrait serait unSearchCommand. Cela inclura une logique conditionnelle dans les cas où un livre a été trouvé ou s'il manque un livre:

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");
        }
    }
}

Si l'application est en cours d'exécution, nous pouvons accéder à cette commande en pointant notre navigateur vershttp://localhost:8080/front-controller/?command=Search&title=patterns.

LeSearchCommand se résout en deux vues, la seconde vue peut être testée avec la requêtehttp://localhost:8080/front-controller/?command=Search&title=any-title suivante.

Pour arrondir notre scénario, nous allons implémenter une deuxième commande, qui est déclenchée comme solution de secours dans tous les cas, une demande de commande est inconnue du servlet:

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

Cette vue sera accessible àhttp://localhost:8080/front-controller/?command=Order&title=any-title ou en omettant complètement les paramètresURL.

4. Déploiement

Comme nous avons décidé de créer un projet de fichierWAR, nous aurons besoin d'un descripteur de déploiement Web. Avec ceweb.xml, nous pouvons exécuter notre application Web dans n'importe quel conteneur de servlet:



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

Comme dernière étape, nous exécuterons‘mvn install jetty:run' et inspecterons nos vues dans un navigateur.

5. Conclusion

Comme nous l'avons vu jusqu'à présent, nous devons maintenant nous familiariser avec lesFront Controller Pattern et leur implémentation en tant que servlet et hiérarchie de commandes.

Comme d'habitude, vous trouverez les sourceson GitHub.