1. Filtro de servlet
1.1 O que é um filtro
Um filtro é um programa que é executado no servidor antes da página do servlet ou JSP associada a ele. Os filtros podem ser anexados a uma ou mais Páginas de Servlets ou JSP e podem verificar as informações de solicitação que entram nesses recursos. Depois disso, o filtro pode ser selecionado da seguinte forma:
① Ligue para os recursos de uma maneira regular (ou seja, ligue para servlets ou páginas JSP).
② Use as informações de solicitação modificadas para ligar para o recurso.
③Call o recurso, mas modifique -o antes de enviar a resposta ao cliente.
④ Bloquear a chamada de recurso e, em vez disso, vá para outro recurso, retorne um código de status específico ou gerar saída de substituição.
1.2 Princípios básicos do filtro de servlet
Quando um servlet é usado como filtro, ele pode processar solicitações de clientes. Após a conclusão do processamento, ele será entregue ao próximo filtro para processamento, para que a solicitação do cliente seja processada uma a uma na cadeia de filtros até que a solicitação seja enviada ao destino. Por exemplo, um site possui uma página da web que envia "informações de registro modificadas". Depois que o usuário preenche as informações modificadas e as envia, o servidor precisa realizar duas tarefas ao processar: determinar se a sessão do cliente é válida; e codificar uniformemente os dados enviados. Essas duas tarefas podem ser processadas em uma cadeia de filtro composta por dois filtros. Quando o processo de filtro é bem -sucedido, os dados enviados são enviados ao destino final; Se o processo de filtro não tiver êxito, a visualização será distribuída na página de erro especificada.
2. Etapas de desenvolvimento do filtro de servlet
As etapas para o desenvolvimento de um filtro de servlet são as seguintes:
① Escreva uma classe de servlet que implemente a interface do filtro.
②Configure filtro em web.xml.
O desenvolvimento de um filtro requer implementar a interface do filtro. A interface do filtro define os seguintes métodos:
① Destory () é chamado pelo contêiner da web para inicializar esse filtro.
② INIT (FILTERCONFIG FILTERCONFIG) é chamado pelo contêiner da web para inicializar esse filtro.
③ Dofilter (Solicitação de ServletRequest, Resposta do ServletResponse, Cadeia de Filtro -Chain) Código de processamento de filtragem específico.
3. Um exemplo de estrutura de filtro
Simplefilter1.java
pacote com.zj.sample; importar java.io.ioException; importar javax.servlet.filter; importar javax.servlet.filterchain; importar javax.servlet.filterConfig; importleQuest.servlet.servlet.Servlexception; importtlestlet.ServletRex; classe pública SimpleFilter1 implementa o filtro {@suppresswarnings ("não utilizado") private filtroConfig filterConfig; public void init (filterConfig config) lança servletexception {this.filterconfig = config; } public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtro) {try {System.out.println ("dentro do simplesFilter1: filtrando a solicitação ..."); Chain.Dofilter (solicitação, resposta); // Envie o processamento para o próximo sistema de filtro.out .println ("dentro do simplesFilter1: filtrando a resposta ..."); } catch (ioexception ioe) {ioe.printStackTrace (); } catch (servletexception SE) {SE.printStackTrace (); }} public void Destroy () {this.FilterConfig = null; }}
Simplefilter2.Java
pacote com.zj.sample; importar java.io.ioException; importar javax.servlet.filter; importar javax.servlet.filterchain; importar javax.servlet.filterConfig; importleQuest.servlet.servlet.Servlexception; importtlestlet.ServletRex; classe pública Simplefilter2 implementa o filtro {@suppresswarnings ("não utilizado") private filtroConfig filterConfig; public void init (filterConfig config) lança servletexception {this.filterconfig = config; } public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtro) {try {System.out.println ("dentro do simplesFilter2: filtrando a solicitação ..."); Chain.Dofilter (solicitação, resposta); // Envie o processamento para o próximo sistema de filtro.out.println ("dentro do simplesFilter2: filtrando a resposta ..."); } catch (ioexception ioe) {ioe.printStackTrace (); } catch (servletexception SE) {SE.printStackTrace (); }} public void Destroy () {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> filtro2 </filter-name> <url-pattern>/*</url-pattern> // filtro para todas as visitas </filter-mapping>
Abra qualquer página no contêiner da web para produzir o resultado: (Observe a solicitação/ordem de resposta executada pelo filtro)
Dentro do simplesFilter1: filtrando a solicitação ... dentro do simplesFilter2: filtrando a solicitação ... dentro do simplesFilter2: filtrando a resposta ... dentro do simplesfilter1: filtrando a resposta ...
4. Filtro de relatório
Vamos experimentar um filtro simples que imprime uma mensagem para a saída padrão, chamando a página de servlet ou jsp relevante. Para implementar essa função, o comportamento de filtragem é realizado no método Dofilter. Sempre que uma página de servlet ou jsp associada a este filtro é chamada, o método Dofilter gera uma impressão que lista o host solicitado e o URL da chamada. Como o método getRequesturl está localizado no httpServletRequest em vez do servletRequest, o objeto ServletRequest é construído como o tipo HttpServletRequest. Vamos alterar o simplesFilter1.java no capítulo 3.
Simplefilter1.java
pacote com.zj.sample; importar java.io.ioexception; importar java.util.date; importar javax.servlet.filter; importar javax.servlet.filterchain; importestleTexception.Servlet.FilterConfig; import Javax.Servlet.ServLeTexception; importação Javot.FilterCofig; importação.Servlet.ServLeTexception; importex. Javax.Servlet.ServletResponse; importar javax.servlet.http.httpServletRequest; classe pública SimpleFilter1 implementa o filtro {@suppresswarnings ("não utilizado") private filtroConfig filterConfig; public void init (filterConfig config) lança servletexception {this.filterconfig = config; } public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtro) {try {System.out.println ("dentro do simplesFilter1: filtrando a solicitação ..."); HttpServletRequest req = (httpServletRequest) solicitação; System.out.println (req.getRemoteHost () + "tentou acessar" + req.getRequesturl () + "on" + new Date () + "."); Chain.Dofilter (solicitação, resposta); System.out.println ("dentro do simplesFilter1: filtrando a resposta ..."); } catch (ioexception ioe) {ioe.printStackTrace (); } catch (servletexception SE) {SE.printStackTrace (); }} public void Destroy () {this.FilterConfig = null; }}
As configurações Web.xml permanecem inalteradas, no mesmo capítulo 3.
teste:
Digite [url] http: // localhost: 8080/test4jsp/login.jsp [/url]
resultado:
Dentro do SimpleFilter1: Filtrando a solicitação ... 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 1 Tentei acessar [url] http: // localhost: 8080/test4jsp/login.jsp [/url] no sol 04 17:01:37 CST 2007.W A resposta ... dentro do simplesFilter1: filtrando a resposta ...
5. Filtros no Access (usando servlets para inicializar parâmetros em filtros)
O seguinte é definir um intervalo de tempo de acesso normal usando o init para registrar acessos que não estão neste período. Vamos alterar o simplesFilter2.Java no capítulo 3.
Simplefilter2.Java.
pacote com.zj.sample; importar java.io.ioException; importar java.text.dateFormat; importar java.util.calendar; importar java.util.greiancalendar; importação javax.servlet.filter; importterl.FilterCax; Importocal; javax.servlet.servletContext; importar javax.servlet.servletexception; importar javax.servlet.servletRequest; importar javax.servlet.servletResponse; importar javax.servlet.http.httpsletrequest; classe pública Simplefilter2 implementa o filtro {@suppresswarnings ("não utilizado") private filterConfig config; contexto privado servletContext; Private Int StartTime, Endtime; FORMATRE DE DATA DE DATA PRIVADO; public void init (filterConfig config) lança servletexception {this.config = config; context = config.getServletContext (); formatter = dateFormat.getDateTimeInstance (DateFormat.Medium, DateFormat.Medium); tente {startTime = Integer.parseint (config.getInitParameter ("starttime")); // web.xml endtime = intoger.parseint (config.getInitParameter ("Endtime"); // web.xml} (número do número 10) // // mAfford ou null // null // web.xml} (número do NFexception) {//formed ou null // null // web.xml} (número do NFexception) {//formed ou null // null // web.xml} (número do NFETEXCECTION); startTime = 22; // 22:00 EndTime = 6; // 6:00 da manhã}} public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtro) {try {System.out.println ("dentro do simplesFilter2: filtrando a solicitação ..."); HttpServletRequest req = (httpServletRequest) solicitação; Calendário GregoriaCalendar = New GregorianCalendar (); int currenttime = calendar.get (calendar.hour_of_day); if (isunusualTime (CurrentTime, StartTime, Endtime)) {context.log ("Warning:" + req.getRemoteHost () + "Acesso" + req.getRequesturl () + "em" + formatter.format (calendar.gettime ())); // O arquivo de log está em <Catalina_home> /logs.one log por dia. } cadeia.dofilter (solicitação, resposta); System.out .println ("dentro do simplesFilter2: filtrando a resposta ..."); } catch (ioexception ioe) {ioe.printStackTrace (); } catch (servletexception SE) {SE.printStackTrace (); }} public void Destroy () {} // O horário atual é entre o início e o final // tempos marcados como tempos de acesso absolutos? ISUNUSTURO BOOLEAN PRIVADO (INT CurrentTime, int StartTime, int Endtime) {// Se o horário de início for menor que o horário de término (ou seja, // eles são duas vezes no mesmo dia), então o // tempo atual é considerado incomum se estiver // entre os horários iniciais e de término. if (starttime <endtime) {return ((currentTime> = startTime) && (current)); } // Se o horário de início for maior ou igual ao horário de término // (ou seja, o tempo de início é um dia e // o horário de término será no dia seguinte), o tempo atual // é considerado incomum se não estiver entre // o final e o início do início. else {return (! isunusualTime (CurrentTime, Endtime, StartTime)); }}}
As configurações Web.xml permanecem inalteradas.
Em relação ao processamento do log do Tomcat, aqui está uma introdução adicional. config.getServletContext (). LOG ("Mensagem de log") escreverá informações de log na pasta <Catalina_home>/logs. O nome do arquivo deve ser localhost_log.2007-03-04.txt (um é gerado por dia por data e pode ser visto no dia seguinte). Para obter esse arquivo de log, você deve ter:
<Logger ClassName = "org.apache.catalina.logger.filelogger" prefix = "catalina_log". sufix = ". txt" timestamp = "true"/>
6. Os filtros do local são proibidos
Se você deseja interromper o processo de filtragem subsequente no meio do caminho quando seu filtro detectar uma exceção anormal, você pode fazer isso:
Public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtro) lança servletexception, ioexception {httpServletRequest req = (httpServleTrequest); HttpServletResponse res = (httpServletResponse); if (isunusualCondition (req)) {res.sendredirect ("http://www.somesite.com"); } else {Chain.dofilter (req, res); }} O exemplo a seguir é um filtro de site proibido. Se você não deseja que alguns sites acessem seu site, poderá listar seu site no valor do parâmetro do web.xml e, em seguida, aplicar o princípio acima para sair da filtragem regular e fornecer a página proibida.
BannedAccessFilter.java
pacote com.zj.sample; importar java.io.ioException; importar java.io.printwriter; importar java.net.malformedurlexception; importar java.net.url; import javax.util.hashset; import java.utilil.stringToken; javax.servlet.filterConfig; importar javax.servlet.servletexception; importar javax.servlet.servletRequest; importar javax.servlet.servletResponse; importar javax.servlet.http.htttsletrequest; classe pública BannedAccessFilter implementa o filtro {private HashSet <String> bannedSiteTable; /*** negar o acesso se a solicitação vier de um site bancada ou for referido aqui* por um site bannerado. */ Public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtragem) lança servletexception, ioexception {System.out.println ("dentro de BannedAccessFilter: filtrando a solicitação ..."); HttpServletRequest req = (httpServletRequest) solicitação; String solicitandoHost = req.getRemoteHost (); String referenceringHost = getReferringHost (req.getheader ("referente")); String bannedSite = null; boolean isbann = false; if (bannedSitEtable.Contains (RequestingHost)) {bannedSite = solicitando. isBann = true; } else if (bannedSiteTable.contains (referringHost)) {bannedSite = referringHost; isBann = true; } if (isbann) {showwarning (resposta, bannedSite); } else {Chain.dofilter (solicitação, resposta); } System.out.println ("dentro do BannedAccessFilter: filtrando a resposta ..."); } /*** Crie uma tabela de sites banidos com base nos parâmetros de inicialização.* Lembre -se de que a versão 2.3 da API Servlet exige o uso da plataforma* java 2. Assim, é seguro usar o hashset (que determina* se uma determinada chave existe) em vez do hashtable mais clos (que tem um valor para cada chave).*/ Public void init (filterConfig config) lança servletexception {bannerredSiteTable = new Hashset <string> (); String bannedSites = config.getInitParameter ("BannedSites"); // Conjunto de token padrão: espaço em branco. StringTokenizer TOK = new StringTokenizer (BannedSites); while (tok.hasmoretokens ()) {string bannedSite = tok.nextToken (); bannedsiteTable.add (BanningSite); System.out.println ("banido" + bannedSite); }} public void Destroy () {} Private String getReferringHost (String refererringUrlString) {try {url referringurl = new URL (refererringurlString); return (referringurl.gethost ()); } catch (MalformEdurLexception mue) {// Malformed ou Null Return (null); }} // Resposta de substituição que é retornada aos usuários // que são ou referidos aqui por um site de banner. Showwarning privado de void (resposta servletResponse, string bannedSite) lança servletexception, ioexception {Response.setContentType ("text/html"); PrintWriter out = Response.getWriter (); String doctype = "<! Doctype html public/"-// w3c // dtd html 4.0 " +" transitório // en/">/n"; out.println (doctype + "<html>/n" + "<head> <title> access proibido </ititle> </ad Head>/n" + "<corpo bgcolor =/" branco/">/n" + "<h1> access proibido </h1>/n" + "de desculpa, acesso ou" bancado " + bancado +" "</body> </html>"); }}
web.xml
<filter> <filter-name> BannedAccessFilter </filter-Name> <filter-Class> com.zj.sample.banningAccessfilter </limter-Class> <iit-param> <amam-name> bannsites </param-name> <amon-value> [url] wwbet.competingsite [/url] [url] ww WW WW WW WW WW WW.CEBTENCIDO.com [/url] [url] www.moreServlets.com [/url] 127.0.0.1//we Teste este </amam-value> </irit-param> </filter> <filter-mapping> <filter-name> bannedaccessfilter </filter-name> <url-pattern>/*</url-tattern>
teste:
[url] http: // localhost: 8080/test4jsp/[/url]
resultado:
7. Substitua o filtro
7.1 Modifique a resposta
Os filtros podem bloquear o acesso a recursos ou impedir que sejam ativados. Mas se o filtro quiser alterar a resposta gerada pelo recurso. O que fazer? Parece não haver como acessar a resposta gerada por um recurso. O segundo parâmetro do Dofilter (ServletResponse) fornece uma maneira de enviar uma nova saída para o cliente, mas não fornece ao filtro uma maneira de acessar a saída da página do servlet ou JSP. Por que isso está acontecendo? Porque a página do servlet ou JSP nem foi executada quando o método Dofilter é chamado pela primeira vez. Depois que o método Dofilter no objeto FilterChain é chamado, parece tarde demais para modificar a resposta, que é que os dados foram enviados ao cliente.
No entanto, existe uma maneira, ou seja, modificar o objeto de resposta do método Dofilter passado para o objeto FilterChain. Geralmente, construa um cache de todas as versões de saída geradas por uma página de servlet ou jsp. A API do servlet versão 2.3 fornece um recurso útil para isso, a saber, a classe HttpServletResponseWrapper. O uso desta classe inclui as cinco etapas seguintes:
1) Crie um invólucro de resposta. Estend javax.servlet.http.httpServletResponseWrapper.
2) Forneça um criador de impressão que armazena em cache de saída. Sobrecarregar o método GetWriter, retorne um PrintWriter que salva tudo enviado a ele e salva o resultado em um campo que pode ser acessado posteriormente.
3) Passe este invólucro para Dofilter. Esta chamada é legal porque o httpServletResponseWrapper implementa HttpServletResponse.
4) Extraia e modifique a saída. Depois de chamar o método Dofilter de filtro, a saída do recurso original pode ser obtida usando o mecanismo fornecido na etapa 2. Você pode modificá -lo ou substituí -lo, desde que seja adequado para o seu aplicativo.
5) Envie a saída modificada para o cliente. Como o recurso original não envia mais saídas para o cliente (essas saídas já estão armazenadas no seu wrapper de resposta), essas saídas devem ser enviadas. Dessa forma, seu filtro precisa obter um PrintWriter ou OutputStream do objeto de resposta original e passar a saída modificada para o fluxo.
7.2 Um invólucro de resposta reutilizável
O exemplo a seguir fornece um invólucro que pode ser usado na maioria dos aplicativos em que o filtro deseja modificar a saída do recurso. A classe CharArrayWrapper sobrecarrega o método GetWriter para retornar um PrintWriter que acumula tudo em uma grande matriz de caracteres. Os desenvolvedores podem obter esse resultado usando o TOCharArray (CHAR original []) ou a tostragem (uma string derivada de char []).
CharArrayWrapper.java
pacote com.zj.sample; importar java.io.charArrayWriter; importar java.io.printwriter; importar javax.servlet.http.httpServletResponse; importar javax.servlet.http.httpsLeResponse; /** * Um invólucro de resposta que leva tudo o que o cliente normalmente * produzia e o salva em uma grande matriz de caracteres. */classe pública CharArrayWrapper estende HttpServletResponseWrapper {private CharArrayWriter Charwriter; /*** Inicializa o wrapper. * <p> * Primeiro, este construtor chama o construtor pai. Essa chamada *é cruel para que a resposta seja armazenada e, portanto, Setheader, *SetStatus, Addcookie e assim por diante, o trabalho normalmente. * <p> * Segundo, este construtor cria um CharArrayWriter que será usado para acumular a resposta. */ public CharArrayWrapper (httpServletResponse Response) {super (resposta); charwriter = new CharArrayWriter (); } /*** Quando servlets ou páginas JSP pedem o escritor, não dê -lhes* o real. Em vez disso, dê a eles uma versão que grava em* a matriz de personagens. * O filtro precisa enviar o conteúdo da matriz para o* cliente (talvez depois de modificá -lo). */ public printWriter getWriter () {return (new PrintWriter (Charwriter)); } /*** Obtenha uma representação de string de todo o buffer. * <p> * Certifique -se de <b> não </b> para chamar esse método várias vezes no mesmo wrapper *. A API para CharArrayWriter não garante que * "lembre -se" do valor anterior, portanto a chamada provavelmente fará * uma nova string todas as vezes. */ public string tostring () {return (charwriter.toString ()); } /** Obtenha a matriz de caracteres subjacente. */ public char [] toCharArray () {return (charwriter.toCharArray ()); }}
7.3 Substitua o filtro
Aqui está uma aplicação comum do CharArrayWrapper, fornecido na seção anterior: alterando um filtro para uma sequência de destino de múltiplas ocorrências para uma sequência substituta.
7.3.1 Filtro de substituição geral
O SubstituirFilter.java fornece um filtro que envolve a resposta no ChararraryWrapper, passa o invólucro para o método Dofilter do objeto FilterChain, extrai um valor do tipo string que fornece a saída de todos os recursos, substitui todas as ocorrências de uma string de destino por uma sequência de substituição e envia o resultado modificado para o cliente.
Há duas coisas a serem observadas sobre esse filtro. Primeiro, é uma classe abstrata. Para usá -lo, você deve criar uma subclasse que forneça a implementação dos métodos GetTargetString e GetReplacementsTring. Um exemplo deste tratamento é apresentado na próxima subseção. Segundo, ele utiliza uma classe de utilidade menor (consulte FilterUtils.java) para substituição real da string. Você pode usar novos pacotes de expressão regular em vez de usar métodos de baixo nível e tedioso no String e StringTokenizer.
Substituirfilter.java
package com.zj.sample;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.Servlet.ServletResponse; importar javax.servlet.http.httpServletResponse; /*** filtro que substitui todas as ocorrências de uma determinada string por uma substituição*. * Esta é uma classe abstrata: você deve substituir os métodos GetTargetString* e GetReplacementsTring em uma subclasse.* O primeiro desses métodos especifica a sequência na resposta* que deve ser substituída. A segunda dessas especificações a string* que deve substituir cada ocorrência da sequência de destino. */public abstrate classe replatefilter implementa o filtro {private filterConfig config; Public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtro) lança servletexception, ioexception {CharArrayWrapper ResponseWrapper = new CharArrayWrapper ((httpServletResponse) Response); // Invoque o recurso, acumulando saída no invólucro. Chain.Dofilter (solicitação, resposta); // Transforme a saída inteira em uma grande corda. String ResponsEstring = ResponseWrapper.toString (); // Na saída, substitua todas as ocorrências da sequência de destino com a substituição // string. ResponsEstring = filterUtils.Replace (ResponsEstring, getTargetString (), getReplacementString ()); // Atualize o cabeçalho de comprimento de conteúdo. UpdateHeaders (resposta, responseString); PrintWriter out = Response.getWriter (); out.Write (Responsestring); } /*** Armazene o objeto FilterConfig Caso as subclasses desejem. */ public void init (filterConfig config) lança servletexception {this.config = config; } FilterConfig protegido getFilterConfig () {return (config); } public void Destroy () {} /*** A sequência que precisa de substituição.* Substitua esse método na sua subclasse. */ public abstrate string getTargetString (); /*** A sequência que substitui o destino. Substitua este método em * sua subclasse. */ public abstract string getReplacementString (); /*** Atualiza os cabeçalhos de resposta. Esta versão simples apenas define* o cabeçalho do comprimento do conteúdo, assumindo que estamos usando um conjunto de caracteres* que usa 1 byte por caractere. */ public void updateHeaders (Resposta do servletResponse, String Responsetring) {Response.SetContentLength (ResponsEstring.Length ()); }}
Filtrutils.java
pacote com.zj.sample; /*** Pequeno utilitário para ajudar com os invólucros de resposta que retornam strings. * /Public class filterUtils { /*** Altere todas as ocorrências de origem na placa de mains para substituir. */ public static string reply (string mainstring, string orig, substituição de string) {string resultado = ""; int OldIndex = 0; int index = 0; int origlength = orig.length (); while ((index = mainstring.indexof (orig, OldIndex))! = -1) {resultado = resultado + mainstring.substring (OldIndex, índice) + substituição; OldIndex = Índice + OrigLength; } resultado = resultado + mainstring.substring (OldIndex); return (resultado); }} 7.3.2 Implemente um filtro de substituição de caracteres. Suponha que o Baidu adquiriu o Google (apenas uma hipótese), todos os textos com a palavra Google em todas as páginas devem ser substituídos pelo Baidu! SubstituaneteNameFilter.java herda o substituto Filter.java acima para implementar esta função. Substitua o nome do samado.javapackage com.zj.sample; classe pública SubstituaNameFilter estende Substituir Filter {public String getTargetString () {return ("google.com.cn"); } public string getReplacementsTring () {return ("Baidu.com"); }}
web.xml
<filter> <filter-name> substitui-sefilter </filter-name> <filter-Class> com.zj.sample.replacesitenameFilter </ftrids-class> </filter> <filter-mapping> <filter-name> replacesitenamefilter </filter-name <rattern> /login>
Resultados do teste:
Antes de filtrar
Após a filtragem
8. filtro de compressão
Existem vários navegadores mais recentes que podem lidar com conteúdo compactado, descompacte automaticamente o arquivo compactado com o GZIP como o valor do cabeçalho da resposta que codifica conteúdo e, em seguida, processe os resultados como o documento original. O envio desse conteúdo compactado pode economizar muito tempo, porque o tempo necessário para comprimir um documento no servidor e, em seguida, desfazer o documento no cliente é trivial em comparação com o tempo necessário para baixar o arquivo. O programa LongServlet.java fornece um servlet com saída de texto simples e longa e duplicado, um servlet maduro para compactação. Se você usar o GZIP, ele pode comprimir a saída para 1/300!
Quando o navegador suporta essa capacidade de compactação, o filtro de compressão pode usar o CharArrayWrapper introduzido no Capítulo 7 para comprimir o conteúdo. O conteúdo a seguir é necessário para concluir esta tarefa:
1) Classe que implementa a interface do filtro. Esta classe é denominada Filter de compressão. O método init armazena o objeto FilterConfig em um campo, caso a subclasse precise acessar o ambiente do servlet ou o nome do filtro. O corpo do método do destino está vazio.
2) o objeto de resposta embrulhada. O método Dofilter envolve o objeto ServletResponse em um CharArrayWrapper e passa esse invólucro para o método Dofilter do objeto FilterChain. Após a conclusão desta chamada, todos os outros filtros e recursos finais foram executados e a saída está dentro do invólucro. Dessa forma, o Dofilter original extrai uma variedade de caracteres representando a saída de todos os recursos. Se o cliente afirmar que suporta compactação (ou seja, tomando o GZIP como um valor para o cabeçalho de codificação de aceitação), o filtro anexa um gzipOutputStream ao bytearrayoutputStream, copie a matriz de caracteres nesse fluxo e define o cabeçalho de resposta de codificação de conteúdo para Gzip. Se o cliente não suportar o GZIP, copie a matriz de caracteres não modificada para bytearrayOutputStream. Finalmente, o Dofilter envia o resultado ao cliente, escrevendo toda a matriz de caracteres (provavelmente compactada) para o outputstream associado à resposta original.
3) Registre o LongServlet.
Compressionfilter.java
pacote com.zj.sample; importar java.io.byteArrayoutputStream; importar java.io.ioException; importar java.io.outputStream; importar java.io.outputStreamWriter; importAmFilter; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; importin; import.util.zip.gzipoutTream; importtlet.Servlet.filter; import.util.zip.gzipout; javax.servlet.ServleTexception; importar javax.servlet.servletRequest; importar javax.servlet.servletResponse; import javax.servlet.htttp.httpsletrequest; /** * filtra que comprime a saída com GZIP (assumindo que o navegador suporta * gzip). */public class ComppressionFilter implementa filtro {private filterConfig config; /*** Se o navegador não suportar o GZIP, invoca o recurso normalmente. Se o navegador * <i> </i> suportar GZIP, defina o cabeçalho da resposta de codificação de conteúdo e * Invoque o recurso com uma resposta embrulhada que coleta toda a saída. * Extraia a saída e escreva -a em uma matriz de bytes. Finalmente, escreva * essa matriz no fluxo de saída do cliente. */ Public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtragem) lança servletexception, ioexception {httpServletRequest req = (httpServletRequest) solicitação; HttpServletResponse res = (httpServletResponse); if (! isgzipsupportd (req)) {// Invoco o recurso normalmente. Chain.Dofilter (req, res); } else {// diga ao navegador que estamos enviando dados gzipped. res.Setheader ("codificação de conteúdo", "gzip"); // Invoque o recurso, acumulando saída no invólucro. CharArrayWrapper ResponseWrapper = new CharArrayWrapper (res); Chain.Dofilter (Req, Responswrapper); // Obtenha a matriz de caracteres representando a saída. char [] ResponseChars = ResponseWrapper.ToCharArray (); // Faça um escritor que comprime dados e o coloque em uma matriz de bytes. ByteArrayOutputStream byTestream = new ByteArrayOutputStream (); GzipOutputStream zipout = new GzipOutputStream (BYTESTREAM); OutputStreamWriter tempout = new OatdStreamWriter (zipout); // Compacte a saída original e coloque -a na matriz de bytes. tempout.write (ResponseChars); // Os fluxos GZIP devem ser explicitamente fechados. tempout.close (); // Atualize o cabeçalho de comprimento de conteúdo. res.setContentLength (byTestream.size ()); // Envie resultado compactado para o cliente. OutputStream realout = res.getOutputStream (); byTestream.WritEto (Realout); }} /*** Armazene o objeto FilterConfig, caso as subclasses desejem. */ public void init (filterConfig config) lança servletexception {this.config = config; } FilterConfig protegido getFilterConfig () {return (config); } public void Destroy () {} private boolean isgzipsupported (httpServletRequest req) {string BrowSerencodings = req.getheader ("aceitar-se-codificação"); 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.http.HttpServletRequest;import javax.servlet.http.httpServletResponse; /*** servlet com <b> long </b> saída. Usado para testar o efeito do filtro de compactação * do capítulo 9. */ Public Class LongServlet estende HttpServlet {public void Doget (solicitação httpServletRequest, httpServletResponse resposta) lança servleTexception, ioxception {Response.setTyTyType ("text/ html"); PrintWriter out = Response.getWriter (); String doctype = "<! Doctype html public/"-// w3c // dtd html 4.0 " +" transitório // en/">/n"; String title = "Long Page"; out.println (doctype + "<html>/n" + "<head> <title>" + title + "</title> </head>/n" + "<corpo bgcolor =/"#fdf5e6/">/n" + "<h1 align =/" center/"" " + title +" </h1> String line = "blá, blá, blá, blá, blá." + "Yadda, yadda, yadda, yadda."; for (int i = 0; i <10000; i ++) {out.println (linha); } 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 </stert-name> <ervlet-name> longServlet </servlet> </filter-maplet> <Verlet-class> com.zj.sample.longservlet </servlet-class> </servlet> <Verlet-mapping> <Servlet-name> longServlet </vlect-name> <url-Pattern>/LongServlet </url-pattern> </sertlet>