[RESOLVIDO] Servlet para Logout sem submeter o form

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):

[code]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");  		
    				    	 
    }	   	 			
	
}[/code]

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

desde já agradeço a ajuda.

tentei fazer isso dentro do doPost:

[code]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");  		

    	}	     
    }	[/code]

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

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

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.

dessa forma, com as duas linhas session comentadas :

[code]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");  		

    	}	     
    }	[/code]

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

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.

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:

[code]
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"));
		} 		

   }  [/code]

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

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.

[quote=fabiomariner]

[code]
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"));
		} 		

   }  [/code][/quote]

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.

[quote=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[/quote]

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

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.

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:

[code]
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");        
    }
  
   }    [/code]

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

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

abaixo o filter:

[code]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 {

}

}[/code]
aqui meu doGet do servlet onde faço o logOut:

[code]
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");
	}
}[/code]

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