O que so Filtros Um filtro um componente Web que reside no servidor Intercepta as requisies e respostas no seu caminho at o servlet e de volta ao cliente Sua existncia ignorada por ambos. totalmente transparente tanto para o cliente quanto para o servlet Suportado desde a verso 2.3 da especificao de Servlets Filtros podem ser concatenados em uma corrente Neste cenrio, as requisies so interceptadas em uma ordem e as respostas em ordem inversa Filtros Um filtro pode realizar diversas transformaes, tanto na resposta como na requisio antes de passar esses objetos adiante (se o fizer) Filtros podem ser reutilizados em vrios servlets Para que servem? Filtros permitem Tomada de decises: podem decidir se repassam uma requisio adiante, se redirecionam ou se enviam uma resposta interrompendo o caminho normal da requisio Tratamento de requisies e respostas: podem empacotar uma requisio (ou resposta) em outra, alterando os dados e o contedo dos cabealhos Aplicaoes tpicas Autenticao Converso de caracteres, MIME types, tokenizing Converso de imagens, compresso e decompresso Criptografia Transformao XSLT Como funcionam? Quando o container recebe uma requisio, ele verifica se h um filtro associado ao recurso solicitado. Se houver, a requisio roteada ao filtro O filtro, ento, pode Gerar sua prpria resposta para o cliente Repassar a requisio, modificada ou no, ao prximo filtro da corrente, se houver, ou ao recurso final, se ele for o ltimo filtro Rotear a requisio para outro recurso Na volta para o cliente, a resposta passa pelo mesmo conjunto de filtros em ordem inversa API: Interfaces Filter, FilterConfig, FilterChain javax.servlet.Filter void init(FilterConfig), void doFilter(ServletRequest, ServletResponse, FilterChain) void destroy() javax.servlet.FilterConfig String getFilterName() String getInitParameter(String name) Enumeration getInitParameterNames() ServletContext getServletContext() javax.servlet.FilterChain void doFilter(ServletRequest, ServletResponse) API: Classes empacotadoras teis para que filtros possam trocar uma requisio por outra Uma subclasse dessas classes empacotadoras pode ser passada em uma corrente de filtros no lugar da requisio ou resposta original Mtodos como getParameter() e getHeader() podem ser sobrepostos para alterar parmetros e cabealhos No pacote javax.servlet ServletRequestWrapper implements ServletRequest: implementa todos os mtodos de ServletRequest e pode ser sobreposta para alterar o request em um filtro ServletResponseWrapper implements ServletResponse: implementa todos os mtodos de ServletResponse No pacote javax.servlet.http HttpServletRequestWrapper e HttpServletResponseWrapper: implementam todos os mtodos das interfaces correspondentes, facilitando a sobreposio para alterao de cabealhos, etc. Como escrever um filtro simples 1. Escreva uma classe implementando a interface Filter e todos os seus mtodos init(FilterConfig) doFilter(ServletRequest, ServletResponse, FilterChain) destroy() 2. Configure o filtro no deployment descriptor (web.xml) usando os elementos <filter> e <filter-mapping> Podem ser mapeados a URLs, como servlets Podem ser mapeados a servlets, para intercept-los A ordem dos mapeamentos significativa 3. Implante o filtro da maneira usual no servidor Filtro simples que substitui servlet Configurao Os elementos <filter> e <filter-mapping> so quase idnticos aos equivalentes para <servlet> A diferena que <filter-mapping> usado tambm para associar filtros a servlets, na ordem em que aparecem Filtro simples, que substitui um servlet
Filtro que intercepta um servlet Filtros "de verdade" Filtros teis podem ser encadeados em uma corrente. Para que isto seja possvel, devem chamar doFilter() no objeto FilterChain - parmetro no seu prprio doFilter() public void doFilter(...req,...res, FilterChain chain) { ... chain.doFilter(req, res); ... } Antes da chamada ao doFilter(), o filtro pode processar a requisio e alterar ou substituir os objetos ServletRequest e ServletResponse ao pass-los adiante ServletRequest newReq = new ModifiedRequest(...); chain.doFilter(newReq, res); Na volta, opera sobre a resposta e pode alter-la Configurao da corrente A corrente pode ser configurada com definio das instncias de filtros e mapeamentos em ordem
Filtros que tomam decises Um filtro pode ler a requisio e tomar decises como transform-la, pass-la adiante ou retorn-la Wrappers Sobrepondo um HttpServletRequest
Usando Wrappers em servlets HTTP Observaes importantes Para filtros usados com servlets HTTP, o request e response passados so HttpServletRequest e HttpServletResponse Wrappers devem estender as classes que implementam essas interfaces Filtros no so chamados quando o recurso que interceptam for chamado atravs de um RequestDispatcher O recurso acessado diretamente sem filtragem Isto ocorre para evitar loops infinitos Filtros associados a pginas de erro tambm no so chamados Sesses Como o HTTP no mantm estado de sesso, so as aplicaes Web que precisam cuidar de mant-lo quando necessrio Sesses representam um cliente A sesso nica para cada cliente e persiste atravs de vrias requisies Sesses Sesses so representados por objetos HttpSession e so obtidas a partir de uma requisio Dois mtodos podem ser usados HttpSession session = request.getSession(false); Se a sesso no existir, retorna null, caso contrrio retorna sesso. HttpSession session = request.getSession(); Retorna a sesso ou cria uma nova. Mesmo que getSession(true) Para saber se uma sesso nova, use o mtodo isNew() if (session.isNew()) { myObject = new BusinessObject(); } else { myObject = (BusinessObject) session.getAttribute("obj"); } getSession() deve ser chamado antes de getOutputStream()* Sesses podem ser implementadas com cookies, e cookies so definidos no cabealho HTTP (que montado antes do texto) Compartilhamento de objetos na sesso Dois mtodos setAttribute("nome", objeto); Object getAttribute("nome"); permitem o compartilhamento de objetos na sesso. Ex:
Como a sesso pode persistir alm do tempo de uma requisio, possvel que a persistncia de alguns objetos no sejam desejveis Use removeAttribute("nome") para remover objetos da sesso Gerncia de sesses No h como saber que cliente no precisa mais da sesso Pode-se definir um timeout em minutos para a durao de uma sesso desde a ltima requisio do cliente setMaxInactiveInterval(int) define novo valor para timeout int getMaxInactiveInterval() recupera valor de timeout Timeout default pode ser definido no web.xml para todas as sesses Outros mtodos teis: getLastAccessedTime() e getCreationTime() Para destruir uma sesso use session.invalidate(); Eventos de ligao e ativao de uma sesso podem ser controlados com implementaes das interfaces HttpSessionBindingListener e HttpSessionActivationListener Consulte a documentao. A abordagem dessas interfaces no faz parte do escopo deste curso Timeout default no web.xml O elemento <session-config> permite definir a configurao da sesso Deve aparecer depois dos elementos <servlet-mapping> O trecho abaixo redefine o tempo de durao default da sesso em 15 minutos para todas as sesses <session-config> <session-timeout>15</session-timeout> </session-config> Uma sesso especfica pode ter uma durao diferente se especificar usando setMaxInactiveInterval() Sesso prova de clientes A sesso implementada com cookies se o cliente suport-los Caso o cliente no suporte cookies, o servidor precisa usar outro meio de manter a sesso Soluo: sempre que uma pgina contiver uma URL para outra pgina da aplicao, a URL deve estar dentro do mtodo encodeURL() de HttpServletResponse out.print("<a href='" + response.encodeURL("caixa.jsp") + "'>"); Se cliente suportar cookies, URL passa inalterada (o identificador da sesso ser guardado em um cookie) Se cliente no suportar cookies, o identificador ser passado como parmetro da requisio ex: http://localhost:8080/servlet/Teste;jsessionid=A424JX08S99 Captura de eventos de atributos possvel saber quando um atributo foi adicionado a uma sesso usando HttpSessionAttributeListener e HttpSessionBindingEvent Mtodos a implementar do Listener attributeAdded(ServletContextAttributeEvent e) attributeRemoved(ServletContextAttributeEvent e) attributeReplaced(ServletContextAttributeEvent) HttpSessionBindingEvent possui trs mtodos para recuperar sesso e nome e valor dos atributos String getName() String getValue() HttpSession getSession() preciso registrar o listener no web.xml Captura de eventos do ciclo de vida Pode-se saber quando uma sesso foi criada, invalidada ou expirada usando HttpSessionListener: Mtodos sessionCreated() e sessionDestroyed() Para saber quando uma sesso existente foi ativada ou est para ser passivada usa-se HttpSessionActivationListener: Mtodos sessionDidActivate() e sessionWillPassivate() Para controlar quando objetos so associados a uma sesso e quando deixam a sesso (por qualquer razo) deve-se implementar um HttpSessionBindingListener Mtodos valueBound() e valueUnbound() Cada listener tem um evento correspondente, que recebido em cada mtodo. Para maiores detalhes, consulte a documentao e exemplos no Tomcat Maiores detalhes sobre este assunto fogem ao escopo deste curso Escopo de objetos em servlets Servlets podem compartilhar informaes de vrias maneiras Usando meios persistentes (bancos de dados, arquivos, etc) Usando objetos na memria por escopo (requisio, sesso, contexto) Usando variveis estticas ou de instncia Servlets oferecem trs nveis diferentes de persistncia na memria (ordem decrescente de durao) Contexto da aplicao: vale enquanto aplicao estiver na memria (javax.servlet.ServletContext) Sesso: dura uma sesso do cliente (javax.servlet.http.HttpSession) Requisio: dura uma requisio (javax.servlet.ServletRequest) Para gravar dados em um objeto de persistncia na memria objeto.setAttribute("nome", dados); Para recuperar ou remover os dados Object dados = objeto.getAttribute("nome"); objeto.removeAttribute("nome"); Escopo de objetos em servlets: resumo
Lidando com recursos compartilhados H vrios cenrios de acesso concorrente Componentes compartilhando sesso ou contexto Threads acessando variveis compartilhadas Servlets so automaticamente multithreaded O container cria um thread na instncia para cada requisio preciso sincronizar blocos crticos para evitar problemas decorrentes do acesso paralelo Exemplo: protegendo definio de atributo de contexto: synchronized(this) { context.setAttribute("nome", objeto); } Para situaes onde multithreading inaceitvel, servlet deve implementar a interface SingleThreadModel (s um thread estar presente no mtodo service() ao mesmo tempo) Evite isto a todo custo: muito ineficiente! Cookies Como j podemos manipular sesses de maneira transparente com HttpSession, usamos cookies principalmente para definir preferncias que iro durar alm do tempo da sesso Servidor ir criar cabealho que ir instruir o browser a criar um arquivo guardando as informaes do cookie Para criar cookies que duram mais que uma sesso (cookies persistentes no disco do cliente) preciso Criar um novo objeto Cookie Definir a durao do cookie com o mtodo setMaxAge() Definir outros mtodos se necessrio Adicionar o cookie resposta Como usar Cookies Exemplo de gravao: 1) definir um cookie que contenha o nome do usurio recebido como parmetro na requisio String nome = request.getParameter("nome"); Cookie c = new Cookie("usuario", nome); 2) Definir a durao do cookie em segundos c.setMaxAge(1000 * 24 * 3600 * 60); // 60 dias 3) Adicionar o cookie resposta response.addCookie(c); Exemplo de leitura: 1) recuperar o cookie da requisio Cookie[] cookies = request.getCookies(); 2) Extrair cookie para um objeto local for (int i = 0; i < cookies.length; i++) { if (cookies[i].getName().equals("nome") { usuario = cookies[i].getValue(); } } Exerccios Escreva um filtro simples que leia a requisio e verifique se ela contm os parmetros usuario e senha Se no tiver, repasse a requisio para a pgina erro.html Se tiver, abra o arquivo usuarios.txt usando a classe Properties. Ele possui uma lista de nome=senha, um por linha. Veja se o usurio coincide com a senha. Se sim, chame o prximo filtro. Se no, redirecione para acessoNegado.html Associe o filtro a um servlet qualquer (o SimpleServlet, por exemplo) Acesse o servlet e verifique que ele passa pelo filtro Exerccios Criar uma aplicao Web usando os objetos de negcio Produto. Atributos (mtodos get/set): int id, String nome, String preco Carrinho. Mtodos: addProduto(Produto), removeProduto(id), Produto getProduto(id), Produto[] getProdutos() a. Crie um servlet LojaServlet LojaServlet recebe parmetros para adicionar um produto e lista os produtos existentes como resposta b. Crie um servlet ComprasServlet ComprasServlet lista todos os produtos disponveis com um boto Adicionar ao lado de cada um. O boto deve adicionar o produto correspondente no objeto Carrinho. A resposta deve mostrar cada item includo com um boto Remover. Deve haver tambm boto Comprar Mais e Encerrar O Carrinho deve persistir entre requisies Exerccios Crie uma tela de entrada na loja LojaServlet com links para os servlets. Ela deve requisitar um e-mail. Grave o e-mail como um Cookie com durao de 30 dias. "Lembre-se" do e-mail na prxima requisio e mostre-o no text-field