[RESOLVIDO] Servlet para Logout sem submeter o form

12 respostas
fabiomariner

bom dia,

Estou com o seguinte probelma:

quero encerrar uma sessão usando o mesmo servlet do login (não sei se é o mais indicado)

meu link sair
<a class="linkMenorCinza" href="LoginServlet?logout=true">Sair</a>
Meu método doPost
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {		
		
		String logout = (String) request.getParameter("logout");		
		
                //HttpSession session = request.getSession();
		if ("true".equals(logout)){	
		       // session.invalidate();
			response.sendRedirect("/treinamento/treinamento/geral/login.jsp"); 		
		}
		
	}

mas um erro é retornado quando declaro um objeto session no doGet:
Cannot create a session after the response has been committed

Como devo proceder para tal fim (logOut)?

abaixo o doPost onde pego a sessão (também não sei se é a melhor forma):

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doPost");
		doGet(request, response);
		
		String nome = (String) request.getParameter("login");
		//String senha = (String) request.getParameter("senha");	
		
	    HttpServletRequest req = (HttpServletRequest) request;  
	    HttpServletResponse res = (HttpServletResponse) response;  	
	    
	    ServletContext contextParam = config.getServletContext(); 	//Verificar por que precisa do argumento passado como parâmetro para o método init
	    String login = contextParam.getInitParameter("user"); 		//'pega' o valor no <context-param> do web.xml	    
	    
	    HttpSession session = req.getSession();	 	   
	    
	    if(nome.equals(login)){	    	    	
	    	session.setAttribute("logado", nome);
	    	request.getRequestDispatcher("/treinamento/aluno/index.jsp").forward(request, response);	    	   

	    }else{	    	 
	    	res.sendRedirect("/treinamento/treinamento/geral/login.jsp");  		
	    				    	 
	    }	   	 			
		
	}

Obs: sempre q clico no link o doGet é chamado.

desde já agradeço a ajuda.

12 Respostas

fabiomariner

tentei fazer isso dentro do doPost:

HttpSession session = req.getSession();	 	   

	    if ("true".equals(logout)){	
	    	System.out.println("logout---------");
	    	//session.invalidate();
	    	//session = request.getSession(false);
	    	response.sendRedirect("/treinamento/treinamento/geral/login.jsp"); 		
	    }else{

	    	if(nome.equals(login)){	    	    	
	    		session.setAttribute("logado", nome);
	    		request.getRequestDispatcher("/treinamento/aluno/index.jsp").forward(request, response);	    	   

	    	}else{	    	 
	    		res.sendRedirect("/treinamento/treinamento/geral/login.jsp");  		

	    	}	     
	    }

mas continuia disparando uma exeption:
[color=red]java.lang.IllegalStateException:Cannot create a session after the response has been committed[/color]

e no browser:
HTTP Status 500 - Cannot create a session after the response has been committed

fabiomariner

vi aqui no Guj um cara falando q isso no web.xml funcionou:

<context-param> <param-name>com.sun.faces.writeStateAtFormEnd</param-name> <param-value>false</param-value> </context-param>

testei e não deu certo
uso tomcat e não uso JSF

gomesrod
response.sendRedirect("/treinamento/treinamento/geral/login.jsp");

Tem dois momentos distintos em que o erro pode estar ocorrendo, o primeiro passo seria determinar exatamente que momento é esse:

  • O primeiro momento é no envio do Redirect em si. Ou seja, o erro ocorre no próprio Servlet de logout?
  • O segundo momento é no processamento da requisição seguinte, apontada pelo redirect. Ou seja, o usuário é redirecionado normalmente mas DEPOIS recebe o erro tentando carregar a página de login?

Para saber isso a maneira mais fácil é ver se a URL no browser muda. Se mudou para login.jsp é porque o usuário foi redirecionado com sucesso, mas depois deu erro na página de login.
E se quiser ver de um jeito realmente preciso, use o firebug (ou IE Developer tools) na aba Network e veja o fluxo de chamadas.

fabiomariner
dessa forma, com as duas linhas session comentadas :
HttpSession session = req.getSession();	 	   

	    if ("true".equals(logout)){	
	    	System.out.println("logout---------");
	    	//session.invalidate();
	    	//session = request.getSession(false);
	    	response.sendRedirect("/treinamento/treinamento/geral/login.jsp"); 		
	    }else{

	    	if(nome.equals(login)){	    	    	
	    		session.setAttribute("logado", nome);
	    		request.getRequestDispatcher("/treinamento/aluno/index.jsp").forward(request, response);	    	   

	    	}else{	    	 
	    		res.sendRedirect("/treinamento/treinamento/geral/login.jsp");  		

	    	}	     
	    }

compila normalmente, e o usuário é redirecionado para ligin.jsp, a exception á lançada quando tento usar o session.invalidate()

estou tentando usar o mesmo servlet para login e logout

gomesrod

Aquilo que falei antes é importante para descobrir a causa do problema.
Leia atentamente meu post anterior e procure identificar o momento em que dá o erro; se tiver dúvidas, poste aqui dizendo qual parte não ficou clara.

fabiomariner

obrigado pela ajuda gomesrod.

- O primeiro momento é no envio do Redirect em si. Ou seja, o erro ocorre no próprio Servlet de logout?
Sim, toda vez que uso o session.invalidate();

- O segundo momento é no processamento da requisição seguinte, apontada pelo redirect. Ou seja, o usuário é redirecionado normalmente mas DEPOIS recebe o erro tentando carregar a página de login?
Não, a exception é lançada antes que a linha do response seja executada.

eu estou usando um filter, quando desativei o mesmo no web.xml o excepition não mais foi lançado:

<filter>
  		<filter-name>TreinamentoFilter</filter-name>
  		<filter-class>br.com.multidata.treinamento.web.filtro.TreinamentoFilter</filter-class>
  </filter>  
  <filter-mapping>
  		<filter-name>TreinamentoFilter</filter-name>
  		<url-pattern>/LoginServlet</url-pattern>
  </filter-mapping>
mas vou precisar desse filter pra verificar se o cara ta logado, segue o código do único método q implementei:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {		
		//**essa parte é executada antes do request chegar ao Servlet		
		chain.doFilter(request, response);		
		//**essa parte é executada depois que o response já foi gerado pelo Servlet 
		
		HttpServletRequest req = (HttpServletRequest) request;
		HttpSession session = req.getSession();
		
			if (session.getAttribute("logado") != null) {
				System.out.println("Logado "+session.getAttribute("logado"));
			} 		

	   }
fabiomariner

cara, consegui resolver (em parte)

o response do servlet estava dando conflito com meu filter, transferi o código do filter para antes do:

chain.doFilter(request, response);

fazendo com e o mesmo seja executado antes que o response seja gerado pelo servlet.

obrigado pela ajuda

gomesrod
fabiomariner:
eu estou usando um filter, quando desativei o mesmo no web.xml o excepition não mais foi lançado:
Informação interessante! Esse filtro tem tudo a ver com o erro. Coloquei alguns comentários a mais no código, para mostrar o problema.
fabiomariner:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {		
		//**essa parte é executada antes do request chegar ao Servlet

// VAI EXECUTAR O SERVLET, QUE MATA A SESSAO E ENVIA UM REDIRECT
		chain.doFilter(request, response);
		//**essa parte é executada depois que o response já foi gerado pelo Servlet 
// EXECUTOU O SERVLET, NESSE MOMENTO NÃO EXISTE NENHUMA SESSÃO ATIVA.
		
		HttpServletRequest req = (HttpServletRequest) request;
// VAI OBTER A SESSÃO CORRENTE, OU SE NÃO EXISTIR ELE CRIA UMA NOVA.
		HttpSession session = req.getSession();
// PRONTO, AGORA JÁ DEU PAU! TENTOU CRIAR UMA SESSÃO NOVA, MAS NÃO PODE PORQUE UMA RESPOSTA JÁ FOI ENVIADA
// PARA O CLIENTE. ENTÃO TEMOS O ERRO
// "Cannot create a session after the response has been committed"
// AO CRIAR UMA SESSÃO O SERVIDOR PRECISA MANDAR UM COOKIE COM A IDENTIFICAÇÃO DA SESSÃO, MAS COMO A
// RESPOSTA JÁ FOI ENTÃO ISSO NÃO É POSSÍVEL...
		
			if (session.getAttribute("logado") != null) {
				System.out.println("Logado "+session.getAttribute("logado"));
			} 		

	   }

Soluções:
- A mais óbvia é tirar esse filter de uma vez, afinal ele não está fazendo nada mesmo! só da um System.out....

Ou talvez o filtro esteja fazendo algo importante, e você só não colocou aqui para simplificar o código. Nesse caso, faça a seguinte alteração:

Troque
HttpSession session = req.getSession();
por
HttpSession session = req.getSession(false);
O parâmetro false diz o seguinte: Se não houver sessão ativa então NÃO tente criar uma automaticamente. Ao invés disso, apenas me devolva null . Depois troque
if (session.getAttribute("logado") != null)
por
if (session != null && session.getAttribute("logado") != null)
para tratar a possibilidade de a sessão estar nula.
gomesrod

fabiomariner:
cara, consegui resolver (em parte)

o response do servlet estava dando conflito com meu filter, transferi o código do filter para antes do:

chain.doFilter(request, response);

fazendo com e o mesmo seja executado antes que o response seja gerado pelo servlet.

obrigado pela ajuda

Você postou enquanto eu digitava minha resposta, realmente tem a ver. Dá uma olhada lá que eu expliquei o motivo.

fabiomariner

muito boa explicação.

agora, quero usar meu filter para verificar a cada requisição se o usuário está logado e redirecionar para login.jsp caso não esteja (essa é a finalidade do filter), tem alguma sugestão de como começar essa implementação?

ainda não pesquisei afundo nessa questão, mas vou amanhã, e vou colocando aqui no forum as dúvidas

novamente obrigado pela ajuda e pela paciência.

gomesrod

O básico é o seguinte:

Primeiro, o filtro não deve ser acionado no servlet de login, e sim nas demais páginas do sistema.

<filter>  
        <filter-name>TreinamentoFilter</filter-name>  
        <filter-class>br.com.multidata.treinamento.web.filtro.TreinamentoFilter</filter-class>  
</filter>    
<filter-mapping>  
        <filter-name>TreinamentoFilter</filter-name>  
//        <url-pattern>/LoginServlet</url-pattern>      <<------ Errado! Não é na página de login que aciona o filtro, 
//                                                                                       e sim nas outras páginas do sistema, para que verifique
//                                                                                      se está logado antes de permitir acesso às funcionalidades
//    ---> Mapeie o filtro para as páginas que compõem a navegação no sistema, por exemplo:
          <url-pattern>*.jsp</url-pattern>
     // ou
          <url-pattern>*.do</url-pattern>
     // etc....
</filter-mapping>
E o filtro é mais ou menos assim:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {          
          
        HttpServletRequest req = (HttpServletRequest) request;  
        HttpSession session = req.getSession(false);  
          
        // Verifica se existe sessão e se está logado
        boolean acessoPermitido;
        if (session != null && session.getAttribute("logado") != null) {
                  acessoPermitido = true;
        } else {
                  acessoPermitido = false;
        }

        // Só executa o chain (ou seja, só continua o processamento) se estiver logado
        if (acessoPermitido) {
                  chain.doFilter(request, response);
        } else {
                  // Não está logado, manda para página de login
                  response.sendRedirect("pagina de login");        
        }
      
       }
Essa é a base, pode partir daí e ir adicionando condições, tipo: se for determinada página pode passar direto sem precisar de login, essa outra tem acesso restrito e só permite para administradores, etc etc
fabiomariner

caras, para ajuda quem acaso cair nesse tópico vou mostrar como ficou meu código final

abaixo o filter:
public class TreinamentoFilter implements Filter{	
	/*  O método destroy é chamado para avisar o filtro que ele está sendo desativado,
	 *  e possa liberar eventuais recursos alocados. 
	 */
	public void destroy() {
		
	}
	
	/*
	 * O método doFilter é onde é feito todo o processamento do filtro	 
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {		

		//HttpServletResponse res = (HttpServletResponse) response;
		HttpServletRequest req = (HttpServletRequest) request;
		HttpSession session = req.getSession();	// não coloquei mas talvez seja importante colocar o argumento "false" como o amigo acima sugeriu 
		
		if (session.getAttribute("logado") != null) {
			System.out.println("Logado "+session.getAttribute("logado"));				
			chain.doFilter(request, response);		
		}else{
			System.out.println("Não logado");
			
			request.getRequestDispatcher("/treinamento/geral/login.jsp").forward(request, response);
			System.out.println("Direcionado");
		}

	}

	/*
	 * O método init é chamado uma vez antes do filtro entrar em operação pela primeira vez. 
	 * Como parâmetro é passado um FilterConfig de onde se pode obter o nome do filtro
	 */
	public void init(FilterConfig fConfig) throws ServletException {
	
	}


}
aqui meu doGet do servlet onde faço o logOut:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {			
		String logout = (String) request.getParameter("logout");
		HttpSession session = request.getSession(true);	 //*** busca uma sessão, se ela não existir será criada por causa do parametro 'true'	   

		if ("true".equals(logout)){				 			
			session.invalidate();			
			response.sendRedirect("/treinamento/treinamento/geral/login.jsp");
		}
	}

mais uma vez, obrigado pela ajuda, o fórum/comunidade está sendo muito importante em meu aprendizado

Criado 13 de dezembro de 2012
Ultima resposta 14 de fev. de 2013
Respostas 12
Participantes 2