• Nenhum resultado encontrado

Aula 7: Servlets (II)

N/A
N/A
Protected

Academic year: 2021

Share "Aula 7: Servlets (II)"

Copied!
31
0
0

Texto

(1)

Aula 7: Servlets (II)

Diego Passos

Universidade Federal Fluminense

(2)

´

Ultima Aula

O que s˜ao Servlets.

Estrutura b´asica de um Servlet. Criac¸˜ao de Servlets simples. Contexto de um Servlet. Informac¸˜oes sobre requisic¸˜oes.

(3)

Nesta Aula

Respostas de requisic¸˜oes. Inicializac¸˜ao de Servlets. Filtros.

(4)

Respostas a Requisic¸˜

oes

Servlets recebem requisic¸˜oes. Clientes esperam respostas.

I Dados de uma consulta. I Confirmac¸˜ao de uma operac¸˜ao. I . . .

Para um Servlet HTTP, resposta cont´em trˆes partes:

I C´odigo de status. I Cabec¸alhos HTTP. I Corpo da resposta.

(5)

Respostas a Requisic¸˜

oes (II)

Manipulac¸˜ao da resposta ´e feita pelas interfaces ServletResponse e HttpServletResponse.

Incluem m´etodos para a criac¸˜ao e manipulac¸˜ao das trˆes partes da resposta de um Servlet. Exemplo de m´etodo de manipulac¸˜ao da resposta: setContentType().

I Recebe como parˆametro uma String especificando um MIME: e.g., “text/html”. I Configura o header Content-Type na resposta.

(6)

Respostas a Requisic¸˜

oes (III)

Interfaces ServletResponse e HttpServletResponse tamb´em s˜ao usadas para produzir stream de sa´ıda.

Dois m´etodos:

I getOutputStream(): retorna um ServletOutputStream para conte´udo bin´ario ou

texto.

I getWriter(): retorna um PrintWriter para conte´udo texto apenas.

Aten¸c˜ao ao usar o m´etodo getWriter():

I Ele inspeciona o Content-Type para determinar configurac¸˜oes de codificac¸˜ao de caracteres.

(7)

Respostas a Requisic¸˜

oes (IV)

H´a m´etodos espec´ıficos para a interface HttpServletResponse.

Estes m´etodos obviamente manipulam componentes espec´ıficos de respostas HTTP. Exemplo: manipulac¸˜ao de cabec¸alhos.

I setHeader(String,String): configura o valor de um cabec¸alho como uma string. I setIntHeader(String,int): configura o valor de um cabec¸alho como um inteiro.

I setDateHeader(String,long): configura o valor de um cabec¸alho como uma data

(milisegundos desde a Era Unix ).

(8)

Respostas a Requisic¸˜

oes (V)

´

E poss´ıvel ainda manipular o c´odigo de status da resposta. Feito atrav´es de dois m´etodos:

I setStatus(int): envia o c´odigo correspondente `a constante especificada.

I sendError(int, String): envia o c´odigo correspondente `a constante especificada e uma mensagem de erro.

F N˜ao pode ser usado se j´a houve sa´ıda enviada ao cliente.

Outro m´etodo ´util ´e o sendRedirect(String): envia um redirecionamento a outra URL. O parˆametro da func¸˜ao pode especificar:

I Uma URL absoluta.

I Um caminho relativo ao contexto do servlet (iniciado pelo caracter “/”). I Um caminho relativo `a URL atual (iniciado sem o caracter “/”).

(9)

Despacho de Requisic¸˜

oes

Muitas vezes em um Servlet e desej´avel delegar uma requisic¸˜ao a um outro servlet. Exemplos:

I Servlet principal apenas detecta qual servlet “secund´ario” deve ser chamado. I Servlet principal chama servlets secund´arios para obter “pedac¸os” da resposta.

API de Servlets permite este tipo de soluc¸˜ao atrav´es da classe RequestDispatcher. A partir de um ServletContext ´e poss´ıvel obter um RequestDispatcher:

ServletContext context = getServletContext();

RequestDispatcher d = getRequestDispatcher("/ServletSecundario");

(10)

Despacho de Requisic¸˜

oes (II)

De posse de um objeto do tipo RequestDispatcher ´e poss´ıvel fazer dois tipos de delegac¸˜ao:

I forward : a responsabilidade pela requisic¸˜ao ´e totalmente passada para o Servlet secund´ario. I include: apenas inclui a sa´ıda do Servlet secund´ario na sa´ıda do Servlet prim´ario.

A classe RequestDispatcher define dois m´etodos correspondentes: forward() e include().

Exemplo de delegac¸˜ao do tipo include: out.println("Uptime for our servers");

ServletContext context = getServletContext();

RequestDispatcher d = context.getRequestDispatcher("/servlet/ServerMonitor"); req.setAttribute("serverurl", new URL("http://www1.company.com"));

d.include(req, res);

req.setAttribute("serverurl", new URL("http://www2.company.com")); d.inc1ude(req, res);

(11)

Despacho de Requisic¸˜

oes (III)

Qual a diferenc¸a entre um despacho do tipo forward e um redirecionamento?

I Redirecionamento exige que cliente receba a resposta e fac¸a uma nova requisic¸˜ao. I No despacho, a mesma requisic¸˜ao ´e passada internamente ao servidor para o servlet em

quest˜ao. I Consequˆencias:

F Despacho tende a ser mais r´apido.

F Para o cliente, URL se mant´em como a da requisic¸˜ao original.

Note que o m´etodo getRequestDispatcher() pode ser usado para qualquer tipo de recurso dentro do contexto do Servlet.

I Arquivos HTML est´aticos, imagens, . . . I N˜ao apenas outros Servlets.

(12)

Lidando com Erros

O que fazer quando o Servlet encontra uma situac¸˜ao de erro ao processar uma requisic¸˜ao? H´a v´arias possibilidades.

A API de Servlets provˆe duas:

I Enviar uma mensagem de erro diretamente ao cliente. I Levantar uma excec¸˜ao.

(13)

Lidando com Erros: Enviando Mensagem ao Cliente

´

E poss´ıvel imprimir mensagens de erro diretamente ao cliente.

I Da mesma forma que imprimimos o conte´udo de uma resposta qualquer.

No entanto, ´e mais elegante (e muitas vezes poderoso) utilizar um m´etodo espec´ıfico para isso:

I sendError(int): envia um c´odigo de erro HTTP ao cliente com uma mensagem de erro padr˜ao.

I sendError(int, String): envia um c´odigo de erro HTTP ao cliente com uma mensagem

de erro especificada.

Ambos os m´etodos podem ser acessados atrav´es da interface HttpServletResponse: response.sendError(HttpServletResponse.SC_NOT_FOUND);

response.sendError(HttpServletResponse.SC_NOT_FOUND,

"Could not find the specified file.");

(14)
(15)

Lidando com Erros: Gerando Excec¸˜

oes

Breve revis˜ao:

I Excec¸˜oes s˜ao a maneira padr˜ao de lidar com erros em Java.

I Um m´etodo pode se declarar capaz de gerar um determinado tipo de excec¸˜ao. I Neste caso, ele pode utilizar a palavra reservada throw, gerando uma nova excec¸˜ao. I M´etodo chamador recebe a excec¸˜ao e deve lidar com ela de alguma forma.

A API de Servlets provˆe dois tipos de excec¸˜ao:

I ServletException: reportar problemas gerais.

I UnavailableException: reportar que o Servlet se encontra indispon´ıvel.

(16)

Lidando com Erros: Gerando Excec¸˜

oes

O comportamento do servidor ao receber uma ServletException n˜ao ´e padronizado.

I Isto ´e, servidores diferentes podem tratar a excec¸˜ao de formas distintas.

Para a UnavailableException, no entanto, o comportamento ´e definido:

I O servidor (container) n˜ao deve repassar novas requisic¸˜oes. I Servlet est´a indispon´ıvel.

Pode-se especificar um “tempo de indisponibilidade” para a UnavailableException.

I Mas n˜ao h´a garantias de que o servidor ir´a tentar novamente ap´os este tempo.

Exemplos:

throw new UnavailableException(this, "Mensagem que especifica o problema."). throw new UnavailableException(120, this,

(17)
(18)

Inicializac¸˜

ao de Servlets

Relembrando:

I Quando um Servlet ´e iniciado pelo container, meu m´etodo init() ´e chamado. I Requisic¸˜oes s´o s˜ao passadas ao Servlet ap´os o fim do respectivo init().

Implementac¸˜ao padr˜ao do m´etodo init() n˜ao faz muito. Mas m´etodo pode ser re-implementando por cada Servlet. Permite realizar tarefas que s´o precisam ser feitas uma vez:

I Operac¸˜oes intensivas em E/S.

(19)

Inicializac¸˜

ao de Servlets (II)

H´a duas vers˜oes do m´etodo init():

I Uma sem parˆametros.

I Outra que recebe um objeto do tipo ServletConfig.

Pode-se reimplementar qualquer uma delas.

I Mas se reimplementarmos a vers˜ao com parˆametro, ´e obrigat´orio chamar a vers˜ao original.

(20)

Inicializac¸˜

ao de Servlets (IV): Parˆ

ametros de Configurac¸˜

ao

O objeto do tipo ServletConfig encapsula parˆametros de configurac¸˜ao espec´ıficos do Servlet.

Estes parˆametros podem ser acessados atrav´es de dois m´etodos:

I getInitParameter(String): retorna uma String com o valor do parˆametro especificado. I getInitParameterNames(): retorna uma enumerac¸˜ao com os nomes dos parˆametros

dispon´ıveis.

Os parˆametros (e seus valores) s˜ao configurados no descritor web.xml atrav´es da tag <init-param>.

(21)

Finalizac¸˜

ao de Servlets

Analogamente ao m´etodo init(), Servlets podem implementar um m´etodo destroy(). Este m´etodo ´e chamado sempre que o servidor quer “descarregar” um Servlet.

´

(22)

Inicializac¸˜

ao e Finalizac¸˜

ao do Contexto

A partir da vers˜ao 2.3, a API de Servlets disponibilizou a interface ServletContextListener.

Uma classe que implementa esta interface pode ser associada a um contexto. Neste caso, a classe ´e avisada sempre que o contexto ´e criado ou destru´ıdo.

I Atrav´es dos m´etodos contextInitialized e contextDestroyed.

A associac¸˜ao de uma classe a um contexto ´e feito no descritor web.xml: <web-app ...> <listener> <listener-class> MyAppServletContextListener </listener-class> </listener> </web-app>

(23)

Filtros

Filtros s˜ao objetos que podem ser colocados no caminho entre as requisic¸˜oes e Servlets (ou outros recursos em um servidor).

Filtros podem modificar a requisic¸˜ao recebida ou resposta enviada por um servlet.

I Exemplo: comprimir os dados da resposta.

Eles podem ainda realizar tarefas de monitoramento ou implementar pol´ıticas de seguranc¸a. Mais de um filtro pode ser utilizado, formando uma cadeia.

I Cada filtro executa sua ac¸˜ao e passa o controle para o pr´oximo filtro.

Cliente Container Filtro Filtro Filtro Servlet

Requisição Resposta

(24)

Filtros (II)

Filtros s˜ao implementados sobre a interface Filter. M´etodos relevantes:

I init(): inicializac¸˜ao do filtro. I destroy(): finalizac¸˜ao do filtro. I doFilter(): m´etodo principal do filtro.

No m´etodo doFilter(), filtro pode fazer qualquer processamento sobre a requisic¸˜ao. Em algum ponto, deve chamar o m´etodo doFilter() do pr´oximo filtro.

I Dispon´ıvel no objeto FilterChain, recebido como parˆametro.

Pode tamb´em interromper a cadeia e retornar um erro para o cliente. Pode realizar redirecionamentos.

(25)

Filtros: Um Exemplo M´ınimo

import javax.servlet.*;

public class GenericFilter implements javax.servlet.Filter { public FilterConfig filterConfig;

public void doFilter(final ServletRequest request, final ServletResponse response, FilterChain chain)

throws java.io.IOException, javax.servlet.ServletException { chain.doFilter(request,response);

}

public void init(final FilterConfig filterConfig) { this.filterConfig = filterConfig;

}

public void destroy() { }

(26)

Filtros: Exemplo de Codificac¸˜

ao de Caracteres

public void doFilter(ServletRequest request,

ServletResponse response, FilterChain chain) throws IOException, ServletException {

String encoding = selectEncoding(request); if (encoding != null)

request.setCharacterEncoding(encoding); chain.doFilter(request, response);

}

public void init(FilterConfig filterConfig) throws ServletException {

this.filterConfig = filterConfig;

this.encoding = filterConfig.getInitParameter("encoding"); }

protected String selectEncoding(ServletRequest request) { return (this.encoding);

(27)

Filtros: Exemplo de Configurac¸˜

ao

<filter> <filter-name>Compression Filter</filter-name> <filter-class>CompressionFilter</filter-class> <init-param> <param-name>compressionThreshold</param-name> <param-value>10</param-value> </init-param> </filter>

(28)

Filtros: Requisic¸˜

oes Despachadas

Originalmente, filtros s´o eram executados em requisic¸˜oes originadas em clientes.

Requisic¸˜oes despachadas atrav´es da interface getRequestDispatcher() n˜ao passavam por filtros.

Em determinados casos, este comportamento ´e desej´avel.

A partir da vers˜ao 2.4 da API de Servlets, isso passou a ser poss´ıvel.

<filter> <filter-name>Compression Filter</filter-name> <filter-class>CompressionFilter</filter-class> <init-param> <param-name>compressionThreshold</param-name> <param-value>10</param-value> </init-param> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> </filter>

(29)

Filtros: Como Alterar a Sa´ıda de Um Servlet

´

E f´acil fazer filtros adicionarem conte´udo antes ou depois da resposta de um Servlet. Mas como alterar o conte´udo que o Servlet gera?

Exemplo:

I Suponha que o Servlet chamado gera uma p´agina HTML. I Queremos adicionar alguma informac¸˜ao na p´agina.

I Mas ap´os a chamada do Servlet, este inclui um </html>.

Soluc¸˜ao: utilizac¸˜ao de wrappers.

(30)

Filtros: Como Alterar a Sa´ıda de Um Servlet (II)

Wrappers encapsulam objetos que representam respostas.

Sobreescrevem m´etodos como o getWriter() ou getOutputStream().

I Ao inv´es de enviarem o conte´udo diretamente para o cliente, pode enviar para algum buffer por exemplo.

Filtro cria o wrapper encapsulando o objeto de resposta original. Filtro chama o pr´oximo filtro (ou Servlet) passando o wrapper.

Quando o controle retorna para o filtro, ele pode inspecionar e alterar o conte´udo da resposta.

(31)

Filtros: Exemplo de Wrapper

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

PrintWriter out = response.getWriter();

CharResponseWrapper wrapper = new CharResponseWrapper( (HttpServletResponse)response);

chain.doFilter(request, wrapper);

if(wrapper.getContentType().equals("text/html")) { CharArrayWriter caw = new CharArrayWriter(); caw.write(wrapper.toString().substring(0,

wrapper.toString().indexOf("</body>")-1)); caw.write("<p>\nYou are visitor number

<font color=’red’>" + counter.getCounter() + "</font>"); caw.write("\n</body></html>"); response.setContentLength(caw.toString().length()); out.write(caw.toString()); } else out.write(wrapper.toString()); out.close(); }

public class CharResponseWrapper extends HttpServletResponseWrapper { private CharArrayWriter output; public String toString() {

return output.toString(); }

public CharResponseWrapper(

HttpServletResponse resp){ super(resp);

output = new CharArrayWriter(); }

public PrintWriter getWriter(){ return new PrintWriter(output); }

Referências

Documentos relacionados