Applications Web Design Patterns

Je conçois une application Web simple. Je suis nouveau dans ce domaine basé sur le Web. J’avais besoin de vos conseils concernant les modèles de conception tels que la répartition des responsabilités entre Servlets, les critères de création de nouveaux Servlet, etc.

En fait, j’ai peu d’entités sur ma page d’accueil et correspondant à chacune d’entre elles, nous avons peu d’options comme append, éditer et supprimer. Auparavant, j’utilisais un Servlet par option comme Servlet1 pour add entity1, Servlet2 pour edit entity1 et ainsi de suite et nous avons fini par avoir un grand nombre de servlets.

Maintenant, nous modifions notre conception. Ma question est de savoir comment vous choisissez exactement comment vous choisissez la responsabilité d’une servlet. Devrions-nous avoir un Servlet par entité qui traiterait toutes ses options et transmettrait la demande à la couche de service. Ou devrions-nous avoir un servlet pour toute la page qui traitera toute la demande de page et le transmettra ensuite à la couche de service correspondante? De même, l’object de requête doit-il être transféré à la couche de service ou non?

Une application Web un peu décente consiste en un mélange de modèles de conception. Je ne mentionnerai que les plus importants.


Modèle de contrôleur de vue de modèle

Le modèle de conception de base (architectural) que vous souhaitez utiliser est le modèle Model-View-Controller . Le contrôleur doit être représenté par un servlet qui crée / utilise directement un modèle et une vue spécifiques en fonction de la demande. Le modèle doit être représenté par des classes javabéennes. Ceci est souvent divisible dans Business Model qui contient les actions (comportement) et le modèle de données qui contient les données (informations). La vue doit être représentée par les fichiers JSP qui ont un access direct au modèle (de données ) par EL (langage d’expression).

Ensuite, il existe des variations en fonction de la manière dont les actions et les événements sont traités. Les plus populaires sont:

  • MVC basé sur la requête (action) : c’est le plus simple à mettre en œuvre. Le modèle ( métier ) fonctionne directement avec les objects HttpServletRequest et HttpServletResponse . Vous devez rassembler, convertir et valider les parameters de la demande (principalement) vous-même. La vue peut être représentée par du HTML / CSS / JS ordinaire et ne conserve pas l’état des requêtes. C’est ainsi que fonctionnent entre autres Spring MVC , Struts et Ssortingpes .

  • MVC basé sur les composants : c’est plus difficile à mettre en œuvre. Mais vous vous retrouvez avec un modèle et une vue plus simples dans lesquels toute l’API Servlet “brute” est complètement supprimée. Vous ne devriez pas avoir besoin de rassembler, convertir et valider les parameters de la demande vous-même. Le contrôleur effectue cette tâche et définit les parameters de demande collectés, convertis et validés dans le modèle . Tout ce que vous avez à faire est de définir des méthodes d’action qui fonctionnent directement avec les propriétés du modèle. La vue est représentée par des “composants” en fonction des tags taglibs JSP ou des éléments XML qui génèrent à leur tour HTML / CSS / JS. L’état de la vue pour les requêtes suivantes est maintenu dans la session. Ceci est particulièrement utile pour la conversion côté serveur, la validation et les changements de valeur. C’est comme ça entre autres JSF , Wicket et Play! travaux.

En passant, le fait de passer du temps avec un framework MVC est un très bon exercice d’apprentissage, et je le recommande aussi longtemps que vous le gardez à des fins personnelles / privées. Mais une fois que vous êtes professionnel, il est fortement recommandé de choisir un cadre existant plutôt que de le réinventer. Apprendre un cadre existant et bien développé prend moins de temps que le développement et le maintien d’un cadre robuste.

Dans l’explication détaillée ci-dessous, je me limiterai à demander un MVC basé sur des demandes, car c’est plus facile à mettre en œuvre.


Modèle de contrôleur frontal ( modèle de médiateur )

Tout d’abord, la partie Contrôleur doit implémenter le modèle de contrôleur frontal (qui est un type spécialisé de modèle de médiateur ). Il ne doit comporter qu’un seul servlet fournissant un point d’entrée centralisé pour toutes les demandes. Il doit créer le modèle en fonction des informations disponibles par la requête, telles que pathinfo ou servletpath, la méthode et / ou des parameters spécifiques. Le modèle de gestion s’appelle Action dans l’exemple HttpServlet ci-dessous.

 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Action action = ActionFactory.getAction(request); Ssortingng view = action.execute(request, response); if (view.equals(request.getPathInfo().subssortingng(1)) { request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response); } else { response.sendRedirect(view); // We'd like to fire redirect in case of a view change as result of the action (PRG pattern). } } catch (Exception e) { throw new ServletException("Executing action failed.", e); } } 

L’exécution de l’action doit renvoyer un identifiant pour localiser la vue. Le plus simple serait de l’utiliser comme nom de fichier du JSP. Mappez cette servlet sur un url-pattern spécifique dans web.xml , par exemple /pages/* , *.do ou même simplement *.html .

Dans le cas de modèles de préfixes comme par exemple /pages/* vous pouvez alors invoquer des URL telles que http://example.com/pages/register , http://example.com/pages/login , etc et Provide /WEB-INF/register.jsp , /WEB-INF/login.jsp avec les actions GET et POST appropriées. Le register pièces, le login , etc. sont alors disponibles par request.getPathInfo() comme dans l’exemple ci-dessus.

Lorsque vous utilisez des modèles de suffixe tels que *.do , *.html , etc., vous pouvez alors appeler des URL telles que http://example.com/register.do , http://example.com/login.do , etc et vous devriez changer les exemples de code dans cette réponse (aussi le ActionFactory ) pour extraire le register et login parties de login par request.getServletPath() place.


Modèle de stratégie

L’ Action doit suivre le schéma de stratégie . Il doit être défini comme un type abstrait / interface qui doit faire le travail en fonction des arguments passés de la méthode abstraite (c’est la différence avec le modèle de commande , où le type abstrait / interface doit effectuer le travail en fonction du arguments qui ont été transmis lors de la création de l’implémentation).

 public interface Action { public Ssortingng execute(HttpServletRequest request, HttpServletResponse response) throws Exception; } 

Vous souhaiterez peut-être rendre l’ Exception plus spécifique avec une exception personnalisée comme ActionException . C’est juste un exemple de lancement de base, le rest dépend de vous.

Voici un exemple de LoginAction qui (comme son nom l’indique) se connecte à l’utilisateur. L’ User lui-même est à son tour un modèle de données . La vue est consciente de la présence de l’ User .

 public class LoginAction implements Action { public Ssortingng execute(HttpServletRequest request, HttpServletResponse response) throws Exception { Ssortingng username = request.getParameter("username"); Ssortingng password = request.getParameter("password"); User user = userDAO.find(username, password); if (user != null) { request.getSession().setAtsortingbute("user", user); // Login user. return "home"; // Redirect to home page. } else { request.setAtsortingbute("error", "Unknown username/password. Please retry."); // Store error message in request scope. return "login"; // Go back to redisplay login form with error. } } } 

Modèle de méthode d’usine

ActionFactory doit suivre le modèle de méthode Factory . Fondamentalement, il devrait fournir une méthode de création qui renvoie une implémentation concrète d’un type abstrait / interface. Dans ce cas, il convient de renvoyer une implémentation de l’interface Action basée sur les informations fournies par la requête. Par exemple, la méthode et pathinfo (le pathinfo est la partie après le contexte et le chemin de servlet dans l’URL de la requête, à l’exclusion de la chaîne de requête).

 public static Action getAction(HttpServletRequest request) { return actions.get(request.getMethod() + request.getPathInfo()); } 

Les actions à leur tour doivent être des Map statiques / applicatives Map qui contiennent toutes les actions connues. C’est à vous de décider comment remplir cette carte. Codage dur:

 actions.put("POST/register", new RegisterAction()); actions.put("POST/login", new LoginAction()); actions.put("GET/logout", new LogoutAction()); // ... 

Ou configurable sur la base d’un fichier de configuration propriétés / XML dans le classpath: (pseudo)

 for (Entry entry : configuration) { actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance()); } 

Ou dynamicment basé sur un scan dans le classpath pour les classes implémentant une certaine interface et / ou une annotation: (pseudo)

 for (ClassFile classFile : classpath) { if (classFile.isInstanceOf(Action.class)) { actions.put(classFile.getAnnotation("mapping"), classFile.newInstance()); } } 

Gardez à l’esprit de créer une action “ne rien faire” pour le cas où il n’y a pas de mappage. Laissons-le par exemple renvoyer directement le request.getPathInfo().subssortingng(1) alors.


Autres motifs

Ce sont les modèles importants jusqu’à présent.

Pour aller plus loin, vous pouvez utiliser le motif Facade pour créer une classe Context qui, à son tour, encapsule les objects de requête et de réponse et propose plusieurs méthodes de délégation déléguées aux objects de requête et de réponse et les transmet en tant qu’argument dans Action#execute() méthode à la place. Cela ajoute une couche abstraite supplémentaire pour masquer l’API Servlet brute. Vous devriez alors finir avec zéro déclaration import javax.servlet.* dans chaque implémentation Action . En termes JSF, c’est ce que FacesContext ExternalContext classes FacesContext et ExternalContext . Vous pouvez trouver un exemple concret dans cette réponse .

Ensuite, il y a le modèle d’état pour le cas où vous souhaiteriez append une couche d’abstraction supplémentaire pour répartir les tâches de collecte des parameters de demande, les convertir, les valider, mettre à jour les valeurs du modèle et exécuter les actions. En termes de JSF, c’est ce que fait le LifeCycle .

Ensuite, il y a le motif composite pour lequel vous souhaitez créer une vue basée sur un composant, qui peut être associée au modèle et dont le comportement dépend de l’état du cycle de vie basé sur la demande. En termes de JSF, c’est ce que représente le UIComponent .

De cette façon, vous pouvez évoluer petit à petit vers un framework basé sur les composants.


Voir également:

  • Exemples de modèles de conception GoF dans les bibliothèques principales de Java
  • Différence entre Request MVC et Component MVC
  • Afficher JDBC ResultSet en HTML dans la page JSP à l’aide du modèle MVC et DAO
  • Quels composants MVC dans le framework JSF MVC?
  • Contrôleur JSF, Service et DAO

Dans le modèle MVC, le Servlet est un contrôleur “C”.

Sa tâche principale consiste à effectuer une évaluation initiale de la demande, puis à envoyer le traitement en fonction de l’évaluation initiale à l’agent spécifique. L’une des responsabilités du travailleur peut être de configurer certains beans de couche de présentation et de transmettre la demande à la page JSP pour afficher le code HTML. Donc, pour cette seule raison, vous devez transmettre l’object de requête à la couche de service.

Je ne voudrais cependant pas commencer à écrire des classes Servlet brutes. Le travail qu’ils font est très prévisible et rapide, ce que fait très bien le framework. Heureusement, il existe de nombreux candidats disponibles dans l’ordre alphabétique: guichet Apache , faces serveur Java , Spring pour n’en citer que quelques-uns.

IMHO, il n’y a pas beaucoup de différence dans le cas de l’application Web si vous le regardez à partir de l’atsortingbution de l’angle de responsabilité. Cependant, gardez la clarté dans la couche. Conservez tout ce qui concerne uniquement la présentation dans la couche de présentation, comme le contrôle et le code spécifiques aux contrôles Web. Gardez simplement vos entités dans la couche de gestion et toutes les fonctionnalités (telles que l’ajout, la modification, la suppression), etc. dans la couche de gestion. Cependant, en les rendant sur le navigateur pour être traitées dans la couche de présentation. Pour .Net, le modèle ASP.NET MVC est très performant en termes de séparation des couches. Regardez dans le modèle MVC.

J’ai utilisé le framework Struts et je le trouve assez facile à apprendre. Lorsque vous utilisez le cadre struts, chaque page de votre site aura les éléments suivants.

1) Une action utilisée est appelée chaque fois que la page HTML est actualisée. L’action doit renseigner les données du formulaire lors du premier chargement de la page et gérer les interactions entre l’interface utilisateur Web et la couche de gestion. Si vous utilisez la page jsp pour modifier un object Java modifiable, une copie de l’object Java doit être stockée dans le formulaire plutôt que l’original afin que les données d’origine ne soient pas modifiées, sauf si l’utilisateur enregistre la page.

2) Le formulaire utilisé pour transférer des données entre l’action et la page jsp. Cet object doit comporter un ensemble de getter et de setters pour les atsortingbuts devant être accessibles au fichier jsp. Le formulaire dispose également d’une méthode pour valider les données avant qu’elles ne soient persistantes.

3) Une page jsp qui est utilisée pour rendre le code HTML final de la page. La page jsp est un hybride de balises HTML et de balises spéciales utilisées pour accéder aux données du formulaire et les manipuler. Bien que struts permette aux utilisateurs d’insérer du code Java dans les fichiers jsp, vous devez être très prudent car cela rend votre code plus difficile à lire. Le code Java à l’intérieur des fichiers jsp est difficile à déboguer et ne peut pas être testé par l’unité. Si vous écrivez plus de 4-5 lignes de code Java dans un fichier jsp, le code devrait probablement être déplacé dans l’action.

BalusC excellent answer couvre la plupart des modèles pour les applications Web.

Certaines applications peuvent nécessiter une chaîne de responsabilité

Dans la conception orientée object, le modèle de chaîne de responsabilité est un modèle de conception constitué d’une source d’objects de commande et d’une série d’objects de traitement. Chaque object de traitement contient une logique qui définit les types d’objects de commande qu’il peut gérer; les autres sont transmis au prochain object de traitement de la chaîne.

Utilisez cas pour utiliser ce modèle:

Lorsque le gestionnaire pour traiter une requête (commande) est inconnu et que cette demande peut être envoyée à plusieurs objects. En général, vous définissez le successeur sur object. Si l’object en cours ne peut pas gérer la demande ou traiter la demande partiellement et transférer la même demande à l’object successeur .

Questions / articles utiles sur le SE:

Pourquoi devrais-je utiliser une chaîne de responsabilité plutôt qu’un décorateur?

Usages courants pour la chaîne de responsabilité?

modèle de chaîne de responsabilité de oodesign

chain_of_responsibility de sourcemaking