Reputation:
My browser is always returning a redirect loop and I have no idea why, it looks like when I access login.html it is calling some of my methods.
Here is the login.html file:
<ui:composition
template="/templates/master.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<ui:define name="body">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<h:form class="form-horizontal">
<fieldset>
<legend>Bem vindo a Sergio's</legend>
<br/>
<p>Preencha os campos abaixo para entrar no sistema.</p>
<div class="control-group">
<label class="control-label" for="user">Usuário</label>
<div class="controls">
<h:inputText required="true" id="user" value="#{loginController.username}" class="input-medium" />
<h:message for="user" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Senha</label>
<div class="controls">
<h:inputSecret required="true" id="password" value="#{loginController.password}" class="input-medium"/>
<h:message for="password" />
</div>
</div>
<div class="form-actions">
<h:commandButton action="#{loginController.login()}" class="btn btn-primary" value="Entrar"/>
</div>
</fieldset>
</h:form>
<h:messages/>
</div>
</div>
</div>
</ui:define>
</ui:composition>
And here is the LoginController:
package com.erp3.gui.controllers;
import java.io.IOException;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
@ManagedBean
public class LoginController {
public Boolean isLoggedIn = false;
private String username;
private String password;
private FacesMessage facesMessage;
public ExternalContext externalContent;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Boolean getIsLoggedIn() {
return isLoggedIn;
}
public void setIsLoggedIn(Boolean isLoggedIn) {
this.isLoggedIn = isLoggedIn;
}
public void login() throws IOException {
if (this.getUsername().equals("daniel") && this.getPassword().equals("123")) {
this.isLoggedIn = true;
externalContent = FacesContext.getCurrentInstance().getExternalContext();
externalContent.getSessionMap().put("loginController", this);
externalContent.redirect(externalContent.getRequestContextPath() + "/views/home.html");
} else {
this.isLoggedIn = false;
facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Usuário ou senha inválida.", username);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
externalContent.redirect(externalContent.getRequestContextPath() + "/views/login.htm");
}
}
public void logOut() throws IOException {
externalContent = FacesContext.getCurrentInstance().getExternalContext();
externalContent.getSessionMap().remove("loginController");
externalContent.redirect(externalContent.getRequestContextPath() + "/views/login.html");
}
}
I have a master.html that is my template and it is calling a top.html with this content:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container-fluid">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="#">Project name</a>
<div class="btn-group pull-right">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
<i class="icon-user"></i>
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="#">Conta</a></li>
<li class="divider"></li>
<li><a href="#{loginController.logout}">Sair</a></li>
</ul>
</div>
<div class="nav-collapse">
<ul class="nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div>
</div>
</div>
</div>
</ui:composition>
Upvotes: 1
Views: 2078
Reputation: 1109132
EL expressions in template text are immediately evaluated during render response and treated as value expressions. I.e. their return value is been printed as part of HTML output. "Plain vanilla" HTML is also template text. So the following
<li><a href="#{loginController.logOut()}">Sair</a></li>
will basically invoke the method, print its returned value as href
URL during render response. The resulting HTML is then:
<li><a href="">Sair</a></li>
(yes, the href
is empty because you actually returned void
instead of a valid String)
But inside that method you're telling JSF to redirect to the login page and hence it ends up in an infinite loop.
This is not what you actually want. You intend to invoke it as a backing bean action method. You should be using fullworthy JSF UICommand
component for this, such as <h:commandLink>
.
<li><h:form><h:commandLink value="Sair" action="#{loginController.logOut()}" /></h:form></li>
This way you can also change your logOut()
method to return a fullworthy navigation outcome:
public String logOut() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "/views/login.html?faces-redirect=true";
}
The ExternalContext#redirect()
is supposed to be used only when you want to redirect to a non-JSF URL, or when you're actually not inside an action method.
Upvotes: 1
Reputation:
found the problem, on my top.html
, I'm calling loginController.logOut()
on a link and I don't know why it is auto executing, is not waiting for my click so I changed the <a>
for <h:commandLink/>
Upvotes: 1