Structure de Struts2
1. Pourquoi utiliser des frameworks?
(1) Le cadre accomplit automatiquement de nombreuses tâches triviales
Pour Struts2, il nous aide à compléter facilement la conversion du type de données, la vérification des données, l'internationalisation, etc.
Tâches courantes dans le développement Web. Il existe également les modes de modèle qui sont largement utilisés au printemps, qui rendent tous notre processus de développement plus automatisé et intelligent. L'utilisation d'un cadre est d'éviter de réinventer la roue et de re-copier ces codes de modèle.
Framework nous permet de nous concentrer davantage sur les problèmes de niveau supérieur que sur les flux de travail courants et les tâches de base.
(2) L'utilisation d'un cadre signifie gracieusement hériter de l'architecture derrière le cadre
L'architecture derrière le cadre définit généralement une série de workflows. Ce que nous devons faire est de joindre le code d'une application spécifique à ce processus, afin que nous puissions profiter des divers avantages apportés par le cadre. Parfois, nous pouvons également résister aux règles architecturales du cadre, mais le cadre fournit généralement son architecture d'une manière difficile à rejeter. C'est si simple que vous pouvez hériter d'une excellente architecture gracieuse et c'est gratuit, alors pourquoi ne pas le faire?
(3) Il est plus facile de trouver des personnes bien formées utilisant le cadre
Je n'ai presque jamais utilisé de frameworks dans l'ensemble du projet de mon entreprise auparavant et de la recherche de services de service (similaire à JNDI)
Pour enregistrer l'impression (similaire à LOG4J), puis au pool de connexions de base de données (similaire à DBCP), tous sont implémentés par le personnel interne lui-même. Premièrement, c'est parce que le projet est relativement ancien, et qu'il n'y a peut-être pas de cadre open source à utiliser à ce moment-là. Deuxièmement, c'est à cause de la stratégie conservatrice de l'entreprise, et il est inquiète que l'utilisation d'un cadre open source instable puisse entraîner des risques au projet. Cela peut être vrai dans l'environnement à ce moment-là, et la haute direction de l'entreprise examinera naturellement l'ensemble du projet dans une perspective plus large.
Cependant, lorsque le projet devient progressivement plus grand et qu'il y a de plus en plus d'excellents cadres open source dans le monde, si certains cadres open source matures ne peuvent pas être refactorisés dans le temps et introduits, le résultat final peut être que les développeurs nouvellement recrutés doivent apprendre ce système complexe à partir de zéro (tous les systèmes internes, et il n'y a pas d'aide sur Internet), et faire attention à divers bogues dans le cadre interne.
Le coût est vraiment trop élevé.
(4) Le cadre interne ne peut pas suivre le développement de l'industrie
Le bogue du cadre interne mentionné précédemment. Pour les cadres open source, il peut y avoir une équipe de fondateurs de cadre, un grand nombre de passionnés d'open source,
Communauté open source pour le soutenir. La puissance des gens est infinie et la vitesse de réparation de bogues peut être imaginée. Ceci est de la récente open source
Le processus de fixation de bogue de Textmate peut être vu. De nombreux bugs qui ont été mis de côté depuis longtemps ont été rapidement résolus par des passionnés après leur open source, mais qu'en est-il du cadre interne? Après que les personnes qui l'ont développé ont quitté l'entreprise, personne ne lirait même son code source sans bugs majeurs. L'écart est évident!
(5) Bien sûr, l'utilisation d'un cadre n'est pas un énorme profit.
Comme mentionné précédemment, l'utilisation d'un cadre immature est risquée, et il est préférable d'être conservateur pour un projet qui n'est pas si radical.
(À moins qu'il ne s'agisse d'un groupe de fanatiques technologiques libres et sans retenue qui peuvent décider quel cadre utiliser à leur propre discrétion, c'est vraiment une bénédiction)
Tout comme Sequioa, le service de haute disponibilité Java HA que j'ai utilisé auparavant, ce cadre n'est plus soutenu par la société de développement, et le risque est encore plus élevé.
De plus, lorsque vous utilisez des cadres peu communs, vous devez également prêter attention au protocole de licence de code source Framework et ne pas le référencer à volonté dans le projet.
Modifiez le code source du cadre pour éviter les litiges juridiques inutiles.
2. L'architecture derrière Struts2
Étant donné que nous avons analysé de nombreux avantages du cadre auparavant, nous commencerons naturellement à apprendre à utiliser Struts2. Mais en utilisant des struts2
Quel genre d'architecture élégante héritera-t-elle? En fait, à partir d'un niveau d'abstraction plus élevé, c'est toujours le modèle MVC que nous connaissons.
Selon l'exemple précédent Helloworld, le contrôleur C (FilterDispatcher) est ce que nous avons déclaré dans web.xml
Classe de base Struts2. Et le modèle M est notre classe d'action NewsAction. Et Voir V est naturellement News.jsp. Le concept du modèle semble un peu vague. Qu'est-ce qu'un modèle? En fait, ce concept qui sonne très nom contient les deux données commerciales transmises statiquement à partir du Front-end Web et la mise en œuvre de la logique métier.
Certaines personnes peuvent dire que cette architecture n'est pas nouvelle, il existe de nombreux cadres MVC, quelle est la différence entre ce frameworks et d'autres frameworks? Dissectons Struts2 à un niveau d'abstraction inférieur et voyons ce qui le rend unique.
À première vue, cela semble très compliqué. Si nous ne le regardons que du point de vue de l'utilisateur, nous n'avons qu'à implémenter la partie jaune pendant le développement, c'est-à-dire que nous
strut.xml, newsAction et news.jsp dans l'instance helloworld. C'est tout ce que nous avons à faire, comme mentionné précédemment, nous n'avons qu'à faire très peu de choses et nous faisons partie de cette excellente architecture.
Regardez maintenant les autres parties. FilterDispatcher est le filtre servlet que nous configurons dans web.xml, qui est Struts2
Toutes les applications Web Struts2 doivent être configurées de cette manière. Ensuite, les pièces bleues et vertes sont au cœur de Struts2. On peut dire que ces classes sont soigneusement conçues par les développeurs de Struts2.
(1) Le client envoie une demande et le conteneur J2EE analyse le paquet HTTP et le résume dans un HttpServleRequest.
(2) FilterDispatcher intercepte cette demande et recherche à l'actionmapper en fonction du chemin de demande pour déterminer l'action à appeler.
(3) Selon le résultat de retour de l'actionmapper, FilterDispatcher confie ActionProxy pour trouver cette action dans strut.xml.
(4) ActionProxy crée une action d'action et commence des appels récursifs à l'intercepteur et à l'action.
(5) Chaque intercepteur accomplit ses propres tâches
(6) Le véritable appel à l'action renvoie le chemin de résultat
(7) L'objet résultat sortira les données de retour au flux
(8) Renvoyez HttpServletResponse au conteneur J2EE, et le conteneur envoie des paquets HTTP au client.
Il s'agit du processus d'exécution de Struts2. Les objets principaux sont ActionInvocation et Interceptor, ainsi que l'actionContext qui n'a pas encore été introduit.
ActionInvocation est la planification totale de l'ensemble du processus, qui est très similaire à l'objet d'invocation dans Spring AOP. De nombreux intercepteurs sont intégrés à Struts2. La chose la plus importante est de sauvegarder les paramètres de demande et de transmettre les données de premier plan aux variables des membres de l'action.
ActionContext est l'objet de contexte global qui enregistre ces données, et la chose la plus importante est le ValueStack utilisé pour enregistrer l'instance d'action.
Le soi-disant global signifie que ActionContext est accessible en action et en résultat, mais il s'agit en fait de type threadlocal. Chaque thread de demande aura sa propre instance d'action et ActionContext.
On peut dire que l'apprentissage de Struts2 concerne principalement l'apprentissage:
(1) Laissez l'intercepteur et l'action coopérer pour terminer la tâche.
(2) Enregistrer les données de premier plan dans l'action.
(3) Le résultat obtient les données de retour de l'action via ValuEstack.
3. Les différences entre les struts2 et les struts1
D'après le processus d'exécution ci-dessus, nous pouvons déjà voir l'énorme différence entre Struts1 et 2.
(1) Où est passé ActionForm? L'action est-elle toujours la même action?
La chose la plus évidente est que nous ne pouvons pas voir l'objet ActionForm dans tout le processus, et bien que l'action soit toujours appelée ce nom, elle semble complètement différente de l'action dans Struts1.
Tout d'abord, ActionForm a été abandonné et les données envoyées à partir de la réception ont pu être enregistrées sur n'importe quel POJO. Le jour de la sauvegarde dans ActionForm d'abord, puis la copie de l'objet DTO est terminée. Deuxièmement, ce POJO est en fait une variable de membre dans l'objet Action. C'est dans Struts1
Il est impossible de partager une instance d'action pour toutes les demandes dans ce cas. Struts2 créera maintenant une instance d'action pour chaque demande, donc cela fonctionne. Troisièmement, bien que cela soit possible, il semble que l'action, en tant que modèle M dans MVC, enregistre les données et contient une logique métier. Est-ce un mauvais design? En fait, si vous y pensez attentivement, cette conception est très pratique, nous avons déjà obtenu les données.
Vous pouvez utiliser directement la couche de service. L'action semble avoir trop de responsabilités, mais pas beaucoup.
(2) Comment le servlet frontal est-il devenu un filtre?
Nous savons que Struts1 et Spring MVC sont tous deux utilisés comme entrées à travers des servlets frontaux. Pourquoi Struts2 utilise-t-il des filtres servtiques?
Étant donné que Struts2 est basé sur le noyau de travail Web, il est complètement différent de Struts1. On peut dire que le travail Web réduit les applications et J2EE
Le couplage de l'API, tel que le changement d'actionvlet au filtre du servlet et l'accès direct à HttpServletRequest / Response.
Par exemple, tout POJO peut servir de forme d'action, n'importe quelle classe peut être utilisée comme action sans implémenter l'interface d'action, etc.
Par conséquent, Struts2 hérite également de cette excellente conception non invasive.
Ceci est quelque peu similaire aux idées de conception de Spring. Par exemple, ces interfaces Ware n'ont pas besoin d'être implémentées du tout, afin de minimiser le couplage entre le code d'application et le cadre. L'invasivité est en effet un facteur important à considérer lors de la conception d'un cadre.
(3) OGNL entre le filtre, l'action et le résultat
La figure suivante peut clairement montrer comment OGNL est intégré dans le cadre Struts2.
Il est tellement pratique d'accéder aux données en action à l'aide de la balise Struts2 dans la page d'entrée inputform.html et revenez à la page resultpage.jsp
OGNL rend l'accès aux propriétés des actions enregistrées dans ValueStack aussi pratiques que l'accès aux propres propriétés de ValuEstack.
L'utilisation approfondie de l'OGNL est une caractéristique majeure de Struts2. Y compris la balise de premier plan qui transmet des valeurs à l'action, le résultat prenant les valeurs de l'action, etc., utilisera OGNL en grande quantité. Cependant, la réflexion est beaucoup utilisée dans OGNL. Je pense que c'est l'une des raisons pour lesquelles Struts2 n'est pas aussi bonne que Struts1. Après tout, il faut un certain prix pour obtenir une architecture flexible et à faible couplée.
(4) La force de l'intercepteur est invincible
Une autre caractéristique puissante de Struts2 est l'intercepteur intercepteur. Struts2 a intégré un grand nombre d'intercepteurs, qui permettent de réutiliser une grande quantité de code, automatisant ce que nous appelions auparavant des tâches triviales, permettant ainsi à Struts2 d'atteindre un haut niveau de séparation de l'attention. Ceci est vraiment un modèle pour l'application des idées AOP dans le cadre!
Struts2 Trois méthodes de transfert de données
Struts2 fournit trois façons d'enregistrer les paramètres dans les demandes HTTP: les attributs JavaBean, les objets JavaBean et les objets modèles. Jetons un coup d'œil à ces trois méthodes de transfert de données grâce à l'exemple de connexion le plus courant. Le code de page est très simple. Le formulaire de soumission contient le nom d'utilisateur et le mot de passe. Vous pouvez obtenir ces deux paramètres dans l'action pour vérifier si l'utilisateur se connecte avec succès.
1. Propriétés de Javabean
<% @ Page ContentType = "Text / Html; charSet = UTF-8"%> <html> <read> </ head> <body> <h1> Page de connexion </h1> <formulaire Action = "/ CDAI / Login" Method = "Post"> <v> <label pour = "Username"> Name: </ Label> <Entrée ID = "USERAM </ div> <v> <étiquette pour = "mot de passe"> Mot de passe: </ label> <entrée id = "mot de passe" name = "mot de passe" type = "mot de passe" /> </ div> <div> <label for = "weblme"> <input id = "webrmeme" name = "reeblme" type = "checkbox" /> webl moi </ label> <entrée type = "soumettre" value = "login"> </fort> </html>
Package com.cdai.web.ssh.action; import com.cdai.web.ssh.request.loginRequest; import com.cdai.web.ssh.service.userservice; Importer com.opensymphony.xwork2.action; Importer com.opensymphony.xwork2.modeLinved; Classe publique LoginAction implémente Action {Private String Username; mot de passe de chaîne privé; Service d'utilisateur privé UserService; @Override public String execute () {System.out.println ("Login Action -" + request); retourner le succès; } public String getUserName () {return request; } public void setUsername (String username) {this.userName = username; } public String getPassword () {return request; } public void setPassword (String Motword) {this.password = mot de passe; }}Cette méthode est relativement simple, enregistrez directement les paramètres sous la forme dans les propriétés de l'action. Lors de la vérification, l'action peut également avoir besoin de résumer le nom d'utilisateur et le mot de passe en DTO pour le transmettre à la couche de service pour vérification. Alors pourquoi ne pas aller plus loin et enregistrer le nom d'utilisateur et le mot de passe directement dans le DTO.
2. Objets javabean
<% @ page contenttype = "text / html; charset = utf-8"%> <html> <adhead> </ head> <body> <h1> Page de connexion </h1> <form action = "/ cdai / ligin" method = "post"> <v> <label for = "username"> name: </ label> <uping id = "username" name = "request.us. </div> <v> <label for = "mot de passe"> Mot de passe: </ label> <entrée id = "mot de passe" name = "request.password" type = "mot de passe" /> </ div> <div> <label for = "RememberMe"> <input id = "webrome" name = "reveryme" Type = CASHBOX "/> webing moi </ labe> <upy type =" soumiver "value =" value = "ligin =" logging "gogne" gogne "ligin" doggo </ body> </html>
Package com.cdai.web.ssh.action; import com.cdai.web.ssh.request.loginRequest; import com.cdai.web.ssh.service.userservice; Importer com.opensymphony.xwork2.action; Importer com.opensymphony.xwork2.modeLinved; classe publique LoginAction implémente Action {Private LoginRequest Request; Service d'utilisateur privé UserService; @Override public String execute () {System.out.println ("Login Action -" + request); retourner le succès; } public LoginRequest getRequest () {remerciation de retour; } public void setRequest (LoginRequest request) {this.request = request; }} Cela facilite l'appel directement la couche de service. Mais il y a un petit inconvénient que cela approfondit la profondeur du nom du paramètre de la page, n'ajoutant qu'une demande au nom du paramètre
Le préfixe (le nom d'attribut dans l'action) permet à Struts2 de enregistrer correctement les paramètres du formulaire dans l'objet de demande via OGNL.
3. Objet modèle
<% @ Page ContentType = "Text / Html; charSet = UTF-8"%> <html> <read> </ head> <body> <h1> Page de connexion </h1> <formulaire Action = "/ CDAI / Login" Method = "Post"> <v> <label pour = "Username"> Name: </ Label> <Entrée ID = "USERAM </ div> <v> <étiquette pour = "mot de passe"> Mot de passe: </ label> <entrée id = "mot de passe" name = "mot de passe" type = "mot de passe" /> </ div> <div> <label for = "weblme"> <input id = "webrmeme" name = "reeblme" type = "checkbox" /> webl moi </ label> <entrée type = "soumettre" value = "login"> </fort> </html>
Package com.cdai.web.ssh.action; import com.cdai.web.ssh.request.loginRequest; import com.cdai.web.ssh.service.userservice; Importer com.opensymphony.xwork2.action; Importer com.opensymphony.xwork2.modeLinved; Classe publique LoginAction implémente Action, ModelDriven <LoginRequest> {private LoginRequest Request = new LoginRequest (); Service d'utilisateur privé UserService; @Override public String execute () {System.out.println ("Login Action -" + request); retourner le succès; } @Override public LoginRequest getModel () {return request; }} De cette façon, une autre interface modélisée est requise, et les objets fournis par ModelDriven sont enregistrés sur ValueStack, afin que la page de premier plan puisse être directement transmise
Le nom d'utilisateur et les noms d'attribut de mot de passe définissent le nom du paramètre du formulaire.
Laquelle des trois méthodes ne devrait pas être généralisée? Cela dépend des besoins spécifiques du projet, puis de le décider vous-même!