Struts2s Struktur
1. Warum Frameworks verwenden?
(1) Das Framework erledigt automatisch viele triviale Aufgaben
Für Struts2 hilft es uns, Datentyp -Konvertierung, Datenüberprüfung, Internationalisierung usw. leicht zu vervollständigen.
Häufige Aufgaben in der Webentwicklung. Es gibt auch die Vorlagenmodi, die im Frühjahr weit verbreitet sind, die unseren Entwicklungsprozess automatisierter und intelligenter gestalten. Die Verwendung eines Frameworks besteht darin, das Rad neu zu erfinden und diese Vorlagencodes neu zu kopieren.
Mit Framework können wir uns mehr auf höhere Probleme als auf gemeinsame Workflows und grundlegende Aufgaben konzentrieren.
(2) Verwenden eines Rahmens bedeutet, die Architektur hinter dem Rahmen anmutig zu erben
Die Architektur hinter dem Rahmen definiert normalerweise eine Reihe von Workflows. Wir müssen den Code einer bestimmten Anwendung an diesen Prozess anschließen, damit wir die verschiedenen Vorteile des Rahmens genießen können. Manchmal können wir auch den architektonischen Regeln des Rahmens widerstehen, aber der Rahmen bietet seine Architektur normalerweise auf eine Weise, die schwer abzulehnen ist. Es ist so einfach, dass Sie eine ausgezeichnete Architektur anmutig erben können und sie ist kostenlos. Warum also nicht?
(3) Es ist einfacher, gut ausgebildete Menschen mit dem Rahmen zu finden
Ich habe im gesamten Projekt meines Unternehmens fast noch nie Frameworks verwendet und nach Servicesendiensten gesucht (ähnlich wie JNDI)
Zum Protokollendruck (ähnlich wie log4j) und dann zum Datenbankverbindungspool (ähnlich wie DBCP) werden alle selbst vom internen Personal implementiert. Erstens liegt es daran, dass das Projekt relativ alt ist und es zu diesem Zeitpunkt möglicherweise kein Open -Source -Framework gibt. Zweitens liegt es an der konservativen Strategie des Unternehmens, und es ist besorgt, dass die Verwendung eines instabilen Open -Source -Rahmens Risiken für das Projekt bringen kann. Dies kann zu dieser Zeit in der Umwelt zutreffen, und das Geschäftsleitung des Unternehmens wird das gesamte Projekt natürlich aus einer größeren Perspektive betrachten.
Wenn das Projekt jedoch allmählich größer wird und es immer mehr hervorragende Open -Source -Frameworks auf der Welt gibt, kann das Endergebnis, dass neu rekrutierte Entwickler dieses komplexe System von Grund auf lernen müssen (alle internen Systeme, und es gibt keine Hilfe im Internet) und sorgfältiger Käfer in den internen Frameworks.
Die Kosten sind wirklich zu hoch.
(4) Der interne Rahmen kann nicht mit der Entwicklung der Branche Schritt halten
Der Fehler im internen Framework zuvor erwähnt. Für Open -Source -Frameworks gibt es möglicherweise ein Team von Gründern, eine große Anzahl von Open -Source -Enthusiasten.
Open Source Community, um es zu unterstützen. Die Kraft der Menschen ist unendlich und die Geschwindigkeit der Fehlerreparatur kann sich vorstellen. Dies ist aus der jüngsten Open Source
Der Fehlerbehebungsprozess von Textmate ist zu sehen. Viele Fehler, die seit langer Zeit zurückgestellt wurden, wurden von Enthusiasten schnell gelöst, nachdem sie Open Source sind, aber was ist mit dem internen Rahmen? Nachdem die Leute, die ihn entwickelt haben, das Unternehmen verlassen hatte, würde niemand seinen Quellcode ohne größere Fehler lesen. Die Lücke ist offensichtlich!
(5) Natürlich ist es kein großer Gewinn, einen Rahmen zu verwenden.
Wie bereits erwähnt, ist die Verwendung eines unreifen Rahmens riskant und es ist besser, für ein nicht so radikales Projekt konservativ zu sein.
(Es sei denn, dies ist eine Gruppe freier und ungezügelter Tech -Fanatiker, die entscheiden können, welchen Rahmen sie nach eigenem Ermessen verwenden sollen, das ist wirklich ein Segen)
Genau wie in Sequioa, dem Java HA -Hochverfügbarkeitsdienst, den ich zuvor verwendet habe, wird dieses Rahmen nicht mehr vom Entwicklungsunternehmen unterstützt und das Risiko ist noch größer.
Bei Verwendung einiger ungewöhnlicher Frameworks sollten Sie außerdem auch auf das Framework -Quellcode -Lizenzprotokoll achten und es nicht nach Belieben im Projekt verweisen.
Ändern Sie den Quellcode des Rahmens, um unnötige Rechtsstreitigkeiten zu vermeiden.
2. Die Architektur hinter Struts2
Da wir zuvor so viele Vorteile des Rahmens analysiert haben, werden wir natürlich lernen, Struts2 zu verwenden. Aber mit Struts2
Welche Art von eleganter Architektur wird es erben? Tatsächlich ist es aus einer höheren Abstraktionsniveau das MVC -Modell, mit dem wir vertraut sind.
Nach dem vorherigen HelloWorld -Beispiel ist Controller C (FilterDispatcher) das, was wir in web.xml deklariert haben
Struts2 Kernklasse. Und Modell M ist unser Nachrichtenaktionsklasse. Und View V ist von Natur aus News.jsp. Das Konzept des Modells scheint etwas vage. Was ist ein Modell? In der Tat enthält dieses Konzept, das sehr Substantiv klingt, beide Geschäftsdaten, die statisch aus dem Web-Front-End übertragen wurden, und der Implementierung der Geschäftslogik.
Einige Leute mögen sagen, dass diese Architektur nicht neu ist, es gibt viele MVC -Frameworks. Was ist der Unterschied zwischen diesem und anderen Frameworks? Lassen Sie uns Struts2 auf einer niedrigeren Abstraktionsebene analysieren und sehen, was sie einzigartig macht.
Auf den ersten Blick sieht es sehr kompliziert aus. Wenn wir es nur aus der Sicht des Benutzers betrachten, müssen wir den gelben Teil während der Entwicklung nur implementieren, das heißt, wir
Struts.xml, Newsaction und News.jsp In HelloWorld Instance. Dies ist alles, was wir tun müssen, wie bereits erwähnt, wir müssen nur sehr kleine Dinge tun und werden Teil dieser hervorragenden Architektur.
Schauen Sie sich nun die anderen Teile an. FilterDispatcher ist der Servlet -Filter, den wir in web.xml konfigurieren, das Struts2 ist
Alle Struts2 -Webanwendungen müssen auf diese Weise konfiguriert werden. Als nächstes sind die blauen und grünen Teile der Kern von Struts2. Man kann sagen, dass diese Klassen von den Entwicklern von Struts2 sorgfältig entworfen werden.
(1) Der Client sendet eine Anfrage, und der J2EE -Container analysiert das HTTP -Paket und fördert sie in ein httpServletRequest.
(2) FilterDispatcher fängt diese Anforderung ab und durchsucht den ActionMapper basierend auf dem Anforderungspfad, um zu bestimmen, welche Aktion aufgerufen werden soll.
(3) Nach dem Rückgabeergebnis von ActionMapper beauftragt FilterDispatcher ActionProxy, diese Aktion in Struts.xml zu finden.
.
(5) Jeder Interceptor erledigt seine eigenen Aufgaben
(6) Der reale Aufruf zum Handeln gibt den Ergebnispfad zurück
(7) Das Ergebnisobjekt gibt die Rückgabedaten in den Stream aus
(8) HttpServletResponse in den J2EE -Container zurückgeben, und der Container sendet HTTP -Pakete an den Client.
Dies ist der Ausführungsprozess von Struts2. Die Kernobjekte sind ActionInvocation und Interceptor sowie der noch nicht eingeführte ActionContext.
ActionInvocation ist die Gesamtplanung des gesamten Prozesses, der dem Aufrufobjekt im Feder AOP sehr ähnlich ist. Viele Schnittstellen sind in Struts2 eingebaut. Das Wichtigste ist, die Anforderungsparameter zu speichern und die Vordergrunddaten an die Aktionsmitgliedvariablen zu übergeben.
ActionContext ist das globale Kontextobjekt, das diese Daten speichert, und das Wichtigste ist, dass der Evalestack verwendet wird, um die Aktionsinstanz zu speichern.
Auf das sogenannte globale bedeutet, dass auf ACCACTCONTEXT in Aktion und Ergebnis zugegriffen werden kann, aber tatsächlich ThreadLocal-Typ. Jeder Anforderungs -Thread hat eine eigene Instanz an Aktion und ActionContext.
Es kann gesagt werden, dass Lernen von Struts2 hauptsächlich um das Lernen geht:
(1) Lassen Sie Interceptor und Action zusammenarbeiten, um die Aufgabe zu erledigen.
(2) Speichern Sie die Vordergrunddaten in die Aktion.
(3) Das Ergebnis erhält die Rückgabedaten von der Aktion durch Evalestack.
3. Die Unterschiede zwischen Struts2 und Struts1
Aus dem obigen Ausführungsprozess können wir bereits den großen Unterschied zwischen Struts1 und 2 erkennen.
(1) Wo ist ActionForm geblieben? Ist Aktion immer noch die gleiche Aktion?
Das Offensichtlichste ist, dass wir das ActionForm -Objekt im gesamten Prozess nicht sehen können, und obwohl die Aktion immer noch dieser Name genannt wird, scheint es sich von der Aktion in Struts1 völlig unterscheiden.
Zunächst wurde Actionform aufgegeben und die von der Rezeption gesendeten Daten in jedem Pojo gespeichert werden. Der Tag des Speicherns in Actionform und dann ist das Kopieren des DTO -Objekts vorbei. Zweitens ist dieses Pojo tatsächlich eine Mitgliedsvariable im Aktionsobjekt. Dies ist in Struts1
In diesem Fall ist es unmöglich, eine Aktionsinstanz für alle Anfragen zu teilen. Jetzt erstellt Struts2 für jede Anfrage eine Aktionsinstanz, sodass dies funktioniert. Drittens, obwohl dies machbar ist, scheint es, dass Aktion als Modell M in MVC Daten spart und Geschäftslogik enthält. Ist das ein schlechtes Design? Wenn Sie sorgfältig darüber nachdenken, ist dieses Design sehr bequem, haben wir die Daten bereits erhalten.
Sie können die Serviceschicht direkt bedienen. Aktion scheint zu viele Verantwortlichkeiten zu haben, aber nicht viele.
(2) Wie wurde das Front-End-Servlet zum Filter?
Wir wissen, dass Struts1 und Spring MVC beide als Eingänge über Front-End-Servlets verwendet werden. Warum verwenden Struts2 Servlet -Filter?
Da Struts2 auf dem Webwork -Kern basiert, unterscheidet sich es völlig von Struts1. Webwork kann gesagt werden, um Anwendungen und J2EE zu reduzieren
API -Kopplung, wie das Ändern von ActionServlet in den Filter von Servlet und direkter Zugriff auf httpServletRequest/Antwort.
Beispielsweise kann jedes Pojo als ActionForm dienen. Jede Klasse kann als Aktion verwendet werden, ohne die Aktionsschnittstelle zu implementieren, usw.
Daher erbt Struts2 auch dieses hervorragende nicht-invasive Design.
Dies ähnelt etwas den Designideen von Spring. Beispielsweise müssen diese Ware -Schnittstellen überhaupt nicht implementiert werden, um die Kopplung zwischen Anwendungscode und Framework zu minimieren. Die Invasivität ist in der Tat ein wichtiger Faktor bei der Gestaltung eines Rahmens.
(3) OGNL zwischen Filter, Aktion und Ergebnis
Die folgende Abbildung kann deutlich zeigen, wie OGNL in das Struts2 -Framework integriert ist.
Es ist so bequem, mit dem Struts2 -Tag in der Eingabepage inputform.html auf die Daten in Aktion zuzugreifen und zur Seite resultPage.jsp zurückzukehren.
OGNL ermöglicht den Zugang zu den Eigenschaften von in Evalestack gespeicherten Aktionen, die so bequem wie der Zugriff auf die eigenen Eigenschaften von Ehegutestack sind.
Die umfassende Verwendung von OGNL ist ein Hauptmerkmal von Struts2. Einschließlich des Vordergrund -Tags, das Werte übergeben, wird das Ergebnis, das Werte aus der Aktion usw. nimmt, OGNL in großen Mengen verwendet. Reflexion wird jedoch in OGNL häufig verwendet. Ich denke, dies ist einer der Gründe, warum Struts2 nicht so gut ist wie Struts1. Schließlich braucht es einen bestimmten Preis, um eine flexible und niedrig gekoppelte Architektur zu erhalten.
(4) Die Stärke des Interceptor ist unbesiegbar
Ein weiteres leistungsstarkes Merkmal in Struts2 ist der Interceptor Interceptor. Struts2 hat eine große Anzahl von Interceptors eingebaut, die es ermöglichen, eine große Menge an Code wiederverwendet zu werden, wodurch das automatisiert wird, was wir zuvor als triviale Aufgaben bezeichnet haben, wodurch Struts2 ein hohes Maß an Aufmerksamkeit getrennt werden kann. Dies ist wirklich ein Modell für die Anwendung von AOP -Ideen im Rahmen!
Struts2 Drei Datenübertragungsmethoden
Struts2 bietet drei Möglichkeiten zum Speichern von Parametern in HTTP -Anforderungen: Javabäe -Attribute, javabäische Objekte und modellbezogene Objekte. Schauen wir uns diese drei Datenübertragungsmethoden im häufigsten Anmeldebuch an. Der Seitencode ist sehr einfach. Das Einreichungsformular enthält den Benutzernamen und das Kennwort. Sie können diese beiden Parameter in der Aktion erhalten, um zu überprüfen, ob sich der Benutzer erfolgreich anmeldet.
1. Javabäische Eigenschaften
<%@ page contentType="text/html;charset=UTF-8" %> <html> <head></head> <body> <h1>Login Page</h1> <form action="/cdai/login" method="post"> <div> <label for="username">Name:</label> <input id="username" name="username" type="textfield"/> </div> <div> <label für = "password"> kennwort: </label> <input id = "password" name = "password" type = "password"/> </div> <div> <label für = "rema </html>
Paket com.cdai.web.sssh.action; import com.cdai.web.sssh.request.loginRequest; import com.cdai.web.sssh.service.userservice; com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.modelDiven; Loginaction im öffentlichen Klassen implementiert Aktion {private String -Benutzername; privates Zeichenfolgenkennwort; private UserService UserService; @Override public String execute () {System.out.println ("Login -Aktion -" + request); Erfolgserfolg; } public String getUsername () {Rückgabeanforderung; } public void setUnername (String -Benutzername) {this.username = userername; } public String getPassword () {Rückgabeanforderung; } public void setPassword (String -Passwort) {this.password = password; }}Diese Methode ist relativ einfach, speichern Sie die Parameter im Formular direkt in den Eigenschaften der Aktion. Bei Überprüfung müssen möglicherweise auch die Aktion den Benutzernamen und das Passwort in DTO zusammenfassen, um es zur Überprüfung an die Serviceschicht weiterzugeben. Gehen Sie also nicht einen Schritt weiter und speichern Sie den Benutzernamen und das Passwort direkt in DTO.
2. Javabäe Objekte
<%@ page contentType="text/html;charset=UTF-8" %> <html> <head></head> <body> <h1>Login Page</h1> <form action="/cdai/login" method="post"> <div> <label for="username">Name:</label> <input id="username" name="request.username" type="textfield"/> </div> <div> <label für = "password"> kennwort: </label> <input id = "password" name = "request.Password" type "password"/> </div> <div> <label für = "rema </body> </html>
Paket com.cdai.web.sssh.action; import com.cdai.web.sssh.request.loginRequest; import com.cdai.web.sssh.service.userservice; com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.modelDiven; Loginaction im öffentlichen Klassen implementiert Aktion {private loginRequest -Anfrage; private UserService UserService; @Override public String execute () {System.out.println ("Login -Aktion -" + request); Erfolgserfolg; } public LoginRequest getRequest () {Rückgabeanforderung; } public void setRequest (LoginRequest -Anforderung) {this.Request = Request; }} Dadurch können Sie die Serviceschicht direkt anrufen. Es gibt jedoch einen kleinen Nachteil, dass dies die Tiefe des Parameternamens der Seite vertieft und nur eine Anforderung zum Parameternamen hinzugefügt wird
Das Präfix (der Attributname in der Aktion) ermöglicht es Struts2, die Parameter im Formular zum Anforderungsobjekt über OGNL korrekt zu speichern.
3. modelldelisiertes Objekt
<%@ page contentType="text/html;charset=UTF-8" %> <html> <head></head> <body> <h1>Login Page</h1> <form action="/cdai/login" method="post"> <div> <label for="username">Name:</label> <input id="username" name="username" type="textfield"/> </div> <div> <label für = "password"> kennwort: </label> <input id = "password" name = "password" type = "password"/> </div> <div> <label für = "rema </html>
Paket com.cdai.web.sssh.action; import com.cdai.web.sssh.request.loginRequest; import com.cdai.web.sssh.service.userservice; com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.modelDiven; LoginAction im Public Class implementiert Aktion, modelldelen <LoginRequest> {private loginRequest request = new LoginRequest (); private UserService UserService; @Override public String execute () {System.out.println ("Login -Aktion -" + request); Erfolgserfolg; } @Override public LoginRequest getModel () {Rückgabeanforderung; }} Auf diese Weise ist eine weitere modelldelen Schnittstelle erforderlich, und die von ModelDiven bereitgestellten Objekte werden auf Evalestack gespeichert, sodass die Vordergrundseite direkt übergeben werden kann
Der Benutzername- und Passwort -Attributnamen definiert den Parameternamen des Formulars.
Welche der drei Methoden sollte nicht verallgemeinert werden? Es hängt von den spezifischen Bedürfnissen des Projekts ab und entscheidet es dann selbst!