1. Servlet Filter
1.1 Was ist ein Filter?
Ein Filter ist ein Programm, das auf dem Server vor der damit verbundenen Servlet- oder JSP -Seite ausgeführt wird. Filter können an einen oder mehrere Servlets oder JSP -Seiten beigefügt sein und die Anfrageinformationen, die diese Ressourcen eingeben, überprüfen. Danach kann der Filter wie folgt ausgewählt werden:
① Rufen Sie regelmäßig Ressourcen auf (d. H. Den Servlets oder JSP -Seiten).
② Verwenden Sie die geänderten Anforderungsinformationen, um die Ressource aufzurufen.
③ALL die Ressource, ändern Sie sie jedoch, bevor Sie die Antwort an den Client senden.
④blöcken Sie den Ressourcenaufruf und wenden Sie sich stattdessen zu einer anderen Ressource, geben Sie einen bestimmten Statuscode zurück oder generieren Sie die Ersatzausgabe.
1.2 Grundprinzipien des Servletfilters
Wenn ein Servlet als Filter verwendet wird, kann es Kundenanfragen bearbeiten. Nach Abschluss der Verarbeitung wird sie an den nächsten Filter zur Bearbeitung übergeben, sodass die Anfrage des Kunden nach dem anderen in der Filterkette bearbeitet wird, bis die Anforderung an das Ziel gesendet wird. Beispielsweise verfügt eine Website über eine Webseite, auf der "geänderte Registrierungsinformationen" eingereicht werden. Nachdem der Benutzer die geänderten Informationen ausgegeben und sie eingereicht hat, muss der Server bei der Bearbeitung zwei Aufgaben ausführen: Stellen Sie fest, ob die Sitzung des Clients gültig ist. und gleichmäßig die übermittelten Daten codieren. Diese beiden Aufgaben können in einer Filterkette verarbeitet werden, die aus zwei Filtern besteht. Wenn der Filterprozess erfolgreich ist, werden die eingereichten Daten an das endgültige Ziel gesendet. Wenn der Filtervorgang nicht erfolgreich ist, wird die Ansicht auf die angegebene Fehlerseite verteilt.
2. Schritte zur Entwicklung des Servletfilters
Die Schritte zur Entwicklung eines Servletfilters sind wie folgt:
① Schreiben Sie eine Servlet -Klasse, die die Filterschnittstelle implementiert.
②Configure -Filter in web.xml.
Um einen Filter zu entwickeln, muss die Filterschnittstelle implementiert werden. Die Filterschnittstelle definiert die folgenden Methoden:
① destory () wird vom Webcontainer aufgerufen, um diesen Filter zu initialisieren.
② Init (FilterConfig FilterConfig) wird vom Webcontainer aufgerufen, um diesen Filter zu initialisieren.
③ Dofilter (ServletRequest Request, ServletResponse -Antwort, Filterchain -Kette) Spezifischer Filterverarbeitungscode.
3. Ein Beispiel für einen Filtergerüst
SimpleFilter1.java
Paket com.zj.Sample; import Java.io.ioxception; import Javax.servlet.filter; import Javax.servlet.filterchain; import Javax.servlet.filterconfig; importieren javax.servlet.servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet. öffentliche Klasse SimpleFilter1 implementiert Filter {@Suppresswarnings ("nicht verwendet") Private FilterConfig FilterConfig; public void init (filterConfig config) löst ServletException {this.FilterConfig = config; } public void dofilter (ServletRequest -Anfrage, ServletResponse -Antwort, Filterchain -Kette) {try {System.out.println ("Innerhalb von SimpleFilter1: Filterung der Anfrage ..."); chain.dofilter (Anfrage, Antwort); // Sende die Verarbeitung an das nächste Filtersystem. } catch (ioException ioe) {ioe.printstacktrace (); } catch (ServletException se) {se.printstacktrace (); }} public void destroy () {this.FilterConfig = null; }}
SimpleFilter2.java
Paket com.zj.Sample; import Java.io.ioxception; import Javax.servlet.filter; import Javax.servlet.filterchain; import Javax.servlet.filterconfig; importieren javax.servlet.servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet.Servlet. öffentliche Klasse SimpleFilter2 implementiert Filter {@Suppresswarnings ("nicht verwendet") Private FilterConfig FilterConfig; public void init (filterConfig config) löst ServletException {this.FilterConfig = config; } public void dofilter (ServletRequest -Anfrage, ServletResponse -Antwort, Filterchain -Kette) {try {System.out.println ("Innerhalb SimpleFilter2: Filterung der Anfrage ..."); chain.dofilter (Anfrage, Antwort); // Sende die Verarbeitung an das nächste Filtersystem.out.println ("innerhalb von SimpleFilter2: Filterung der Antwort ..."); } catch (ioException ioe) {ioe.printstacktrace (); } catch (ServletException se) {se.printstacktrace (); }} public void destroy () {this.filterConfig = null; }}
web.xml
<Filter> <Filter-name> filter1 </filter-name> <filterklasse> com.zj.Sampel <Filter-name> filter2 </filter-name> <Filter-Klasse> com.zj.Sampel.SimpleFilter2 </Filter-Class> </filter> <filter-mapping> <filter-name> filter2 </filter-name
Öffnen Sie eine Seite im Webbehälter, um das Ergebnis auszugeben: (Beachten Sie die vom Filter ausgeführte Anforderung/Antwortauftrag).
In SimpleFilter1: Filterung der Anforderung ... innerhalb von SimpleFilter2: Filterung der Anforderung ... In SimpleFilter2: Filtern der Antwort ... innerhalb von SimpleFilter1: Filtern der Antwort ...
4. Berichtsfilter
Lassen Sie uns mit einem einfachen Filter experimentieren, der eine Nachricht an die Standardausgabe druckt, indem Sie das entsprechende Servlet oder die JSP -Seite aufrufen. Um diese Funktion zu implementieren, wird das Filterverhalten in der Dofilter -Methode durchgeführt. Wenn eine mit diesem Filter zugeordnete Servlet- oder JSP -Seite zugeordnete Seite aufgerufen wird, generiert die Dofilter -Methode einen Ausdruck, der den angeforderten Host und die URL des Anrufs auflistet. Da sich die GetRequesturl -Methode in der httpServletRequest anstelle des ServletRequest befindet, wird das ServletRequest -Objekt als HTTPServletRequest -Typ konstruiert. Ändern wir die SimpleFilter1.java in Kapitel 3.
SimpleFilter1.java
Paket com.zj.Sample; import java.io.ioxception; import Java.util.date; import Javax.servlet.filter; import Javax.servlet.filterchain; import Javax.servlet.filterconfig; Import Javax.Servlet.ServletExcept; javax.servlet.servletResponse; import javax.servlet.http.httpServletRequest; öffentliche Klasse SimpleFilter1 implementiert Filter {@Suppresswarnings ("nicht verwendet") Private FilterConfig FilterConfig; public void init (filterConfig config) löst ServletException {this.FilterConfig = config; } public void dofilter (ServletRequest -Anfrage, ServletResponse -Antwort, Filterchain -Kette) {try {System.out.println ("Innerhalb von SimpleFilter1: Filterung der Anfrage ..."); HttpServletRequest req = (httpServletRequest) Anfrage; System.out.println (req.getRemotehost () + "versucht zu greifen" + req.getRequesturl () + "auf" + New Date () + "."); chain.dofilter (Anfrage, Antwort); System.out.println ("Innerhalb von SimpleFilter1: Filtern der Antwort ..."); } catch (ioException ioe) {ioe.printstacktrace (); } catch (servleTException se) {se.printstacktrace (); }} public void destroy () {this.filterConfig = null; }}
Die Einstellungen von web.xml bleiben im gleichen Kapitel 3 unverändert.
prüfen:
Geben Sie [url] http: // localhost: 8080/test4jsp/login.jsp [/url] ein
Ergebnis:
In SimpleFilter1: Filterung der Anforderung ... 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 1 Versuchte, auf [url] http: // localhost: 8080/test4jsp/login.jsp [/url] auf Sonne Mar 04 17:01:37 CST 2007.Witin2: Filtering ... Initorfilter2: Filtering ... Initur 2007.witin2: Filtering ... Initor2: Asoing ... Witch 2007.Witin2: Filtering ... SimpleFilter2: Filterung der Antwort ... innerhalb von SimpleFilter1: Filtern der Antwort ...
5. Filter bei Zugriff (mithilfe von Servlets zur Initialisierung der Parameter in Filtern)
Im Folgenden ist ein normaler Zugriffszeitbereich mit Init festgelegt, um Zugriffe aufzuzeichnen, die in diesem Zeitraum nicht vorhanden sind. Lassen Sie uns die SimpleFilter2.java in Kapitel 3 ändern.
SimpleFilter2.java.
Paket com.zj.Sample; import java.io.ioxception; import Java.Text.DateFormat; Import Java.util.Calendar; Import Java.util.gregoriancalendar; Import Javax.servlet.Filter; javax.servlet.servletContext; import javax.servlet.servletException; import javax.servlet.servletrequest; import Javax.servlet.servletResponse; import Javax.servlet.http.httpletrequest; öffentliche Klasse SimpleFilter2 implementiert Filter {@SuppressWarnings ("nicht verwendet") Private FilterConfig -Konfiguration; private ServletContext -Kontext; private int starttime, endzeit; privates DateFormat -Formatierer; public void init (filterConfig config) löst ServletException {this.config = config; context = config.getServletContext (); formatter = dateFormat.getDatetimeInstance (DateFormat.Medium, DateFormat.Medium); try {startTime = integer.parseInt (config.getInitParameter ("StartTime"); // web.xml EndTime = Integer.ParseInt (config.GetInitParameter ("endzeit"); // web.xml} catch (numberformatexception) {// astgrad //. StartTime = 22; // 22:00 Uhr Endzeit = 6; // 6:00 Uhr}} public void dofilter (ServletRequest -Anforderung, ServletResponse -Antwort, Filterchain -Kette) {try {System.out.println ("Innerhalb von SimpleFilter2: Filterung der Anfrage ..."); HttpServletRequest req = (httpServletRequest) Anfrage; Gregoriancalendar -Kalender = neuer Gregoriancalendar (); int currentime = calendar.get (calendar.hour_of_day); if (isunualTime (currentime, starttime, endzeit)) {context.log ("WARNUNG:" + req.getremotehost () + "abgerufen" + req.getRequesturl () + "on" + formatter.format (calendar.getime ()); // Die Protokolldatei befindet sich unter <catalina_home> /logs.one Protokoll pro Tag. } chain.dofilter (Anfrage, Antwort); System.out .println ("Innerhalb SimpleFilter2: Filterung der Antwort ..."); } catch (ioException ioe) {ioe.printstacktrace (); } catch (servleTException se) {se.printstacktrace (); }} public void destroy () {} // Ist die aktuelle Zeit zwischen Start und Ende // Zeiten, die als absolute Zugriffszeiten gekennzeichnet sind? Private boolean isunualime (int CurrentTime, int starttime, int Endime) {// Wenn die Startzeit geringer als die Endzeit ist (dh // sie sind zweimal am selben Tag), wird die aktuelle Zeit als ungewöhnlich angesehen, wenn es zwischen Start- und Endzeiten liegt. if (startTime <endzeit) {return ((currentTime> = startTime) && (currentTime <endzeit)); } // Wenn die Startzeit größer oder gleich der Endzeit ist (dh die Startzeit ist an einem Tag und // die Endzeit am nächsten Tag), wird die aktuelle // Zeit als ungewöhnlich angesehen, wenn sie nicht zwischen // der End- und Startzeiten liegt. sonst {return (! isunusualTime (currentime, endzeit, starttime)); }}}
Die Einstellungen von Web.xml bleiben unverändert.
In Bezug auf die Tomcat -Protokollverarbeitung finden Sie hier eine weitere Einführung. config.GetServletContext (). Log ("Log Meldung") schreibt Protokollinformationen in den Ordner <Catalina_home>/Protokolle. Der Dateiname sollte localhost_log.2007-03-04.txt sein (einer wird pro Tag für Datum generiert und ist am nächsten Tag zu sehen). Um eine solche Protokolldatei zu erhalten, sollten Sie:
<Logger classname = "org.apache.catalina.logger.filelogger" prefix = "catalina_log". Suffix = ". TXT" TIMESTAMP = "TRUE"/>
6. Standortfilter sind verboten
Wenn Sie den nachfolgenden Filterprozess auf halbem Weg unterbrechen möchten, wenn Ihr Filter eine abnormale Ausnahme erkennt, können Sie dies tun:
public void dofilter (servletRequest request, servletResponse response, filterchain kette) löscht servletException, ioException {httpServletRequest req = (httpServletRequest) Anfrage; HttpServletResponse res = (httpServletResponse) Antwort; if (isUnualCondition (req)) {res.sendredirect ("http://www.somesit.com"); } else {chain.dofilter (req, res); }} Das folgende Beispiel ist ein verbotener Site -Filter. Wenn Sie nicht möchten, dass einige Websites auf Ihre Website zugreifen, können Sie die Website im Paramwert von web.xml auflisten und dann das obige Prinzip anwenden, um aus der regulären Filterung herauszuspringen und die verbotene Seite zu geben.
BanneDaccessfilter.java
Paket com.zj.Sample; import Java.io.ioxception; import Java.io.printwriter; import Java.net.malformeDurlexception; import Java.net.url; Import Java.util.hashset; javax.servlet.filterconfig; import javax.servlet.servletException; import javax.servlet.servletrequest; import Javax.servlet.servletResponse; import Javax.servlet.http.httpletrequest; öffentliche Klasse BannEdAccessFilter implementiert Filter {private hashset <string> bannedSitetable; /*** Zugriff verweigern, wenn die Anfrage von einer Banner -Site stammt oder hier* von einer Banner -Website verwiesen wird. */ public void dofilter (ServletRequest -Anfrage, ServletResponse -Antwort, Filterchain -Kette) löst ServletException aus, iOException {System.out.println ("Innerhalb von BannedAccessfilter: Filterung der Anfrage ..."); HttpServletRequest req = (httpServletRequest) Anfrage; String RequestingHost = req.getremotehost (); String referingHost = getRerferringHost (Req.Getheader ("Referer")); String bannedsit = null; boolean isBanned = false; if (bannedStaTable.Contains (RequestingHost)) {bannedSite = RequestingHost; isbanned = true; } else if (bannedStetable.contains (referingHost)) {bannedSite = referingHost; isbanned = true; } if (isBanned) {showWarning (Antwort, verboten); } else {chain.dofilter (Anfrage, Antwort); } System.out.println ("Innerhalb von BannEDAccessFilter: Filterung der Antwort ..."); } /*** Erstellen Sie eine Tabelle von Banner -Websites basierend auf Initialisierungsparametern.* Denken Sie daran, dass Version 2.3 der Servlet -API die Verwendung der* Java 2 -Plattform vorschreibt. Daher ist es sicher, Hashset (das bestimmt*, ob ein bestimmter Schlüssel existiert) und nicht der Clumsier -Hashtable* (der für jeden Schlüssel einen Wert hat). String bannedessites = config.getInitParameter ("verbotene Sites"); // Standardtoken -Set: White Space. StringTokenizer tok = new StringTokenizer (verbotene Sites); while (tok.hasmoretokens ()) {String bannedSite = tok.nextToken (); verbotene.add (verboten); System.out.println ("verboten" + verbotene Site); }} public void destroy () {} private String getRerferringHost (String refererringUrlstring) {try {url referingurl = new url (refererringurlstring); return (referingurl.gethost ()); } catch (fehl Formaledurlexception mue) {// fehlformiert oder null return (null); }} // Ersatzantwort, die an Benutzer zurückgegeben wird //, die von einer Banner -Site von oder hier verwiesen werden. private void showWarning (ServletResponse -Antwort, String verbotene Site) löst ServletException aus, ioException {response.setContentType ("text/html"); Printwriter out = response.getWriter (); String docType = "<! DocType html public/"-// w3c // dtd html 4.0 " +" transitional // en/">/n"; out.println(docType + "<HTML>/n" + "<HEAD><TITLE>Access Prohibited</TITLE></HEAD>/n" + "<BODY BGCOLOR=/"WHITE/">/n" + "<H1>Access Prohibited</H1>/n" + "Sorry, access from or via " + bannedSite + "/n" + "is not allowed./n" + "</Body> </html>"); }}
web.xml
<filter> <filter-name>BannedAccessFilter</filter-name> <filter-class>com.zj.sample.BannedAccessFilter</filter-class> <init-param> <param-name>bannedSites</param-name> <param-value> [url]www.competingsite.com[/url] [url]www.bettersite.com[/url] [url] www.moreServlets.com [/url] 127.0.0.1//we testen this </param-value> </init-param> </filter> <filter-mapping> <filter-name> verbotenes Accessfilter </filter-name> <url-patter
prüfen:
[url] http: // localhost: 8080/test4jsp/[/url]
Ergebnis:
7. Filter ersetzen
7.1 Ändern Sie die Antwort
Filter können den Zugriff auf Ressourcen blockieren oder verhindern, dass sie aktiviert werden. Wenn der Filter jedoch die von der Ressource generierte Antwort ändern möchte. Was zu tun? Es scheint keine Möglichkeit zu geben, auf die von einer Ressource generierte Antwort zugreifen zu können. Der zweite Parameter von Dofilter (ServletResponse) bietet eine Möglichkeit, eine neue Ausgabe an den Client zu senden, bietet dem Filter jedoch nicht die Möglichkeit, auf die Ausgabe des Servlet- oder JSP -Seitens zuzugreifen. Warum passiert das? Weil die SERVLET- oder JSP -Seite noch nicht einmal ausgeführt wurde, wenn die Dofilter -Methode zum ersten Mal aufgerufen wird. Sobald die Dofilter -Methode im Filterchain -Objekt aufgerufen wurde, scheint es zu spät, die Antwort zu ändern, nämlich dass die Daten an den Client gesendet wurden.
Es gibt jedoch eine Möglichkeit, das Antwortobjekt der Dofilter -Methode zu ändern, die an das Filterchain -Objekt übergeben wurden. Erstellen Sie im Allgemeinen einen Cache aller Ausgabeversionen, die von einem Servlet oder einer JSP -Seite generiert werden. Servlet API Version 2.3 bietet eine nützliche Ressource dafür, nämlich die httpServletResponseWrapper -Klasse. Die Verwendung dieser Klasse enthält die folgenden fünf Schritte:
1) Erstellen Sie eine Antwortverpackung. Erweitern Sie javax.servlet.http.httpServletResponsewrapper.
2) Geben Sie einen Printwriter an, der die Ausgabe zwischengespeichert. Überlasten Sie die GetWriter -Methode, geben Sie einen Printwriter zurück, der alles speichert, und speichert das Ergebnis in ein Feld, auf das später zugegriffen werden kann.
3) Übergeben Sie diesen Wrapper an Dofilter. Dieser Anruf ist legal, da httpServletResponsewrapper httpServletResponse implementiert.
4) extrahieren und modifizieren Sie die Ausgabe. Nach dem Aufrufen der Dofilter -Methode der Filterchain kann die Ausgabe der ursprünglichen Ressource durch die Verwendung des in Schritt 2 angegebenen Mechanismus erhalten werden. Sie können sie ändern oder ersetzen, solange sie für Ihre Anwendung geeignet sind.
5) Senden Sie die geänderte Ausgabe an den Client. Da die ursprüngliche Ressource Ausgänge nicht mehr an den Client sendet (diese Ausgänge sind bereits in Ihrem Antwortverpackung gespeichert), müssen diese Ausgänge gesendet werden. Auf diese Weise muss Ihr Filter einen Pressewriter oder einen Ausgangsstream aus dem ursprünglichen Antwortobjekt abrufen und die geänderte Ausgabe in den Stream übergeben.
7.2 Eine wiederverwendbare Antwortverpackung
Das folgende Beispiel gibt einen Wrapper an, der in den meisten Anwendungen verwendet werden kann, in denen der Filter die Ausgabe der Ressource ändern möchte. Die ChararrayWrapper -Klasse überlädt die GetWriter -Methode, um einen Pressewriter zurückzugeben, der alles in einem großen Charakter -Array ansammelt. Entwickler können dieses Ergebnis mit TOCHARArray (Original char []) oder dem ToString (einer von Char [] abgeleiteten Zeichenfolge) erzielen.
Chararraywrapper.java
Paket com.zj.Sample; import Java.io.chararraywriter; import Java.io.printwriter; import Javax.servlet.http.httpServletResponse; Import Javax.servlet.http.httpletRespondeRepon; /** * Eine Antwortverpackung, die alles nimmt, was der Client normalerweise * ausgibt und es in einem großen Charakter -Array spart. */Public Class ChararrayWrapper erweitert httpServletResponsewrapper {private ChararrayWriter Charwriter; /*** Initialisiert Wraper. * <p> * Erstens ruft dieser Konstruktor den übergeordneten Konstruktor auf. Dieser Anruf *ist grausam, damit die Antwort gespeichert und somit Setheader, *setStatus, addookie und so weiter normal arbeiten. * <p> * Zweitens erstellt dieser Konstruktor einen ChararrayWriter, der verwendet wird, um die Antwort zu sammeln. */ public ChararrayWrapper (httpServletResponse -Antwort) {Super (Antwort); charcwriter = new ChararrayWriter (); } /*** Wenn Servlets oder JSP -Seiten nach dem Schriftsteller fragen, geben Sie ihnen nicht den wahren. Geben Sie ihnen stattdessen eine Version, die in das Charakter -Array schreibt. * Der Filter muss den Inhalt des Arrays an den* Client senden (möglicherweise nach der Änderung). */ public printwriter getWriter () {return (neuer Printwriter (Charwriter)); } /*** eine String -Darstellung des gesamten Puffers erhalten. * <p> * Stellen Sie sicher, dass <b> nicht </b> diese Methode mehrmals auf demselben * Wrapper aufrufen. Die API für ChararrayWriter garantiert nicht, dass sie sich an den vorherigen Wert * erinnert ", sodass der Anruf wahrscheinlich jedes Mal eine neue Zeichenfolge erstellt. */ public String toString () {return (charwriter.toString ()); } /** Holen Sie sich das zugrunde liegende Zeichenarray. */ public char [] tocharArray () {return (charwriter.toarArray ()); }}
7.3 Filter ersetzen
Hier finden Sie eine gemeinsame Anwendung von ChararrayWrapper im vorherigen Abschnitt: Ändern eines Filters für eine mehrfach auftretende Zielzeichenfolge in eine Ersatzfolge.
7.3.1 Allgemeiner Ersatzfilter
Ersatzfilter.java gibt einen Filter an, der die Antwort in ChararraryWrapper einbringt, den Wrapper in die Dofilter-Methode des Filterchain-Objekts übergibt, einen Sting-Typ-Wert extrahiert, der die Ausgabe aller Ressourcen ergibt, alle Ereignisse einer Zielzeichenfolge ersetzt und das modifizierte Ergebnis an das Client sendet.
Es gibt zwei Dinge zu diesem Filter zu beachten. Erstens ist es eine abstrakte Klasse. Um es zu verwenden, müssen Sie eine Unterklasse erstellen, die die Implementierung von GetTargetString und GetreplacementString -Methoden bietet. Ein Beispiel für diese Behandlung ist im nächsten Unterabschnitt. Zweitens wird eine kleinere Versorgungsklasse (siehe filterutils.java) zum tatsächlichen Saitenersatz verwendet. Sie können neue reguläre Ausdruckspakete verwenden, anstatt niedrige und mühsame Methoden in String und StringOkenizer zu verwenden.
Ersetzen SieFilter.java
Paket com.zj.Sample; import Java.io.ioxception; import Java.io.printwriter; import Javax.servlet.filter; import Javax.servlet.filterchain; importieren javax.servlet.filterconfig; import Javax.servlet.servlet.Servlet. javax.servlet.servletResponse; import javax.servlet.http.httpServletResponse; /*** Filter, der alle Vorkommen einer bestimmten Zeichenfolge durch einen* Ersatz ersetzt. * Dies ist eine abstrakte Klasse. Die zweite dieser Spezifikationen Die Zeichenfolge*, die jedes Auftreten der Zielzeichenfolge ersetzen sollte. */public abstract Class Ersatzfilter implementiert Filter {private filterconfig config; public void dofilter (servletRequest request, servletResponse response, filterchain kette) löst servletException, ioException {charArrayWrapper responsewrapper = new ChararrayWrapper ((httpServletRespon) aus; // Ressource aufrufen und die Ausgabe im Wrapper ansammeln. chain.dofilter (request, responseWrapper); // Die gesamte Ausgabe in eine große Zeichenfolge verwandeln. String responstring = responseWrapper.toString (); // Ersetzen Sie in der Ausgabe alle Vorkommen der Zielzeichenfolge durch Ersatz // String. responstring = filterUtils.replace (reponestring, getTargetString (), getReplacementString ()); // Aktualisieren Sie den Header inhaltslang. UpdateHeaders (Antwort, Antwort); Printwriter out = response.getWriter (); out.write (responstring); } /*** Speichern Sie das FilterConfig -Objekt, falls die Unterklassen es wollen. */ public void init (filterConfig config) löst ServletException {this.config = config; } protected filterconfig getFilterConfig () {return (config); } public void destroy () {} /*** Die Zeichenfolge, die ersetzt werden muss.* Überschreiben Sie diese Methode in Ihrer Unterklasse. */ public abstract String GettargetString (); /*** Die Zeichenfolge, die das Ziel ersetzt. Überschreiben Sie diese Methode in * in Ihrer Unterklasse. */ public abstract String getReplacementString (); /*** Aktualisiert die Antwortüberschriften. Diese einfache Version legt nur den Header inhaltslanger Länge ein, vorausgesetzt, wir verwenden einen* Zeichensatz, der 1 Byte pro Zeichen verwendet.* Überschreiben Sie diese Methode für andere Zeichen, um* unterschiedliche Logik zu verwenden, oder geben Sie die anhaltende HTTP-Verbindungen auf. */ public void updateHeaders (ServletResponse -Antwort, String -Antwort) {response.setContentLength (respotsString.length ()); }}
Filterutils.java
Paket com.zj.Sample; /*** Kleines Dienstprogramm, mit dem Antwortverpackungen, die Strings zurückgeben. * /öffentliche Klasse Filterutils { /*** Ändern Sie alle Vorkommen von Orig in Mainstring, um zu ersetzen. */ public static String ersetzen (String Mainstring, String orig, String -Ersatz) {String result = ""; int oldIndex = 0; int index = 0; int origlength = orig.length (); while ((index = mainstring.indexof (orig, OldIndex))! = -1) {result = result + mainstring.substring (oldIndex, index) + Ersatz; oldIndex = index + origLength; } result = result + mainstring.substring (OldIndex); Rückgabe (Ergebnis); }} 7.3.2 Implementieren Sie einen Zeichenersatzfilter. Angenommen, Baidu hat Google (nur eine Hypothese) erworben, alle Texte mit dem Wort Google auf allen Seiten müssen durch Baidu ersetzt werden! ErsetzterameFilter.java erbt die oben ersatzfilter.java, um diese Funktion zu implementieren. ErsetztesameFilter.javapackage com.zj.Sample; public class ersatztemameFilter erweitert ersatzfilter {public String gettargetString () {return ("google.com.cn"); } public String getReplacementString () {return ("baidu.com"); }}
web.xml
<Filter> <Filter-name> ersetztesameFilter </filter-name> <filterklasse> com.zj.sample.replaceSeNameFilter </filter-class> </filter> <filtermapping> <Filter-Name> ErsatznameFilter </filter-name> <URL-Muster> /login.jsp </url-pattern> </filtermapping>
Testergebnisse:
Vor dem Filtern
Nach Filterung
8. Kompressionsfilter
Es gibt mehrere neueste Browser, die komprimierte Inhalte verarbeiten können, die komprimierte Datei automatisch mit GZIP als Inhalts-kodierender Antwort-Header-Wert auspacken und dann die Ergebnisse genau wie das Originaldokument verarbeiten. Das Senden solcher komprimierter Inhalte kann viel Zeit sparen, da die Zeit, die zum Komprimieren eines Dokuments auf dem Server erforderlich ist, und dann das Dokument auf dem Client rückgängig zu machen, im Vergleich zum Zeitpunkt, mit dem das Herunterladen der Datei heruntergeladen werden muss. Das Programm longServlet.java bietet ein Servlet mit langer, doppelter Ebene der Klartext, ein ausgereiftes Servlet für die Komprimierung. Wenn Sie GZIP verwenden, kann der Ausgang auf 1/300 komprimiert werden!
Wenn der Browser diese Komprimierungsfunktion unterstützt, kann der Komprimierungsfilter den in Kapitel 7 eingeführten ChararrayWrapper verwenden, um den Inhalt zu komprimieren. Der folgende Inhalt ist erforderlich, um diese Aufgabe zu erledigen:
1) Klasse, die die Filterschnittstelle implementiert. Diese Klasse wird als Kompressionsfilter ausgezeichnet. Die Init -Methode speichert das FilterConfig -Objekt in einem Feld, falls die Unterklasse auf die Servlet -Umgebung oder den Filternamen zugreifen muss. Der Körper der Destory -Methode ist leer.
2) Das verpackte Antwortobjekt. Die Dofilter -Methode wickelt das ServletResponse -Objekt in einen ChararrayWrapper und leitet diesen Wrapper auf die Dofilter -Methode des Filterchain -Objekts. Nach Abschluss dieses Anrufs wurden alle anderen Filter und endgültigen Ressourcen ausgeführt und der Ausgang befindet sich im Wrapper. Auf diese Weise extrahiert der ursprüngliche Dofilter eine Reihe von Zeichen, die die Ausgabe aller Ressourcen darstellen. Wenn der Client feststellt, dass es die Komprimierung unterstützt (d. H. GZIP als Wert für den Akzept-kodierenden Header), findet der Filter einen GzipoutputStream an den BytearrayoutputStream an, kopieren Sie das Charakter-Array in diesen Stream und legt den inhaltscodierenden Antwort-Header auf GZIP ein. Wenn der Client GZIP nicht unterstützt, kopieren Sie das nicht modifizierte Zeichenarray in BytearrayoutputStream. Schließlich sendet Dofilter das Ergebnis an den Client, indem er das gesamte Zeichenarray (wahrscheinlich komprimiert) in den Ausgangsstream schreibt, der der ursprünglichen Antwort zugeordnet ist.
3) Registrieren Sie das Longservlet.
KompressionsFilter.java
Paket com.zj.Sample; import Java.io.BytearrayoutputStream; Import Java.io.ioException; import Java.io.outputStream; Import Java.io.outputStreamWriter; importieren java.util.zip.gzipoutputStream; Importing Javax.servlet.Filter; javax.servlet.filterconfig; import javax.servlet.servletException; import javax.servlet.servletRequest; import Javax.servlet.servletResponse; import Javax.servlet.http.httpletrequest; /** * Filter, die die Ausgabe mit GZIP komprimiert (vorausgesetzt, der Browser unterstützt * gzip). */Public Class CompressionFilter implementiert Filter {private filterconfig config; /*** Wenn Browser GZIP nicht unterstützt, rufen Sie die Ressource normal auf. Wenn der Browser * <i> </i> GZIP unterstützt, setzen Sie den Inhalts-kodierenden Antwortheader und * rufen Ressourcen mit einer verpackten Antwort auf, die die gesamte Ausgabe sammelt. * Extrahieren Sie die Ausgabe und schreiben Sie sie in ein Gziped -Byte -Array. Schreiben Sie schließlich das Array in den Ausgangsstream des Clients. */ public void dofilter (servletRequest request, servletResponse antwort, filterchain kette) löst ServletException aus, ioException {httpServletRequest req = (httpServletRequest) Anforderung; HttpServletResponse res = (httpServletResponse) Antwort; if (! isgzipSupported (req)) {// Ressource Normalerweise aufrufen. chain.dofilter (req, res); } else {// Sagen Sie Browser, wir senden es GZIP -Daten. res.setheader ("Content-Coding", "Gzip"); // Ressource aufrufen und die Ausgabe im Wrapper ansammeln. Chararraywrapper responsewrapper = new ChararrayWrapper (res); chain.dofilter (req, responseWrapper); // Zeichenarray für die Ausgabe abrufen. char [] respectechars = responseWrapper.toCharArray (); // Machen Sie einen Schriftsteller, der Daten komprimiert und in ein Byte -Array einbringt. BytearrayoutputStream byTestream = new bytearrayoutputStream (); GzipoutputStream zipout = new gzipoutputStream (bytestream); OutputStreamwriter tempout = neuer outputStreamWriter (Zipout); // Die ursprüngliche Ausgabe komprimieren und in Byte -Array eingeben. tempout.write (sprechung); // Gzip -Streams müssen explizit geschlossen sein. tempout.close (); // Aktualisieren Sie den Header inhaltslang. Res.SetContentLength (byTestream.size ()); // Komprimiertes Ergebnis an den Client senden. OutputStream realout = res.getOutputStream (); byTestream.writeto (Realout); }} /*** Speichern Sie das FilterConfig -Objekt, falls die Unterklassen es wollen. */ public void init (filterConfig config) löst ServletException {this.config = config; } protected filterconfig getFilterConfig () {return (config); } public void destroy () {} private boolean isgzipSupported (httpServletRequest req) {String browSerenCodings = req.getheader ("Akzeptanz-Codierung"); return ((browSerencodings! = null) && (BrowSerencodings.indexof ("gzip")! = -1)); }} Longservlet.javapackage com.zj.Sample; import Java.io.ioException; import Java.io.printwriter; import Javax.servlet.servletException; import Javax.servlet.http.httpervlet; Import Javax.Servlet.httpl.http.htplet.httplet.httplet.httplet.httplet.httplet.httplet.httplet.httplet.httplet.httplet.httplet.httplet.httplet.httplet. javax.servlet.http.httpServletResponse; /*** Servlet mit <b> lang </b> Ausgabe. Wird verwendet, um den Effekt des Komprimierung * Filter von Kapitel 9 zu testen. */ Public Class LongServlet erweitert HttpServlet (public void dodget (httpServletRequest Request, httpServletResponse -Antwort), die ServletException, IOException {response.setContentType ("text/ html"); Printwriter out = response.getWriter (); String docType = "<! DocType html public/"-// w3c // dtd html 4.0 " +" transitional // en/">/n"; String title = "lange Seite"; out.println (docType + "<html>/n" + "<kopf> <titels>" + title + "</title> </head>/n" + "<body bgcolor =/"#fdf5e6/">/n" + "<h1 align =/" center/">" + title + "</n"); String Line = "Blah, bla, bla, bla, bla." + "Yadda, Yadda, Yadda, Yadda."; für (int i = 0; i <10000; i ++) {out.println (Zeile); } out.println ("</body> </html>"); }}
web.xml
<filter> <filter-name>CompressionFilter</filter-name> <filter-class>com.zj.sample.CompressionFilter</filter-class></filter><filter-mapping> <filter-name>CompressionFilter</filter-name> <servlet-name>LongServlet</servlet-name></filter-mapping> <servlet> <servlet-name> longservlet </servlet-name> <Servlet-Klasse> com.zj.sama.longServlet </Servlet-Class> </Servlet> <Servlet-Mapping> <Servlet-name> longServlet </Servlet-name> <url-pattern>/longServlet </url-pattern> </Servlet-name