1. Сервлет фильтр
1.1 Что такое фильтр
Фильтр - это программа, которая работает на сервере до того, как с ним связана страница сервлета или JSP. Фильтры могут быть прикреплены к одному или нескольким страницам сервлетов или JSP и могут проверять информацию о запросе, вводя эти ресурсы. После этого фильтр можно выбрать следующим образом:
① Регулярно вызовите ресурсы (то есть, звоните сервлетам или страницам JSP).
② Используйте измененную информацию о запросе, чтобы вызвать ресурс.
③ Оглаживайте ресурс, но измените его перед отправкой ответа клиенту.
④ Заблокировать ресурсный вызов, а вместо этого перейдите в другой ресурс, верните конкретный код состояния или генерируйте вывод замены.
1.2 Основные принципы сервлетного фильтра
Когда сервлет используется в качестве фильтра, он может обрабатывать запросы клиентов. После завершения обработки она будет передана следующему фильтру для обработки, так что запрос клиента обрабатывается один за другим в цепочке фильтров, пока запрос не будет отправлен в цель. Например, на веб -сайте есть веб -страница, которая представляет «измененную информацию о регистрации». После того, как пользователь заполнит измененную информацию и представляет ее, сервер должен выполнять две задачи при обработке: определить, является ли сеанс клиента действительным; и равномерно кодировать представленные данные. Эти две задачи могут быть обработаны в цепочке фильтров, состоящей из двух фильтров. Когда процесс фильтра будет успешным, представленные данные отправляются в окончательную цель; Если процесс фильтра не удастся, представление будет распределено на указанную страницу ошибки.
2. Стадии разработки сервлетных фильтров
Шаги по разработке фильтра сервлета следующие:
① Напишите класс сервлета, который реализует интерфейс фильтра.
②configure Фильтр в web.xml.
Разработка фильтра требует реализации интерфейса фильтра. Интерфейс фильтра определяет следующие методы:
① destory () вызывается веб -контейнером для инициализации этого фильтра.
② init (FilterConfig FilterConfig) вызывается веб -контейнером для инициализации этого фильтра.
③ Dofilter (запрос ServletRequest, ответ Servletresponse, цепочка FilterChain) Код обработки фильтрации.
3. Пример платформы фильтра
SimpleFilter1.java
пакет com.zj.sample; импорт java.io.ioexception; импорт javax.servlet.filter; импорт javax.servlet.filterchain; импорт javax.servlet.filterConfig; import javax.servlet.servletexception; import javax.servlet.servlectrequest; importsersplex public Class SimpleFilter1 реализует фильтр {@suppresswarnings («неиспользованный») private filterConfig filterConfig; public void init (filterConfig Config) Throws ServletException {this.filterConfig = config; } public void doFilter (запрос ServletRequest, ответ ServletResponse, цепочка FilterChain) {try {System.out.println ("Внутри простого файла: фильтрация запроса ..."); chain.dofilter (запрос, ответ); // Отправить обработку в следующую систему фильтров. } catch (ioException ioe) {io.printstackTrace (); } catch (servletexception se) {se.printstacktrace (); }} public void destry () {this.filterConfig = null; }}
SimpleFilter2.java
пакет com.zj.sample; импорт java.io.ioexception; импорт javax.servlet.filter; импорт javax.servlet.filterchain; импорт javax.servlet.filterConfig; import javax.servlet.servletexception; import javax.servlet.servlectrequest; importsersplex Public Class SimpleFilter2 реализует Filter {@SuppressWarnings («неиспользованный») частное фильтр FilterConfig; public void init (filterConfig Config) Throws ServletException {this.filterConfig = config; } public void doFilter (запрос ServletRequest, ответ ServletResponse, цепь FilterChain) {try {System.out.println ("Внутри SimpleFilter2: фильтрация запроса ..."); chain.dofilter (запрос, ответ); // Отправить обработку в следующую систему фильтров.out.println («Внутри простогофильтра2: фильтрация ответа ...»); } catch (ioException ioe) {io.printstackTrace (); } catch (servletexception se) {se.printstacktrace (); }} public void destry () {this.filterConfig = null; }}
web.xml
<filter> <filter-name>filter1</filter-name> <filter-class>com.zj.sample.SimpleFilter1</filter-class></filter><filter-mapping> <filter-name>filter1</filter-name> <url-pattern>/*</url-pattern>//Filter</filter-mapping> <filter> <Filter-name> Filter2 </filter-name> <filter-class> com.zj.sample.simplefilter2 </filter-class> </filter> <filter-mapping> <filter-name> filter2 </filter-name> <url-pattern>/*</url-pattern> // forter for All Viests </filter-mappant>/*</url-pattern> /// Для всех посещений.
Откройте любую страницу в веб -контейнере, чтобы вывести результат: (обратите внимание на заказ запроса/ответа, выполненный фильтром)
Внутри SimpleFilter1: фильтрация запроса ... Внутри SimpleFilter2: Фильтрация запроса ... в SimpleFilter2: фильтрация ответа ... В рамках SimpleFilter1: фильтрация ответа ...
4. Сообщите фильтр
Давайте экспериментируем с простым фильтром, который печатает сообщение на стандартный вывод, вызывая соответствующую страницу Сервлета или JSP. Для реализации этой функции поведение фильтрации выполняется в методе Дофильтера. Всякий раз, когда называется сервенс или страница JSP, связанная с этим фильтром, метод DoFilter генерирует распечатку, в которой перечислены запрошенный хост и URL -адрес вызова. Поскольку метод getRequesturl расположен в httpservletRequest вместо сервизлета, объект ServletRequest строится как тип httpservlectrequest. Давайте изменим SimpleFilter1.java в главе 3.
SimpleFilter1.java
пакет com.zj.sample; импорт java.io.ioexception; import java.util.date; импорт javax.servlet.filter; import javax.servlet.filterchain; импорт javax.servlet.filterconfig; import javax.servlet.servletexception; import javax.servlet.servequest; javax.servlet.servletresponse; импорт javax.servlet.http.httpservletrequest; public Class SimpleFilter1 реализует фильтр {@suppresswarnings («неиспользованный») private filterConfig filterConfig; public void init (filterConfig Config) Throws ServletException {this.filterConfig = config; } public void doFilter (запрос ServletRequest, ответ ServletResponse, цепочка FilterChain) {try {System.out.println ("Внутри простого файла: фильтрация запроса ..."); Httpservletrequest req = (httpservletrequest) запрос; System.out.println (req.getRemotehost () + «Попытался получить доступ» + req.getRequesturl () + "on" + new Date () + "."); chain.dofilter (запрос, ответ); System.out.println («Внутри простогофильтра1: фильтрация ответа ...»); } catch (ioException ioe) {io.printstackTrace (); } catch (servletexception se) {se.printstacktrace (); }} public void destry () {this.filterConfig = null; }}
Настройки web.xml остаются неизменными, в той же главе 3.
тест:
Введите [url] http: // localhost: 8080/test4jsp/login.jsp [/url]
результат:
Внутри SimpleFilter1: фильтрация запроса ... 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 1 Пробудил доступ SimpleFilter2: фильтрация ответа ... В рамках SimpleFilter1: фильтрация ответа ...
5. Фильтры при доступе (используя сервлеты для инициализации параметров в фильтрах)
Следующее - установить нормальный диапазон времени доступа, используя Init для записи доступа, которые не являются в этот период времени. Давайте изменим SimpleFilter2.java в главе 3.
SimpleFilter2.java.
пакет com.zj.sample; импорт java.io.ioexception; import java.text.dateformat; import java.util.calendar; import java.util.gregoriancalendar; импорт javax.servlet.filter; import javax.servlet.filterchain; import javax.servlet.filterConfig; javax.servlet.servletcontext; import javax.servlet.servletexception; импорт javax.servlet.servletrequest; import javax.servlet.servletresponse; импорт javax.servlet.http.httpservlectrequest; открытый класс SimpleFilter2 реализует фильтр {@suppresswarnings («неиспользованный») private filterConfig config; частный контекст ServletContext; Private Int Starttime, EndTime; частная формат формата; public void init (config filterConfig) Throws 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 ("endtime")); // web.xml} catch (numberFormatexcept nfe) {// malformed или null////// nef -aflect at after -ntfer -nf wor -ntrame is/ am -ntramula is/ amulal is hound aMula. начало = 22; // 10:00 вечера окончание = 6; // 6:00 утра}} public void dofilter (запрос ServletRequest, ответ ServletResponse, FilterChain Chain) {try {System.out.println («Внутри простогофильтера 2: фильтрация запроса ...»); Httpservletrequest req = (httpservletrequest) запрос; Gregoriancalendar Calendar = new Gregoriancalendar (); int currentTime = calendar.get (calendar.hour_of_day); if (isunusualtime (currentTime, startTime, endtime)) {context.log ("Warning:" + req.getRemotehost () + "accessed" + req.getRequesturl () + "on" + formatter.format (calendar.gettime ())); // Файл журнала находится в рамках <Catalina_home> /logs.One журнал в день. } chain.dofilter (запрос, ответ); System.out .println («Внутри простогофильтра 2: фильтрация ответа ...»); } catch (ioException ioe) {io.printstackTrace (); } catch (servletexception se) {se.printstacktrace (); }} public void destress () {} // Это текущее время между началом и конец // времена, отмеченные как абсолютное время доступа? Private Boolean Isunusualtime (int currenttime, int starttime, int endtime) {// Если время начала меньше времени окончания (т.е. // они два раза в один и тот же день), то время текущего времени считается необычным, если оно // между временем начала и окончания. if (startTime <EndTime) {return ((currentTime> = startTime) && (currentTime <EndTime)); } // Если время начала превышает или равно времени // времени (т.е. время начала на один день, и // время окончания на следующий день), то время // время считается необычным, если оно не между // конечным временем и временем начала. else {return (! isunusualtime (CurrentTime, EndTime, StartTime)); }}}
Настройки web.xml остаются неизменными.
Что касается обработки журнала Tomcat, вот дальнейшее введение. config.getServletContext (). Имя файла должно быть localhost_log.2007-03-04.txt (один из них генерируется в день к дате и может быть замечена на следующий день). Чтобы получить такой файл журнала, вы должны иметь:
<Logger classname = "org.apache.catalina.logger.filelogger" prefix = "catalina_log." Суффикс = ". txt" timeStamp = "true"/>
6. Фильтры сайта запрещены
Если вы хотите прервать последующий процесс фильтрации на полпути, когда ваш фильтр обнаружит ненормальное исключение, вы можете сделать это:
Public void DoFilter (запрос ServletRequest, ответ ServletResponse, FilterChain Chain) Throws ServletException, ioException {httpservletrequest req = (httpservletrequest); Httpservletresponse res = (httpservletresponse) ответ; if (isunusualcondition (req)) {res.sendredirect ("http://www.somesite.com"); } else {chain.dofilter (req, res); }} Следующий пример является запрещенным фильтром сайта. Если вы не хотите, чтобы некоторые сайты имели доступ к вашему веб-сайту, вы можете перечислить его сайт в значении Param web.xml, а затем применить приведенный выше принцип, чтобы выпрыгнуть из обычной фильтрации и дать запрещенную страницу.
BanneAccessFilter.java
пакет com.zj.sample; импорт java.io.ioexception; импорт java.io.printwriter; импорт java.net.malformedurlexception; импорт java.net.url; импорт java.util.hashset; import java.util.StringTokingizer; импорт javax.servlet.filter; import.serserfistizer; импорт javax.servlet.filter; javax.servlet.filterConfig; import javax.servlet.servletexception; импорт javax.servlet.servletrequest; import javax.servlet.servletresponse; импорт javax.servlet.http.httpservlectrequest; Общедоступный класс BannaCcessFilter реализует фильтр {Private HashSet <string> BannaSiteTable; /*** ОТВЕТИТЬ доступ, если запрос поступает с сайта банкера или упоминается здесь* банкетным сайтом. */ public void dofilter (запрос ServletRequest, ответ ServletResponse, FilterChain Chain) Throws ServletException, ioException {System.out.println («В рамках BannaCcessFilter: фильтрация запроса ...»); Httpservletrequest req = (httpservletrequest) запрос; String requestHost = req.getRemotehost (); String referringhost = getReferringhost (req.getheader ("Реферат")); String banneSite = null; логический ISBANMANER = FALSE; if (bannedsitetable.contains (reakinghost)) {banneSite = reakingHost; Isbanned = true; } else if (bannedsiteTable.contains (ссылка)) {banneSite = referringHost; Isbanned = true; } if (iSbanned) {showwarning (response, bannedsite); } else {chain.dofilter (запрос, ответ); } System.out.println ("Внутри BannaCcessFilter: фильтрация ответа ..."); } /*** Создание таблицы банкерированных сайтов на основе параметров инициализации.* Помните, что версия 2.3 API сервлета требует использования платформы* Java 2. Таким образом, безопасно использовать хэшсет (который определяет* существует ли заданный ключ), а не более неуклюжий хэштата* (который имеет значение для каждого ключа).*/ Public void init (confignfig), выбросит ServletException {banneredSiteTable = new Hashset <String> (); String banneSites = config.getInitParameter ("Bannedsites"); // Набор токенов по умолчанию: пробел. StringTokenizer tok = new StringTokenizer (BannalSites); while (tok.hasmoretokens ()) {string bannedsite = tok.nexttoken (); BannedSiteTable.Add (Bannedsite); System.out.println ("запрещено" + запрещает); }} public void destress () {} частная строка getReferringHost (string refererringUrlString) {try {url referringurl = new URL (refererringUrlString); return (referringurl.gethost ()); } catch (malformedurlexception mue) {// Умен или нулевой возврат (null); }} // Ответ о замене, который возвращается пользователям //, которые из них или упоминаются здесь баннерным сайтом. private void showwarnning (revletresponse response, string bannedsite) выбрасывает ServletException, 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 запрещен </title> </head>/n" + "<body bgcolor =/" white/">/n" + "<h1> Доступ, запрещенный </h1>/n" + "извините, доступ или через" + barnsite + "/n" + "/n"/n "/n". "</Body> </html>"); }}
web.xml
<Filter> <Filter-name> bannaCcessFilter </filter-name> <Filter-class> com.zj.sample.banneccessfilter </filter-class> <init-param> <maper-name> bannedsites </param-name> <param-value> [url] www.competingsite.com [/url] [/url www. [url] www.moreservlets.com [/url] 127.0.0.1//we test this </param-value> </init-param> </filter> <filter-pather> <filter> banneacccessfilter </filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <url-pattern>/*</url-pattern> </filter> <url-pattern>/*</url-pattern>
тест:
[url] http: // localhost: 8080/test4jsp/[/url]
результат:
7. Замените фильтр
7.1 Измените ответ
Фильтры могут блокировать доступ к ресурсам или предотвратить их активирование. Но если фильтр хочет изменить ответ, сгенерированный ресурсом. Что делать? Кажется, нет никакого способа получить доступ к ответу, сгенерированному ресурсом. Второй параметр dofilter (Servletresponse) предоставляет способ отправить новый вывод клиенту, но не предоставляет фильтр способом доступа к выводу страницы сервлета или JSP. Почему это происходит? Потому что страница сервлета или JSP даже не была выполнена, когда метод DoFilter вызывается в первый раз. Как только метод Dofilter в объекте FilterChain вызывается, кажется слишком поздно изменять ответ, который состоит в том, что данные были отправлены клиенту.
Тем не менее, есть способ, то есть изменять объект ответа метода Dofilter, переданный объекту FilterChain. Как правило, создайте кэш всех выходных версий, сгенерированных страницей сервлета или JSP. Версия API Servlet 2.3 предоставляет для этого полезный ресурс, а именно класс httpservletresponsewrapper. Использование этого класса включает в себя следующие пять шагов:
1) Создайте обертку ответа. Extend javax.servlet.http.httpservletresponsewrapper.
2) Предоставьте Printwriter, который кэширует вывод. Перегружайте метод GetWriter, верните PrintWriter, который сохраняет все, что отправляет ему, и сохраняет результат в поле, к которому можно получить доступ позже.
3) Передайте эту обертку Dofilter. Этот вызов является законным, потому что httpservletresponsewrapper реализует httpservletresponse.
4) Извлечь и изменить выход. После вызова метода Dofilter of FilterChain вывод исходного ресурса может быть получен с помощью механизма, представленного на шаге 2. Вы можете изменить или заменить его, если он подходит для вашего приложения.
5) Отправьте измененный вывод клиенту. Поскольку исходный ресурс больше не отправляет выходы клиенту (эти выходы уже хранятся в вашей обертке ответа), эти выходы должны быть отправлены. Таким образом, ваш фильтр должен получить PrintWriter или Output -поставки от исходного объекта ответа и передать измененный выход в поток.
7.2 Постоянная обертка ответа
В следующем примере приведен обертка, которая может использоваться в большинстве приложений, где фильтр хочет изменить выходной сигнал ресурса. Класс ChararrayWrapper перегружает метод GetWriter, чтобы вернуть PrintWriter, который накапливает все в большом массиве символов. Разработчики могут получить этот результат, используя ToCharrare (Original Char []) или ToString (строка, полученная из char []).
Chararraywrapper.java
пакет com.zj.sample; импорт java.io.chararraywriter; import java.io.printwriter; импорт javax.servlet.http.httpservletresponse; импорт javax.servlet.http.httpservlectresponsewrapper; /** * Обертка ответа, которая берет все, что клиент обычно * выводит, и сохраняет ее в одном большом массиве символов. */public class chararraywrapper расширяет httpservletresponsewrapper {private chararraywriter Charwriter; /*** Инициализирует обертку. * <p> * Во -первых, этот конструктор вызывает родительский конструктор. Этот звонок *жестокий, так что ответ хранится, и, таким образом, Setheader, *SetStatus, Addcookie и т. Д. * <p> * Во -вторых, этот конструктор создает ChararrayWriter, который будет * использоваться для накопления ответа. */ public chararraywrapper (httpservletresponse response) {super (response); charwriter = new ChararrayWriter (); } /*** Когда сервлеты или страницы JSP просят писателя, не дайте им* настоящего. Вместо этого дайте им версию, которая записывает в* массив персонажей. * Фильтр должен отправить содержимое массива на* клиент (возможно, после его изменения). */ public printwriter getWriter () {return (new PrintWriter (charwriter)); } /*** Получить строковое представление всего буфера. * <p> * Будьте уверены, что <b> не </b>, чтобы вызовать этот метод несколько раз на одной и той же обертке. API для ChararrayWriter не гарантирует, что он * «запоминает» предыдущее значение, поэтому вызов, вероятно, будет делать * новую строку каждый раз. */ public String toString () {return (charwriter.tostring ()); } /** Получите базовый массив символов. */ public char [] toCharraray () {return (charwriter.thararray ()); }}
7.3 Замените фильтр
Вот общее применение ChararrayWrapper, приведенное в предыдущем разделе: Изменение фильтра для многооткрывающей целевой строки на заменительную строку.
7.3.1 Общая замена фильтра
Replyfilter.java дает фильтр, который завершает ответ в ChararraryWrapper, передает обертку в метод Dofilter объекта FilterChain, извлекает значение строкового типа, давая вывод всех ресурсов, заменяет все входы целевой строки строкой замены и посылает модифицированный результат клиенту.
В этом фильтре есть две вещи. Во -первых, это абстрактный класс. Чтобы использовать его, вы должны создать подкласс, который обеспечивает реализацию методов GetTargetString и GetRePlacementString. Пример этого лечения приведен в следующем подразделе. Во -вторых, он использует меньший утилита (см. Filterutils.java) для фактической замены строки. Вы можете использовать новые пакеты регулярных выражений вместо использования низкоуровневых и утомительных методов в строке и StringTokenizer.
Replyfilter.java
Пакет com.zj.sample; импорт java.io.ioexception; импорт java.io.printwriter; импорт javax.servlet.filter; import javax.servlet.filterchain; импорт javax.servlet.filterConfig; import javax.servlet.servletexception; import javax.servlet.servlet.serquequest; javax.servlet.servletresponse; импорт javax.servlet.http.httpservletresponse; /*** Фильтр, который заменяет все входы данной строки* заменой. * Это абстрактный класс: вы <i> должны </i> переопределить GetTargetString* и методы GetRePlacementString в подклассе.* Первый из этих методов указывает строку в ответе*, который следует заменить. Вторая из этих спецификаций строка*, которая должна заменить каждое вхождение целевой строки. */public Abstract Class Replyfilter реализует Filter {Private FilterConfig Config; Public void DoFilter (запрос ServletRequest, ответ ServletResponse, цепочка FilterChain), бросает ServletException, ioException {chararrayWrapper responseWrapper = new ChararrayWrapper ((httpservletresponse) ответ); // вызывают ресурс, накапливая выход в обертке. chain.dofilter (запрос, responsewrapper); // превратить весь выход в одну большую строку. String responseString = responseWrapper.toString (); // В выходе замените все входы целевой строки на замену // строка. responseString = filterutils.replace (responseString, getTargetString (), getReplacementString ()); // Обновление заголовка длины содержимого. Обновление головы (ответ, Отвечая); Printwriter Out = response.getWriter (); out.write (responsegring); } /*** Храните объект FilterConfig в случае, если подклассы хотят этого. */ public void init (FilterConfig Config) Throws ServletException {this.config = config; } защищенный FilterConfig getFilterConfig () {return (config); } public void destress () {} /*** Строка, которая нуждается в замене.* Переопределяет этот метод в вашем подклассе. */ public Abstract String getTargetString (); /*** Строка, которая заменяет цель. Переопределите этот метод в * ваш подкласс. */ public Abstract String getReplacementString (); /*** Обновляет заголовки ответов. Эта простая версия просто устанавливает* заголовок длины содержимого, предполагая, что мы используем набор символов*, который использует 1 байт на символ. */ public void обновления головы (revletresponse ответ, string responsing) {response.setContentLength (responseString.length ()); }}
Filterutils.java
пакет com.zj.sample; /*** Небольшая утилита, чтобы помочь с обертками ответов, которые возвращают строки. * /public class filterutils { /*** Изменить все входы оригинала в MainString для замены. */ public static String reply (String mainstring, String Orig, String замена) {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) + замена; OldIndex = index + Origlength; } result = result + mainstring.substring (OldIndex); возврат (результат); }} 7.3.2 Реализовать фильтр для замены символов. Предположим, что Baidu приобрел Google (просто гипотеза), все тексты со словом Google на всех страницах должны быть заменены Baidu! ReplyceSiteNameFilter.java наследует remopfilter.java выше, чтобы реализовать эту функцию. ReplycesitEnamefilter.javapackage com.zj.sample; public Class ReplaceSiteNameFilter Extends revelyFilter {public String getTargetString () {return ("Google.com.cn"); } public String getReplacementSting () {return ("baidu.com"); }}
web.xml
<Filter> <Filter-name> reploceSitEnameFilter </filter-name> <filter-class> com.zj.sample.replacesiteNamefilter </filter-class> </filter> <filter-mapping> <Filter-name> replaseSitEnameFilter </filter-Name> <url-pattern>/legin.jspter-p-maling> </filter-name> <url-pattern> /login.jspternamefilter </filter-name> <url-pattern> /login.jspaterfilter </filter-name> <url-pattern>/login.jspaterfilter </filter-meam
Результаты теста:
Перед фильтрацией
После фильтрации
8. Фильтр сжатия
Существует несколько последних браузеров, которые могут обрабатывать сжатый контент, автоматически распаковывать сжатый файл с помощью GZIP в качестве значения заголовка отклика, кодирующего контент, а затем обрабатывают результаты, как и исходный документ. Отправка такого сжатого контента может сэкономить много времени, потому что время, необходимое для сжатия документа на сервере, а затем отменить документ на клиенте, это тривиально по сравнению со временем, которое необходимо для загрузки файла. Программа Longservlet.java дает сервлет с длинным дублирующимся простым текстовым выводом, зрелым сервлетом для сжатия. Если вы используете GZIP, он может сжать выход до 1/300!
Когда браузер поддерживает эту возможность сжатия, фильтр сжатия может использовать ChararrayWrapper, введенный в главе 7 для сжатия содержимого. Для выполнения этой задачи требуется следующее содержание:
1) Класс, который реализует интерфейс фильтра. Этот класс называется CompressionFilter. Метод init хранит объект FilterConfig в поле, если подкласс должен получить доступ к среде сервлета или имени фильтра. Тело метода Destory пусто.
2) Обернутый объект ответа. Метод Dofilter заполняет объект Servletresponse в ChararrayWrapper и передает эту обертку на метод Dofilter объекта FilterChain. После завершения этого вызова были выполнены все остальные фильтры и окончательные ресурсы, и вывод находится в пределах обертки. Таким образом, оригинальный Dofilter извлекает множество символов, представляющих вывод всех ресурсов. Если клиент утверждает, что он поддерживает сжатие (т. Е. Принимая GZIP в качестве значения для заголовка приема), фильтр добавляет GzipoutputStream в BytearrayOutputStream, копируйте массив символов в этот поток и устанавливает заголовок ответа на контент на Gzip. Если клиент не поддерживает GZIP, скопируйте немодифицированный массив символов в BytearRayOutputStream. Наконец, DoFilter отправляет результат клиенту, написав весь массив символов (вероятно, сжатый) в выходное производство, связанное с исходным ответом.
3) Зарегистрируйте Longservlet.
CompressionFilter.java
Пакет com.zj.sample; импорт java.io.bytearrayoutputstream; import java.io.ioexception; импорт java.io.outputstream; импорт java.io.outputstreamwriter; импорт java.util.zip.gzipoutputstream; импорт javax.servlet.filter; import.servlet.serther javax.servlet.filterConfig; import javax.servlet.servletexception; импорт javax.servlet.servletrequest; import javax.servlet.servletresponse; import javax.servlet.http.httpserveltrequest; import javax.servlet.httpsespessespess; /** * Фильтр, который сжимает выход с помощью GZIP (при условии, что браузер поддерживает * gzip). */public class compressionfilter реализует фильтр {private filterConfig config; /*** Если браузер не поддерживает GZIP, обычно вызовите ресурс. Если браузер * <i> выполняет </i> поддержать GZIP, установите заголовок ответа с контентом и * вызвать ресурс с помощью обернутого ответа, который собирает все выводы. * Извлеките вывод и напишите его в массив байтов GZEPIP. Наконец, напишите * этот массив в выходной поток клиента. */ public void dofilter (запрос ServletRequest, ответ ServletResponse, FilterChain Chain) Throws ServletException, ioException {httpservletRequest req = (httpservlectrequest) запрос; Httpservletresponse res = (httpservletresponse) ответ; if (! isgzipsupported (req)) {// вызывают ресурс нормально. chain.dofilter (req, res); } else {// Расскажите браузер, что мы отправляем ему данные. res.setheader («кодирование контента», «gzip»); // вызывают ресурс, накапливая выход в обертке. Chararraywrapper responsewrapper = new Chararraywrapper (res); chain.dofilter (req, responsewrapper); // Получить массив символов, представляющий вывод. char [] responseChars = responseWrapper.thararray (); // Сделать писателя, который сжимает данные и помещает их в массив байтов. BytearrayOutputStream Bytestream = new BytearRayOutputStream (); Gzipoutputstream Zipout = new GzipoutputStream (Bytestream); OutputStreamWriter tempout = new outputStreamWriter (Zipout); // Сжатие исходного вывода и поместите его в байтовый массив. tempout.write (responseechars); // потоки GZIP должны быть явно закрыты. tempout.close (); // Обновление заголовка длины содержимого. res.setContentLength (bytestream.size ()); // Отправить сжатый результат клиенту. OutputStream Realout = res.getOutputStream (); bytestream.writeto (Realout); }} /*** Храните объект FilterConfig в случае, если подклассы хотят этого. */ public void init (FilterConfig Config) Throws ServletException {this.config = config; } защищенный FilterConfig getFilterConfig () {return (config); } public void destress () {} private boolean isgzipsupported (httpservletrequest req) {string browserencodings = req.getheader ("accept-encoding"); 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.httpservlet; import javax.servlet.httplet.httplequest; javax.servlet.http.httpservletresponse; /*** Сервлет с <b> long </b> выходом. Используется для проверки эффекта сжатия * Фильтр главы 9. */ Public Class Longservlet расширяет httpservlet {public void Doget (httpservletrequest, httpservletresponse response) throws 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 = "длинная страница"; out.println (doctype + "<html>/n" + "<Head>" + title + "</title> </head>/n" + "<body bgcolor =/"#fdf5e6/">/n" + "<h1 align =/" center/">" + title + "</h1>/n"); String Line = "blah, blah, blah, blah, blah." + "Yadda, yadda, yadda, yadda."; for (int i = 0; i <10000; i ++) {out.println (line); } 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> <vervlet-class> com.zj.sample.longservlet </servlet-class> </servlet> <servlet-mapping> <servlet-name> longservlet </servlet-name> <url-pattern>/longservlet </url-pattern> </servlet-mapping> <url-pattern>/longservlet </url-pattern>